Changes In Branch dev Through [ab3d150448] Excluding Merge-Ins
This is equivalent to a diff from 0277842dc6 to ab3d150448
2020-12-06
| ||
18:40 | Merge dev into trunk check-in: 81dd73fb26 user: bohwaz | |
2020-12-02
| ||
00:08 | Use SUM as we are grouping check-in: 620e523fe4 user: bohwaz tags: dev | |
00:01 | Use autocomplete="new-password" for password change check-in: ab3d150448 user: bohwaz tags: dev | |
2020-11-30
| ||
21:08 | Fix local_login with automatic user id check-in: a302e98a8e user: bohwaz tags: dev | |
2020-10-26
| ||
20:45 | Merge back changes from trunk check-in: 13b04f66ad user: bohwaz tags: dev | |
2020-09-08
| ||
18:53 | Limiter la longueur du champ de recherche check-in: 0277842dc6 user: bohwaz tags: trunk, stable | |
18:42 | Fix: erreur quand le fichier de fond d'écran a déjà été supprimé (race condition) check-in: 41baaae90b user: bohwaz tags: trunk, stable | |
Modified .travis.yml from [ab9c965cec] to [4da8c0eef1].
1 2 | language: php php: | < < < | 1 2 3 4 5 6 7 8 9 | language: php php: - '7.2' - '7.3' - '7.4' install: - make -C src deps |
︙ | ︙ |
Added COPYING version [78e50e186b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 | GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>. |
Added README.md version [b535b9dd6a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # Garradin - Le gestionnaire d'association Garradin est un logiciel de gestion de petite et moyenne association. Plus d'infos sur le site de développement ici : [fossil.kd2.org/garradin](https://fossil.kd2.org/garradin/) [Documentation développeuse⋅développeur](https://fossil.kd2.org/garradin/wiki?name=Documentation+d%C3%A9veloppeur) Il est possible d'essayer et utiliser gratuitement Garradin sur la plateforme [Garradin.eu](https://garradin.eu/). Le code sur Github, n'est qu'un miroir, le développement principal se passe sur Fossil. ## Licence GNU Affero GPL v3 (voir fichier COPYING) Cette licence permet la libre redistribution, utilisation et modification du logiciel. La seule condition est de re-partager les éventuelles modifications apportées. Cette clause s'applique même si le logiciel n'est pas distribué et simplement installé sur un serveur. ## Code utilisé Inclus les bibliothèques suivantes : * [KD2fw](https://fossil.kd2.org/kd2fw/) - Copyright : 2001-2020+ BohwaZ - Licence : GNU AGPL v3 * [Gibberish AES](https://github.com/mdp/gibberish-aes) - Copyright : Mark Percival 2008 - http://markpercival.us -Licence : MIT |
Added archives/0.7.0_migration.sql version [acaa57e895].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | CREATE TABLE plugins_signaux -- Association entre plugins et signaux (hooks) ( signal TEXT NOT NULL, plugin TEXT NOT NULL REFERENCES plugins (id), callback TEXT NOT NULL, PRIMARY KEY (signal, plugin) ); CREATE TABLE compta_rapprochement -- Rapprochement entre compta et relevés de comptes ( operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id), date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, auteur INTEGER NOT NULL REFERENCES membres (id) ); CREATE TABLE fichiers -- Données sur les fichiers ( id INTEGER NOT NULL PRIMARY KEY, nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg) type TEXT NULL, -- Type MIME image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Date d'ajout ou mise à jour du fichier id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ); CREATE INDEX fichiers_date ON fichiers (datetime); CREATE TABLE fichiers_contenu -- Contenu des fichiers ( id INTEGER NOT NULL PRIMARY KEY, hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier taille INTEGER NOT NULL, -- Taille en octets contenu BLOB NULL ); CREATE UNIQUE INDEX fichiers_hash ON fichiers_contenu (hash); CREATE TABLE fichiers_membres -- Associations entre fichiers et membres (photo de profil par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES membres (id), PRIMARY KEY(fichier, id) ); CREATE TABLE fichiers_wiki_pages -- Associations entre fichiers et pages du wiki ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES wiki_pages (id), PRIMARY KEY(fichier, id) ); CREATE TABLE fichiers_compta_journal -- Associations entre fichiers et journal de compta (pièce comptable par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES compta_journal (id), PRIMARY KEY(fichier, id) ); |
Added archives/0.7.2_migration.sql version [ba4b5fbcc7].
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | -- Colonne manquante ALTER TABLE rappels_envoyes ADD COLUMN id_rappel INTEGER NULL REFERENCES rappels (id); -- Un bug a permis d'insérer des comptes avec des lettres minuscules, créant des problèmes -- corrigeons donc les comptes pour les mettre en majuscules. UPDATE compta_comptes SET id = UPPER(id); -- Le champ id_auteur était à NOT NULL, il faut corriger ça pour pouvoir avoir un rapprochement anonyme -- une fois que le membre a été supprimé CREATE TABLE compta_rapprochement2 -- Rapprochement entre compta et relevés de comptes ( id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id), date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, id_auteur INTEGER NULL REFERENCES membres (id) ); INSERT INTO compta_rapprochement2 SELECT operation, date, auteur FROM compta_rapprochement; DROP TABLE compta_rapprochement; ALTER TABLE compta_rapprochement2 RENAME TO compta_rapprochement; |
Added archives/0.8.0_migration.sql version [b56b968950].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | -- Ajouter champ pour OTP ALTER TABLE membres ADD COLUMN secret_otp TEXT NULL; -- Ajouter champ clé PGP ALTER TABLE membres ADD COLUMN clef_pgp TEXT NULL; -------------------------------------------------------------------------------- -- Mise à jour des tables contenant un champ date pour ajouter la contrainte -- -- Ceci afin de forcer les champs à contenir un format de date correct -- -- On en profite pour ajouter les ON DELETE nécessaires -- -------------------------------------------------------------------------------- -- Convertir les dates UNIX en date Y-m-d, apparemment il y en a encore parfois ? UPDATE wiki_pages SET date_creation = datetime(date_creation, "unixepoch") WHERE CAST(date_creation AS INT) = date_creation; UPDATE wiki_pages SET date_creation = datetime(date_creation) WHERE datetime(date_creation) != date_creation; -- Renommage des tables qu'il faut mettre à jour ALTER TABLE cotisations_membres RENAME TO cotisations_membres_old; ALTER TABLE rappels RENAME TO rappels_old; ALTER TABLE rappels_envoyes RENAME TO rappels_envoyes_old; ALTER TABLE wiki_pages RENAME TO wiki_pages_old; ALTER TABLE wiki_revisions RENAME TO wiki_revisions_old; ALTER TABLE compta_categories RENAME TO compta_categories_old; ALTER TABLE compta_comptes_bancaires RENAME TO compta_comptes_bancaires_old; ALTER TABLE compta_exercices RENAME TO compta_exercices_old; ALTER TABLE compta_journal RENAME TO compta_journal_old; ALTER TABLE compta_rapprochement RENAME TO compta_rapprochement_old; ALTER TABLE fichiers RENAME TO fichiers_old; ALTER TABLE membres_operations RENAME TO membres_operations_old; ALTER TABLE membres_categories RENAME TO membres_categories_old; -- Suppression des index pour que les nouveaux soient liés aux nouvelles tables DROP INDEX cm_unique; DROP INDEX wiki_uri; DROP INDEX wiki_revisions_id_page; DROP INDEX wiki_revisions_id_auteur; DROP INDEX compta_operations_exercice; DROP INDEX compta_operations_date; DROP INDEX compta_operations_comptes; DROP INDEX compta_operations_auteur; DROP INDEX fichiers_date; -- Suppression ancienne table recherche DROP TABLE wiki_recherche; -- Suppression des triggers -- Sinon les nouveaux ne seront pas créés sur la nouvelle table DROP TRIGGER wiki_recherche_delete; DROP TRIGGER wiki_recherche_update; DROP TRIGGER wiki_recherche_contenu_insert; DROP TRIGGER wiki_recherche_contenu_chiffre; -- Création des tables mises à jour (et de leurs index) .read 0.8.0_schema.sql -- Copie des données INSERT INTO cotisations_membres SELECT * FROM cotisations_membres_old; INSERT INTO rappels SELECT * FROM rappels_old; INSERT INTO rappels_envoyes SELECT id, id_membre, id_cotisation, id_rappel, date, media FROM rappels_envoyes_old; INSERT INTO wiki_pages SELECT * FROM wiki_pages_old; INSERT INTO wiki_revisions SELECT * FROM wiki_revisions_old; INSERT INTO compta_categories SELECT * FROM compta_categories_old; INSERT INTO compta_comptes_bancaires SELECT * FROM compta_comptes_bancaires_old; INSERT INTO compta_exercices SELECT * FROM compta_exercices_old; INSERT INTO compta_journal SELECT *, NULL FROM compta_journal_old; INSERT INTO compta_rapprochement SELECT * FROM compta_rapprochement_old; INSERT INTO fichiers SELECT * FROM fichiers_old; INSERT INTO membres_operations SELECT * FROM membres_operations_old; INSERT INTO membres_categories SELECT id, nom, droit_wiki, droit_membres, droit_compta, droit_inscription, droit_connexion, droit_config, cacher, id_cotisation_obligatoire FROM membres_categories_old; -- Suppression des anciennes tables DROP TABLE cotisations_membres_old; DROP TABLE rappels_old; DROP TABLE rappels_envoyes_old; DROP TABLE wiki_pages_old; DROP TABLE wiki_revisions_old; DROP TABLE compta_categories_old; DROP TABLE compta_comptes_bancaires_old; DROP TABLE compta_exercices_old; DROP TABLE compta_journal_old; DROP TABLE compta_rapprochement_old; DROP TABLE fichiers_old; DROP TABLE membres_operations_old; DROP TABLE membres_categories_old; |
Added archives/0.8.0_schema.sql version [1c0ae41b79].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | CREATE TABLE IF NOT EXISTS config ( -- Configuration de Garradin cle TEXT PRIMARY KEY NOT NULL, valeur TEXT ); -- On stocke ici les ID de catégorie de compta correspondant aux types spéciaux -- compta_categorie_cotisations => id_categorie -- compta_categorie_dons => id_categorie CREATE TABLE IF NOT EXISTS membres_categories -- Catégories de membres ( id INTEGER PRIMARY KEY NOT NULL, nom TEXT NOT NULL, description TEXT NULL, droit_wiki INTEGER NOT NULL DEFAULT 1, droit_membres INTEGER NOT NULL DEFAULT 1, droit_compta INTEGER NOT NULL DEFAULT 1, droit_inscription INTEGER NOT NULL DEFAULT 0, droit_connexion INTEGER NOT NULL DEFAULT 1, droit_config INTEGER NOT NULL DEFAULT 0, cacher INTEGER NOT NULL DEFAULT 0, id_cotisation_obligatoire INTEGER NULL REFERENCES cotisations (id) ON DELETE SET NULL ); -- Membres de l'asso -- Table dynamique générée par l'application -- voir Garradin\Membres\Champs.php CREATE TABLE IF NOT EXISTS membres_sessions -- Sessions ( selecteur TEXT NOT NULL, hash TEXT NOT NULL, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, expire INT NOT NULL, PRIMARY KEY (selecteur, id_membre) ); CREATE TABLE IF NOT EXISTS cotisations -- Types de cotisations et activités ( id INTEGER PRIMARY KEY NOT NULL, id_categorie_compta INTEGER NULL, -- NULL si le type n'est pas associé automatiquement à la compta intitule TEXT NOT NULL, description TEXT NULL, montant REAL NOT NULL, duree INTEGER NULL, -- En jours debut TEXT NULL, -- timestamp fin TEXT NULL, FOREIGN KEY (id_categorie_compta) REFERENCES compta_categories (id) ); CREATE TABLE IF NOT EXISTS cotisations_membres -- Enregistrement des cotisations et activités ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date) ); CREATE UNIQUE INDEX IF NOT EXISTS cm_unique ON cotisations_membres (id_membre, id_cotisation, date); CREATE TABLE IF NOT EXISTS membres_operations -- Liaision des enregistrement des paiements en compta ( id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_operation INTEGER NOT NULL REFERENCES compta_journal (id) ON DELETE CASCADE, id_cotisation INTEGER NULL REFERENCES cotisations_membres (id) ON DELETE SET NULL, PRIMARY KEY (id_membre, id_operation) ); CREATE TABLE IF NOT EXISTS rappels -- Rappels de devoir renouveller une cotisation ( id INTEGER NOT NULL PRIMARY KEY, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, delai INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel sujet TEXT NOT NULL, texte TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS rappels_envoyes -- Enregistrement des rappels envoyés à qui et quand ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, id_rappel INTEGER NULL REFERENCES rappels (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), media INTEGER NOT NULL -- Média utilisé pour le rappel : 1 = email, 2 = courrier, 3 = autre ); -- -- WIKI -- CREATE TABLE IF NOT EXISTS wiki_pages -- Pages du wiki ( id INTEGER PRIMARY KEY NOT NULL, uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki) titre TEXT NOT NULL, date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation), date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification), parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte) droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe) droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe) ); CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri); CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4 -- Table dupliquée pour chercher une page ( id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire titre TEXT NOT NULL, contenu TEXT NULL, -- Contenu de la dernière révision FOREIGN KEY (id) REFERENCES wiki_pages(id) ); CREATE TABLE IF NOT EXISTS wiki_revisions -- Révisions du contenu des pages ( id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE, revision INTEGER NULL, id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL, contenu TEXT NOT NULL, modification TEXT NULL, -- Description des modifications effectuées chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), PRIMARY KEY(id_page, revision) ); CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page); CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur); -- Triggers pour synchro avec table wiki_pages CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages BEGIN DELETE FROM wiki_recherche WHERE id = old.id; END; CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages BEGIN UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id; END; -- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1 BEGIN UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page; END; -- Si le contenu est chiffré, la recherche n'affiche pas de contenu CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1 BEGIN UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page; END; /* CREATE TABLE wiki_suivi -- Suivi des pages ( id_membre INTEGER NOT NULL, id_page INTEGER NOT NULL, PRIMARY KEY (id_membre, id_page), FOREIGN KEY (id_page) REFERENCES wiki_pages (id), -- Clé externe obligatoire FOREIGN KEY (id_membre) REFERENCES membres (id) -- Clé externe obligatoire ); */ -- -- COMPTA -- CREATE TABLE IF NOT EXISTS compta_exercices -- Exercices ( id INTEGER NOT NULL PRIMARY KEY, libelle TEXT NOT NULL, debut TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(debut) IS NOT NULL AND date(debut) = debut), fin TEXT NULL DEFAULT NULL CHECK (fin IS NULL OR (date(fin) IS NOT NULL AND date(fin) = fin)), cloture INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS compta_comptes -- Plan comptable ( id TEXT NOT NULL PRIMARY KEY, -- peut contenir des lettres, eg. 53A, 53B, etc. parent TEXT NOT NULL DEFAULT 0, libelle TEXT NOT NULL, position INTEGER NOT NULL, -- position actif/passif/charge/produit plan_comptable INTEGER NOT NULL DEFAULT 1, -- 1 = fait partie du plan comptable, 0 = a été ajouté par l'utilisateur desactive INTEGER NOT NULL DEFAULT 0 -- 1 = compte historique désactivé ); CREATE INDEX IF NOT EXISTS compta_comptes_parent ON compta_comptes (parent); CREATE TABLE IF NOT EXISTS compta_comptes_bancaires -- Comptes bancaires ( id TEXT NOT NULL PRIMARY KEY, banque TEXT NOT NULL, iban TEXT NULL, bic TEXT NULL, FOREIGN KEY(id) REFERENCES compta_comptes(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS compta_projets -- Projets (compta analytique) ( id INTEGER PRIMARY KEY NOT NULL, libelle TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS compta_journal -- Journal des opérations comptables ( id INTEGER PRIMARY KEY NOT NULL, libelle TEXT NOT NULL, remarques TEXT NULL, numero_piece TEXT NULL, -- N° de pièce comptable montant REAL NOT NULL, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), moyen_paiement TEXT NULL, numero_cheque TEXT NULL, compte_debit TEXT NULL, -- N° du compte dans le plan, NULL est utilisé pour une opération qui vient d'un exercice précédent compte_credit TEXT NULL, -- N° du compte dans le plan id_exercice INTEGER NULL DEFAULT NULL, -- En cas de compta simple, l'exercice est permanent (NULL) id_auteur INTEGER NULL, id_categorie INTEGER NULL, -- Numéro de catégorie (en mode simple) id_projet INTEGER NULL, FOREIGN KEY(moyen_paiement) REFERENCES compta_moyens_paiement(code), FOREIGN KEY(compte_debit) REFERENCES compta_comptes(id), FOREIGN KEY(compte_credit) REFERENCES compta_comptes(id), FOREIGN KEY(id_exercice) REFERENCES compta_exercices(id), FOREIGN KEY(id_auteur) REFERENCES membres(id) ON DELETE SET NULL, FOREIGN KEY(id_categorie) REFERENCES compta_categories(id) ON DELETE SET NULL, FOREIGN KEY(id_projet) REFERENCES compta_projets(id) ON DELETE SET NULL ); CREATE INDEX IF NOT EXISTS compta_operations_exercice ON compta_journal (id_exercice); CREATE INDEX IF NOT EXISTS compta_operations_date ON compta_journal (date); CREATE INDEX IF NOT EXISTS compta_operations_comptes ON compta_journal (compte_debit, compte_credit); CREATE INDEX IF NOT EXISTS compta_operations_auteur ON compta_journal (id_auteur); CREATE TABLE IF NOT EXISTS compta_moyens_paiement -- Moyens de paiement ( code TEXT NOT NULL PRIMARY KEY, nom TEXT NOT NULL ); --INSERT INTO compta_moyens_paiement (code, nom) VALUES ('AU', 'Autre'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CB', 'Carte bleue'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CH', 'Chèque'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('ES', 'Espèces'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('PR', 'Prélèvement'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('TI', 'TIP'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('VI', 'Virement'); CREATE TABLE IF NOT EXISTS compta_categories -- Catégories pour simplifier le plan comptable ( id INTEGER NOT NULL PRIMARY KEY, type INTEGER NOT NULL DEFAULT 1, -- 1 = recette, -1 = dépense, 0 = autre (utilisé uniquement pour l'interface) intitule TEXT NOT NULL, description TEXT NULL, compte TEXT NOT NULL, -- Compte affecté par cette catégorie FOREIGN KEY(compte) REFERENCES compta_comptes(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS plugins ( id TEXT NOT NULL PRIMARY KEY, officiel INTEGER NOT NULL DEFAULT 0, nom TEXT NOT NULL, description TEXT NULL, auteur TEXT NULL, url TEXT NULL, version TEXT NOT NULL, menu INTEGER NOT NULL DEFAULT 0, config TEXT NULL ); CREATE TABLE IF NOT EXISTS plugins_signaux -- Association entre plugins et signaux (hooks) ( signal TEXT NOT NULL, plugin TEXT NOT NULL REFERENCES plugins (id), callback TEXT NOT NULL, PRIMARY KEY (signal, plugin) ); CREATE TABLE IF NOT EXISTS compta_rapprochement -- Rapprochement entre compta et relevés de comptes ( id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), id_auteur INTEGER NULL REFERENCES membres (id) ); CREATE TABLE IF NOT EXISTS fichiers -- Données sur les fichiers ( id INTEGER NOT NULL PRIMARY KEY, nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg) type TEXT NULL, -- Type MIME image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime); CREATE TABLE IF NOT EXISTS fichiers_contenu -- Contenu des fichiers ( id INTEGER NOT NULL PRIMARY KEY, hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier taille INTEGER NOT NULL, -- Taille en octets contenu BLOB NULL ); CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash); CREATE TABLE IF NOT EXISTS fichiers_membres -- Associations entre fichiers et membres (photo de profil par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES membres (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_wiki_pages -- Associations entre fichiers et pages du wiki ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES wiki_pages (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_compta_journal -- Associations entre fichiers et journal de compta (pièce comptable par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES compta_journal (id), PRIMARY KEY(fichier, id) ); |
Added archives/0.8.3_migration.sql version [78f64dc820].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | -- Ajout d'une clause ON DELETE SET NULL sur la table cotisations ALTER TABLE cotisations_membres RENAME TO cotisations_membres_old; -- Création des tables mises à jour (et de leurs index) .read 0.8.3_schema.sql -- Copie des données INSERT INTO cotisations_membres SELECT * FROM cotisations_membres_old; -- Suppression des anciennes tables DROP TABLE cotisations_membres_old; |
Added archives/0.8.3_schema.sql version [80be656e5d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | CREATE TABLE IF NOT EXISTS config ( -- Configuration de Garradin cle TEXT PRIMARY KEY NOT NULL, valeur TEXT ); -- On stocke ici les ID de catégorie de compta correspondant aux types spéciaux -- compta_categorie_cotisations => id_categorie -- compta_categorie_dons => id_categorie CREATE TABLE IF NOT EXISTS membres_categories -- Catégories de membres ( id INTEGER PRIMARY KEY NOT NULL, nom TEXT NOT NULL, description TEXT NULL, droit_wiki INTEGER NOT NULL DEFAULT 1, droit_membres INTEGER NOT NULL DEFAULT 1, droit_compta INTEGER NOT NULL DEFAULT 1, droit_inscription INTEGER NOT NULL DEFAULT 0, droit_connexion INTEGER NOT NULL DEFAULT 1, droit_config INTEGER NOT NULL DEFAULT 0, cacher INTEGER NOT NULL DEFAULT 0, id_cotisation_obligatoire INTEGER NULL REFERENCES cotisations (id) ON DELETE SET NULL ); -- Membres de l'asso -- Table dynamique générée par l'application -- voir Garradin\Membres\Champs.php CREATE TABLE IF NOT EXISTS membres_sessions -- Sessions ( selecteur TEXT NOT NULL, hash TEXT NOT NULL, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, expire INT NOT NULL, PRIMARY KEY (selecteur, id_membre) ); CREATE TABLE IF NOT EXISTS cotisations -- Types de cotisations et activités ( id INTEGER PRIMARY KEY NOT NULL, id_categorie_compta INTEGER NULL REFERENCES compta_categories (id) ON DELETE SET NULL, -- NULL si le type n'est pas associé automatiquement à la compta intitule TEXT NOT NULL, description TEXT NULL, montant REAL NOT NULL, duree INTEGER NULL, -- En jours debut TEXT NULL, -- timestamp fin TEXT NULL ); CREATE TABLE IF NOT EXISTS cotisations_membres -- Enregistrement des cotisations et activités ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date) ); CREATE UNIQUE INDEX IF NOT EXISTS cm_unique ON cotisations_membres (id_membre, id_cotisation, date); CREATE TABLE IF NOT EXISTS membres_operations -- Liaison des enregistrement des paiements en compta ( id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_operation INTEGER NOT NULL REFERENCES compta_journal (id) ON DELETE CASCADE, id_cotisation INTEGER NULL REFERENCES cotisations_membres (id) ON DELETE SET NULL, PRIMARY KEY (id_membre, id_operation) ); CREATE TABLE IF NOT EXISTS rappels -- Rappels de devoir renouveller une cotisation ( id INTEGER NOT NULL PRIMARY KEY, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, delai INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel sujet TEXT NOT NULL, texte TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS rappels_envoyes -- Enregistrement des rappels envoyés à qui et quand ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, id_rappel INTEGER NULL REFERENCES rappels (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), media INTEGER NOT NULL -- Média utilisé pour le rappel : 1 = email, 2 = courrier, 3 = autre ); -- -- WIKI -- CREATE TABLE IF NOT EXISTS wiki_pages -- Pages du wiki ( id INTEGER PRIMARY KEY NOT NULL, uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki) titre TEXT NOT NULL, date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation), date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification), parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte) droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe) droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe) ); CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri); CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4 -- Table dupliquée pour chercher une page ( id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire titre TEXT NOT NULL, contenu TEXT NULL, -- Contenu de la dernière révision FOREIGN KEY (id) REFERENCES wiki_pages(id) ); CREATE TABLE IF NOT EXISTS wiki_revisions -- Révisions du contenu des pages ( id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE, revision INTEGER NULL, id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL, contenu TEXT NOT NULL, modification TEXT NULL, -- Description des modifications effectuées chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), PRIMARY KEY(id_page, revision) ); CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page); CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur); -- Triggers pour synchro avec table wiki_pages CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages BEGIN DELETE FROM wiki_recherche WHERE id = old.id; END; CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages BEGIN UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id; END; -- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1 BEGIN UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page; END; -- Si le contenu est chiffré, la recherche n'affiche pas de contenu CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1 BEGIN UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page; END; /* CREATE TABLE wiki_suivi -- Suivi des pages ( id_membre INTEGER NOT NULL, id_page INTEGER NOT NULL, PRIMARY KEY (id_membre, id_page), FOREIGN KEY (id_page) REFERENCES wiki_pages (id), -- Clé externe obligatoire FOREIGN KEY (id_membre) REFERENCES membres (id) -- Clé externe obligatoire ); */ -- -- COMPTA -- CREATE TABLE IF NOT EXISTS compta_exercices -- Exercices ( id INTEGER NOT NULL PRIMARY KEY, libelle TEXT NOT NULL, debut TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(debut) IS NOT NULL AND date(debut) = debut), fin TEXT NULL DEFAULT NULL CHECK (fin IS NULL OR (date(fin) IS NOT NULL AND date(fin) = fin)), cloture INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS compta_comptes -- Plan comptable ( id TEXT NOT NULL PRIMARY KEY, -- peut contenir des lettres, eg. 53A, 53B, etc. parent TEXT NOT NULL DEFAULT 0, libelle TEXT NOT NULL, position INTEGER NOT NULL, -- position actif/passif/charge/produit plan_comptable INTEGER NOT NULL DEFAULT 1, -- 1 = fait partie du plan comptable, 0 = a été ajouté par l'utilisateur desactive INTEGER NOT NULL DEFAULT 0 -- 1 = compte historique désactivé ); CREATE INDEX IF NOT EXISTS compta_comptes_parent ON compta_comptes (parent); CREATE TABLE IF NOT EXISTS compta_comptes_bancaires -- Comptes bancaires ( id TEXT NOT NULL PRIMARY KEY, banque TEXT NOT NULL, iban TEXT NULL, bic TEXT NULL, FOREIGN KEY(id) REFERENCES compta_comptes(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS compta_projets -- Projets (compta analytique) ( id INTEGER PRIMARY KEY NOT NULL, libelle TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS compta_journal -- Journal des opérations comptables ( id INTEGER PRIMARY KEY NOT NULL, libelle TEXT NOT NULL, remarques TEXT NULL, numero_piece TEXT NULL, -- N° de pièce comptable montant REAL NOT NULL, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), moyen_paiement TEXT NULL, numero_cheque TEXT NULL, compte_debit TEXT NULL, -- N° du compte dans le plan, NULL est utilisé pour une opération qui vient d'un exercice précédent compte_credit TEXT NULL, -- N° du compte dans le plan id_exercice INTEGER NULL DEFAULT NULL, -- En cas de compta simple, l'exercice est permanent (NULL) id_auteur INTEGER NULL, id_categorie INTEGER NULL, -- Numéro de catégorie (en mode simple) id_projet INTEGER NULL, FOREIGN KEY(moyen_paiement) REFERENCES compta_moyens_paiement(code), FOREIGN KEY(compte_debit) REFERENCES compta_comptes(id), FOREIGN KEY(compte_credit) REFERENCES compta_comptes(id), FOREIGN KEY(id_exercice) REFERENCES compta_exercices(id), FOREIGN KEY(id_auteur) REFERENCES membres(id) ON DELETE SET NULL, FOREIGN KEY(id_categorie) REFERENCES compta_categories(id) ON DELETE SET NULL, FOREIGN KEY(id_projet) REFERENCES compta_projets(id) ON DELETE SET NULL ); CREATE INDEX IF NOT EXISTS compta_operations_exercice ON compta_journal (id_exercice); CREATE INDEX IF NOT EXISTS compta_operations_date ON compta_journal (date); CREATE INDEX IF NOT EXISTS compta_operations_comptes ON compta_journal (compte_debit, compte_credit); CREATE INDEX IF NOT EXISTS compta_operations_auteur ON compta_journal (id_auteur); CREATE TABLE IF NOT EXISTS compta_moyens_paiement -- Moyens de paiement ( code TEXT NOT NULL PRIMARY KEY, nom TEXT NOT NULL ); --INSERT INTO compta_moyens_paiement (code, nom) VALUES ('AU', 'Autre'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CB', 'Carte bleue'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CH', 'Chèque'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('ES', 'Espèces'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('PR', 'Prélèvement'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('TI', 'TIP'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('VI', 'Virement'); CREATE TABLE IF NOT EXISTS compta_categories -- Catégories pour simplifier le plan comptable ( id INTEGER NOT NULL PRIMARY KEY, type INTEGER NOT NULL DEFAULT 1, -- 1 = recette, -1 = dépense, 0 = autre (utilisé uniquement pour l'interface) intitule TEXT NOT NULL, description TEXT NULL, compte TEXT NOT NULL, -- Compte affecté par cette catégorie FOREIGN KEY(compte) REFERENCES compta_comptes(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS plugins ( id TEXT NOT NULL PRIMARY KEY, officiel INTEGER NOT NULL DEFAULT 0, nom TEXT NOT NULL, description TEXT NULL, auteur TEXT NULL, url TEXT NULL, version TEXT NOT NULL, menu INTEGER NOT NULL DEFAULT 0, config TEXT NULL ); CREATE TABLE IF NOT EXISTS plugins_signaux -- Association entre plugins et signaux (hooks) ( signal TEXT NOT NULL, plugin TEXT NOT NULL REFERENCES plugins (id), callback TEXT NOT NULL, PRIMARY KEY (signal, plugin) ); CREATE TABLE IF NOT EXISTS compta_rapprochement -- Rapprochement entre compta et relevés de comptes ( id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), id_auteur INTEGER NULL REFERENCES membres (id) ); CREATE TABLE IF NOT EXISTS fichiers -- Données sur les fichiers ( id INTEGER NOT NULL PRIMARY KEY, nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg) type TEXT NULL, -- Type MIME image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime); CREATE TABLE IF NOT EXISTS fichiers_contenu -- Contenu des fichiers ( id INTEGER NOT NULL PRIMARY KEY, hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier taille INTEGER NOT NULL, -- Taille en octets contenu BLOB NULL ); CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash); CREATE TABLE IF NOT EXISTS fichiers_membres -- Associations entre fichiers et membres (photo de profil par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES membres (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_wiki_pages -- Associations entre fichiers et pages du wiki ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES wiki_pages (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_compta_journal -- Associations entre fichiers et journal de compta (pièce comptable par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES compta_journal (id), PRIMARY KEY(fichier, id) ); |
Added archives/0.8.4_migration.sql version [107bec2b2d].
> > > | 1 2 3 | -- Mise à jour des URI du wiki pour ne pas inclure les tirets en début et fin de chaîne -- (problème de concordance entre API PHP et données SQLite) UPDATE wiki_pages SET uri = trim(uri, '-') WHERE uri != trim(uri, '-'); |
Added archives/0.9.0_migration.sql version [90ab72f7f4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | -- Désactivation de l'accès aux membres, pour les groupes qui n'avaient que le droit de lecture -- car maintenant ce droit permet de voir les fiches de membres complètes UPDATE membres_categories SET droit_membres = 0 WHERE droit_membres = 1; -- Suppression de la colonne description des catégories ALTER TABLE membres_categories RENAME TO membres_categories_old; -- Mise à jour table compta_rapprochement: la foreign key sur membres est passée -- à ON DELETE SET NULL ALTER TABLE compta_rapprochement RENAME TO compta_rapprochement_old; -- Re-créer la table -- Créer également les nouvelles tables email .read 0.9.0_schema.sql -- Copie des données, sauf la colonne description INSERT INTO membres_categories SELECT id, nom, droit_wiki, droit_membres, droit_compta, droit_inscription, droit_connexion, droit_config, cacher, id_cotisation_obligatoire FROM membres_categories_old; -- Suppression des anciennes tables DROP TABLE membres_categories_old; -- Migration des données INSERT INTO compta_rapprochement SELECT * FROM compta_rapprochement_old; DROP TABLE compta_rapprochement_old; -- Cette variable n'est plus utilisée DELETE FROM config WHERE cle = 'email_envoi_automatique'; ALTER TABLE plugins ADD COLUMN menu_condition TEXT NULL; -- Supprimer le début dans le nom des plugins UPDATE plugins_signaux SET callback = replace(callback, 'Garradin\Plugin\', ''); |
Added archives/0.9.0_schema.sql version [9f23495ff4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | -- Désactivation de l'accès aux membres, pour les groupes qui n'avaient que le droit de lecture -- car maintenant ce droit permet de voir les fiches de membres complètes UPDATE membres_categories SET droit_membres = 0 WHERE droit_membres = 1; -- Suppression de la colonne description des catégories ALTER TABLE membres_categories RENAME TO membres_categories_old; -- Mise à jour table compta_rapprochement: la foreign key sur membres est passée -- à ON DELETE SET NULL ALTER TABLE compta_rapprochement RENAME TO compta_rapprochement_old; -- Re-créer la table -- Créer également les nouvelles tables email .read schema.sql -- Copie des données, sauf la colonne description INSERT INTO membres_categories SELECT id, nom, droit_wiki, droit_membres, droit_compta, droit_inscription, droit_connexion, droit_config, cacher, id_cotisation_obligatoire FROM membres_categories_old; -- Suppression des anciennes tables DROP TABLE membres_categories_old; -- Migration des données INSERT INTO compta_rapprochement SELECT * FROM compta_rapprochement_old; DROP TABLE compta_rapprochement_old; -- Cette variable n'est plus utilisée DELETE FROM config WHERE cle = 'email_envoi_automatique'; ALTER TABLE plugins ADD COLUMN menu_condition TEXT NULL; -- Supprimer le début dans le nom des plugins UPDATE plugins_signaux SET callback = replace(callback, 'Garradin\Plugin\', ''); |
Added archives/0.9.1_migration.sql version [6227606b97].
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | -- Il manquait une clause ON DELETE SET NULL sur la foreign key -- de cotisations quand on faisait une mise à jour depuis une -- ancienne version ALTER TABLE cotisations RENAME TO cotisations_old; .read 0.9.1_schema.sql INSERT INTO cotisations SELECT * FROM cotisations_old; DROP TABLE cotisations_old; -- Changer le compte des reports automatiques UPDATE compta_journal SET compte_debit = '890' WHERE compte_debit IS NULL; UPDATE compta_journal SET compte_credit = '890' WHERE compte_credit IS NULL; |
Added archives/0.9.1_schema.sql version [efe750515a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | CREATE TABLE IF NOT EXISTS config ( -- Configuration de Garradin cle TEXT PRIMARY KEY NOT NULL, valeur TEXT ); -- On stocke ici les ID de catégorie de compta correspondant aux types spéciaux -- compta_categorie_cotisations => id_categorie -- compta_categorie_dons => id_categorie CREATE TABLE IF NOT EXISTS membres_categories -- Catégories de membres ( id INTEGER PRIMARY KEY NOT NULL, nom TEXT NOT NULL, droit_wiki INTEGER NOT NULL DEFAULT 1, droit_membres INTEGER NOT NULL DEFAULT 1, droit_compta INTEGER NOT NULL DEFAULT 1, droit_inscription INTEGER NOT NULL DEFAULT 0, droit_connexion INTEGER NOT NULL DEFAULT 1, droit_config INTEGER NOT NULL DEFAULT 0, cacher INTEGER NOT NULL DEFAULT 0, id_cotisation_obligatoire INTEGER NULL REFERENCES cotisations (id) ON DELETE SET NULL ); -- Membres de l'asso -- Table dynamique générée par l'application -- voir Garradin\Membres\Champs.php CREATE TABLE IF NOT EXISTS membres_sessions -- Sessions ( selecteur TEXT NOT NULL, hash TEXT NOT NULL, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, expire INT NOT NULL, PRIMARY KEY (selecteur, id_membre) ); CREATE TABLE IF NOT EXISTS cotisations -- Types de cotisations et activités ( id INTEGER PRIMARY KEY NOT NULL, id_categorie_compta INTEGER NULL REFERENCES compta_categories (id) ON DELETE SET NULL, -- NULL si le type n'est pas associé automatiquement à la compta intitule TEXT NOT NULL, description TEXT NULL, montant REAL NOT NULL, duree INTEGER NULL, -- En jours debut TEXT NULL, -- timestamp fin TEXT NULL ); CREATE TABLE IF NOT EXISTS cotisations_membres -- Enregistrement des cotisations et activités ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date) ); CREATE UNIQUE INDEX IF NOT EXISTS cm_unique ON cotisations_membres (id_membre, id_cotisation, date); CREATE TABLE IF NOT EXISTS membres_operations -- Liaison des enregistrement des paiements en compta ( id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_operation INTEGER NOT NULL REFERENCES compta_journal (id) ON DELETE CASCADE, id_cotisation INTEGER NULL REFERENCES cotisations_membres (id) ON DELETE SET NULL, PRIMARY KEY (id_membre, id_operation) ); CREATE TABLE IF NOT EXISTS rappels -- Rappels de devoir renouveller une cotisation ( id INTEGER NOT NULL PRIMARY KEY, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, delai INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel sujet TEXT NOT NULL, texte TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS rappels_envoyes -- Enregistrement des rappels envoyés à qui et quand ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, id_rappel INTEGER NULL REFERENCES rappels (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), media INTEGER NOT NULL -- Média utilisé pour le rappel : 1 = email, 2 = courrier, 3 = autre ); -- -- WIKI -- CREATE TABLE IF NOT EXISTS wiki_pages -- Pages du wiki ( id INTEGER PRIMARY KEY NOT NULL, uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki) titre TEXT NOT NULL, date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation), date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification), parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte) droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe) droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe) ); CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri); CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4 -- Table dupliquée pour chercher une page ( id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire titre TEXT NOT NULL, contenu TEXT NULL, -- Contenu de la dernière révision FOREIGN KEY (id) REFERENCES wiki_pages(id) ); CREATE TABLE IF NOT EXISTS wiki_revisions -- Révisions du contenu des pages ( id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE, revision INTEGER NULL, id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL, contenu TEXT NOT NULL, modification TEXT NULL, -- Description des modifications effectuées chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), PRIMARY KEY(id_page, revision) ); CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page); CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur); -- Triggers pour synchro avec table wiki_pages CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages BEGIN DELETE FROM wiki_recherche WHERE id = old.id; END; CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages BEGIN UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id; END; -- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1 BEGIN UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page; END; -- Si le contenu est chiffré, la recherche n'affiche pas de contenu CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1 BEGIN UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page; END; /* CREATE TABLE wiki_suivi -- Suivi des pages ( id_membre INTEGER NOT NULL, id_page INTEGER NOT NULL, PRIMARY KEY (id_membre, id_page), FOREIGN KEY (id_page) REFERENCES wiki_pages (id), -- Clé externe obligatoire FOREIGN KEY (id_membre) REFERENCES membres (id) -- Clé externe obligatoire ); */ -- -- COMPTA -- CREATE TABLE IF NOT EXISTS compta_exercices -- Exercices ( id INTEGER NOT NULL PRIMARY KEY, libelle TEXT NOT NULL, debut TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(debut) IS NOT NULL AND date(debut) = debut), fin TEXT NULL DEFAULT NULL CHECK (fin IS NULL OR (date(fin) IS NOT NULL AND date(fin) = fin)), cloture INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS compta_comptes -- Plan comptable ( id TEXT NOT NULL PRIMARY KEY, -- peut contenir des lettres, eg. 53A, 53B, etc. parent TEXT NOT NULL DEFAULT 0, libelle TEXT NOT NULL, position INTEGER NOT NULL, -- position actif/passif/charge/produit plan_comptable INTEGER NOT NULL DEFAULT 1, -- 1 = fait partie du plan comptable, 0 = a été ajouté par l'utilisateur desactive INTEGER NOT NULL DEFAULT 0 -- 1 = compte historique désactivé ); CREATE INDEX IF NOT EXISTS compta_comptes_parent ON compta_comptes (parent); CREATE TABLE IF NOT EXISTS compta_comptes_bancaires -- Comptes bancaires ( id TEXT NOT NULL PRIMARY KEY, banque TEXT NOT NULL, iban TEXT NULL, bic TEXT NULL, FOREIGN KEY(id) REFERENCES compta_comptes(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS compta_projets -- Projets (compta analytique) ( id INTEGER PRIMARY KEY NOT NULL, libelle TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS compta_journal -- Journal des opérations comptables ( id INTEGER PRIMARY KEY NOT NULL, libelle TEXT NOT NULL, remarques TEXT NULL, numero_piece TEXT NULL, -- N° de pièce comptable montant REAL NOT NULL, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), moyen_paiement TEXT NULL, numero_cheque TEXT NULL, compte_debit TEXT NULL, -- N° du compte dans le plan, NULL est utilisé pour une opération qui vient d'un exercice précédent compte_credit TEXT NULL, -- N° du compte dans le plan id_exercice INTEGER NULL DEFAULT NULL, -- En cas de compta simple, l'exercice est permanent (NULL) id_auteur INTEGER NULL, id_categorie INTEGER NULL, -- Numéro de catégorie (en mode simple) id_projet INTEGER NULL, FOREIGN KEY(moyen_paiement) REFERENCES compta_moyens_paiement(code), FOREIGN KEY(compte_debit) REFERENCES compta_comptes(id), FOREIGN KEY(compte_credit) REFERENCES compta_comptes(id), FOREIGN KEY(id_exercice) REFERENCES compta_exercices(id), FOREIGN KEY(id_auteur) REFERENCES membres(id) ON DELETE SET NULL, FOREIGN KEY(id_categorie) REFERENCES compta_categories(id) ON DELETE SET NULL, FOREIGN KEY(id_projet) REFERENCES compta_projets(id) ON DELETE SET NULL ); CREATE INDEX IF NOT EXISTS compta_operations_exercice ON compta_journal (id_exercice); CREATE INDEX IF NOT EXISTS compta_operations_date ON compta_journal (date); CREATE INDEX IF NOT EXISTS compta_operations_comptes ON compta_journal (compte_debit, compte_credit); CREATE INDEX IF NOT EXISTS compta_operations_auteur ON compta_journal (id_auteur); CREATE TABLE IF NOT EXISTS compta_moyens_paiement -- Moyens de paiement ( code TEXT NOT NULL PRIMARY KEY, nom TEXT NOT NULL ); --INSERT INTO compta_moyens_paiement (code, nom) VALUES ('AU', 'Autre'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CB', 'Carte bleue'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CH', 'Chèque'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('ES', 'Espèces'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('PR', 'Prélèvement'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('TI', 'TIP'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('VI', 'Virement'); CREATE TABLE IF NOT EXISTS compta_categories -- Catégories pour simplifier le plan comptable ( id INTEGER NOT NULL PRIMARY KEY, type INTEGER NOT NULL DEFAULT 1, -- 1 = recette, -1 = dépense, 0 = autre (utilisé uniquement pour l'interface) intitule TEXT NOT NULL, description TEXT NULL, compte TEXT NOT NULL, -- Compte affecté par cette catégorie FOREIGN KEY(compte) REFERENCES compta_comptes(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS plugins ( id TEXT NOT NULL PRIMARY KEY, officiel INTEGER NOT NULL DEFAULT 0, nom TEXT NOT NULL, description TEXT NULL, auteur TEXT NULL, url TEXT NULL, version TEXT NOT NULL, menu INTEGER NOT NULL DEFAULT 0, menu_condition TEXT NULL, config TEXT NULL ); CREATE TABLE IF NOT EXISTS plugins_signaux -- Association entre plugins et signaux (hooks) ( signal TEXT NOT NULL, plugin TEXT NOT NULL REFERENCES plugins (id), callback TEXT NOT NULL, PRIMARY KEY (signal, plugin) ); CREATE TABLE IF NOT EXISTS compta_rapprochement -- Rapprochement entre compta et relevés de comptes ( id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL ); CREATE TABLE IF NOT EXISTS fichiers -- Données sur les fichiers ( id INTEGER NOT NULL PRIMARY KEY, nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg) type TEXT NULL, -- Type MIME image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime); CREATE TABLE IF NOT EXISTS fichiers_contenu -- Contenu des fichiers ( id INTEGER NOT NULL PRIMARY KEY, hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier taille INTEGER NOT NULL, -- Taille en octets contenu BLOB NULL ); CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash); CREATE TABLE IF NOT EXISTS fichiers_membres -- Associations entre fichiers et membres (photo de profil par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES membres (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_wiki_pages -- Associations entre fichiers et pages du wiki ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES wiki_pages (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_compta_journal -- Associations entre fichiers et journal de compta (pièce comptable par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES compta_journal (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS recherches -- Recherches enregistrées ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NULL REFERENCES membres (id) ON DELETE CASCADE, -- Si non NULL, alors la recherche ne sera visible que par le membre associé intitule TEXT NOT NULL, creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(creation) IS NOT NULL AND datetime(creation) = creation), cible TEXT NOT NULL, -- "membres" ou "compta_journal" type TEXT NOT NULL, -- "json" ou "sql" contenu TEXT NOT NULL ); |
Added archives/0.9.5_schema.sql version [c8df01c2dd].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | CREATE TABLE IF NOT EXISTS config ( -- Configuration de Garradin cle TEXT PRIMARY KEY NOT NULL, valeur TEXT ); -- On stocke ici les ID de catégorie de compta correspondant aux types spéciaux -- compta_categorie_cotisations => id_categorie -- compta_categorie_dons => id_categorie CREATE TABLE IF NOT EXISTS membres_categories -- Catégories de membres ( id INTEGER PRIMARY KEY NOT NULL, nom TEXT NOT NULL, droit_wiki INTEGER NOT NULL DEFAULT 1, droit_membres INTEGER NOT NULL DEFAULT 1, droit_compta INTEGER NOT NULL DEFAULT 1, droit_inscription INTEGER NOT NULL DEFAULT 0, droit_connexion INTEGER NOT NULL DEFAULT 1, droit_config INTEGER NOT NULL DEFAULT 0, cacher INTEGER NOT NULL DEFAULT 0, id_cotisation_obligatoire INTEGER NULL REFERENCES cotisations (id) ON DELETE SET NULL ); -- Membres de l'asso -- Table dynamique générée par l'application -- voir Garradin\Membres\Champs.php CREATE TABLE IF NOT EXISTS membres_sessions -- Sessions ( selecteur TEXT NOT NULL, hash TEXT NOT NULL, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, expire INT NOT NULL, PRIMARY KEY (selecteur, id_membre) ); CREATE TABLE IF NOT EXISTS cotisations -- Types de cotisations et activités ( id INTEGER PRIMARY KEY NOT NULL, id_categorie_compta INTEGER NULL REFERENCES compta_categories (id) ON DELETE SET NULL, -- NULL si le type n'est pas associé automatiquement à la compta intitule TEXT NOT NULL, description TEXT NULL, montant REAL NOT NULL, duree INTEGER NULL, -- En jours debut TEXT NULL, -- timestamp fin TEXT NULL ); CREATE TABLE IF NOT EXISTS cotisations_membres -- Enregistrement des cotisations et activités ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date) ); CREATE UNIQUE INDEX IF NOT EXISTS cm_unique ON cotisations_membres (id_membre, id_cotisation, date); CREATE TABLE IF NOT EXISTS membres_operations -- Liaison des enregistrement des paiements en compta ( id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_operation INTEGER NOT NULL REFERENCES compta_journal (id) ON DELETE CASCADE, id_cotisation INTEGER NULL REFERENCES cotisations_membres (id) ON DELETE SET NULL, PRIMARY KEY (id_membre, id_operation) ); CREATE TABLE IF NOT EXISTS rappels -- Rappels de devoir renouveller une cotisation ( id INTEGER NOT NULL PRIMARY KEY, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, delai INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel sujet TEXT NOT NULL, texte TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS rappels_envoyes -- Enregistrement des rappels envoyés à qui et quand ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE, id_rappel INTEGER NULL REFERENCES rappels (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), media INTEGER NOT NULL -- Média utilisé pour le rappel : 1 = email, 2 = courrier, 3 = autre ); -- -- WIKI -- CREATE TABLE IF NOT EXISTS wiki_pages -- Pages du wiki ( id INTEGER PRIMARY KEY NOT NULL, uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki) titre TEXT NOT NULL, date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation), date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification), parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte) droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe) droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe) ); CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri); CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4 -- Table dupliquée pour chercher une page ( id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire titre TEXT NOT NULL, contenu TEXT NULL, -- Contenu de la dernière révision FOREIGN KEY (id) REFERENCES wiki_pages(id) ); CREATE TABLE IF NOT EXISTS wiki_revisions -- Révisions du contenu des pages ( id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE, revision INTEGER NULL, id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL, contenu TEXT NOT NULL, modification TEXT NULL, -- Description des modifications effectuées chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), PRIMARY KEY(id_page, revision) ); CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page); CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur); -- Triggers pour synchro avec table wiki_pages CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages BEGIN DELETE FROM wiki_recherche WHERE id = old.id; END; CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages BEGIN UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id; END; -- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1 BEGIN UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page; END; -- Si le contenu est chiffré, la recherche n'affiche pas de contenu CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1 BEGIN UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page; END; /* CREATE TABLE wiki_suivi -- Suivi des pages ( id_membre INTEGER NOT NULL, id_page INTEGER NOT NULL, PRIMARY KEY (id_membre, id_page), FOREIGN KEY (id_page) REFERENCES wiki_pages (id), -- Clé externe obligatoire FOREIGN KEY (id_membre) REFERENCES membres (id) -- Clé externe obligatoire ); */ -- -- COMPTA -- CREATE TABLE IF NOT EXISTS compta_exercices -- Exercices ( id INTEGER NOT NULL PRIMARY KEY, libelle TEXT NOT NULL, debut TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(debut) IS NOT NULL AND date(debut) = debut), fin TEXT NULL DEFAULT NULL CHECK (fin IS NULL OR (date(fin) IS NOT NULL AND date(fin) = fin)), cloture INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS compta_comptes -- Plan comptable ( id TEXT NOT NULL PRIMARY KEY, -- peut contenir des lettres, eg. 53A, 53B, etc. parent TEXT NOT NULL DEFAULT 0, libelle TEXT NOT NULL, position INTEGER NOT NULL, -- position actif/passif/charge/produit plan_comptable INTEGER NOT NULL DEFAULT 1, -- 1 = fait partie du plan comptable, 0 = a été ajouté par l'utilisateur desactive INTEGER NOT NULL DEFAULT 0 -- 1 = compte historique désactivé ); CREATE INDEX IF NOT EXISTS compta_comptes_parent ON compta_comptes (parent); CREATE TABLE IF NOT EXISTS compta_comptes_bancaires -- Comptes bancaires ( id TEXT NOT NULL PRIMARY KEY, banque TEXT NOT NULL, iban TEXT NULL, bic TEXT NULL, FOREIGN KEY(id) REFERENCES compta_comptes(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS compta_projets -- Projets (compta analytique) ( id INTEGER PRIMARY KEY NOT NULL, libelle TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS compta_journal -- Journal des opérations comptables ( id INTEGER PRIMARY KEY NOT NULL, libelle TEXT NOT NULL, remarques TEXT NULL, numero_piece TEXT NULL, -- N° de pièce comptable montant REAL NOT NULL, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), moyen_paiement TEXT NULL, numero_cheque TEXT NULL, compte_debit TEXT NULL, -- N° du compte dans le plan, NULL est utilisé pour une opération qui vient d'un exercice précédent compte_credit TEXT NULL, -- N° du compte dans le plan id_exercice INTEGER NULL DEFAULT NULL, -- En cas de compta simple, l'exercice est permanent (NULL) id_auteur INTEGER NULL, id_categorie INTEGER NULL, -- Numéro de catégorie (en mode simple) id_projet INTEGER NULL, FOREIGN KEY(moyen_paiement) REFERENCES compta_moyens_paiement(code), FOREIGN KEY(compte_debit) REFERENCES compta_comptes(id), FOREIGN KEY(compte_credit) REFERENCES compta_comptes(id), FOREIGN KEY(id_exercice) REFERENCES compta_exercices(id), FOREIGN KEY(id_auteur) REFERENCES membres(id) ON DELETE SET NULL, FOREIGN KEY(id_categorie) REFERENCES compta_categories(id) ON DELETE SET NULL, FOREIGN KEY(id_projet) REFERENCES compta_projets(id) ON DELETE SET NULL ); CREATE INDEX IF NOT EXISTS compta_operations_exercice ON compta_journal (id_exercice); CREATE INDEX IF NOT EXISTS compta_operations_date ON compta_journal (date); CREATE INDEX IF NOT EXISTS compta_operations_comptes ON compta_journal (compte_debit, compte_credit); CREATE INDEX IF NOT EXISTS compta_operations_auteur ON compta_journal (id_auteur); CREATE TABLE IF NOT EXISTS compta_moyens_paiement -- Moyens de paiement ( code TEXT NOT NULL PRIMARY KEY, nom TEXT NOT NULL ); --INSERT INTO compta_moyens_paiement (code, nom) VALUES ('AU', 'Autre'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CB', 'Carte bleue'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CH', 'Chèque'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('ES', 'Espèces'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('PR', 'Prélèvement'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('TI', 'TIP'); INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('VI', 'Virement'); CREATE TABLE IF NOT EXISTS compta_categories -- Catégories pour simplifier le plan comptable ( id INTEGER NOT NULL PRIMARY KEY, type INTEGER NOT NULL DEFAULT 1, -- 1 = recette, -1 = dépense, 0 = autre (utilisé uniquement pour l'interface) intitule TEXT NOT NULL, description TEXT NULL, compte TEXT NOT NULL, -- Compte affecté par cette catégorie FOREIGN KEY(compte) REFERENCES compta_comptes(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS plugins ( id TEXT NOT NULL PRIMARY KEY, officiel INTEGER NOT NULL DEFAULT 0, nom TEXT NOT NULL, description TEXT NULL, auteur TEXT NULL, url TEXT NULL, version TEXT NOT NULL, menu INTEGER NOT NULL DEFAULT 0, menu_condition TEXT NULL, config TEXT NULL ); CREATE TABLE IF NOT EXISTS plugins_signaux -- Association entre plugins et signaux (hooks) ( signal TEXT NOT NULL, plugin TEXT NOT NULL REFERENCES plugins (id), callback TEXT NOT NULL, PRIMARY KEY (signal, plugin) ); CREATE TABLE IF NOT EXISTS compta_rapprochement -- Rapprochement entre compta et relevés de comptes ( id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL ); CREATE TABLE IF NOT EXISTS fichiers -- Données sur les fichiers ( id INTEGER NOT NULL PRIMARY KEY, nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg) type TEXT NULL, -- Type MIME image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime); CREATE TABLE IF NOT EXISTS fichiers_contenu -- Contenu des fichiers ( id INTEGER NOT NULL PRIMARY KEY, hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier taille INTEGER NOT NULL, -- Taille en octets contenu BLOB NULL ); CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash); CREATE TABLE IF NOT EXISTS fichiers_membres -- Associations entre fichiers et membres (photo de profil par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES membres (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_wiki_pages -- Associations entre fichiers et pages du wiki ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES wiki_pages (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_compta_journal -- Associations entre fichiers et journal de compta (pièce comptable par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id), id INTEGER NOT NULL REFERENCES compta_journal (id), PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS recherches -- Recherches enregistrées ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NULL REFERENCES membres (id) ON DELETE CASCADE, -- Si non NULL, alors la recherche ne sera visible que par le membre associé intitule TEXT NOT NULL, creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(creation) IS NOT NULL AND datetime(creation) = creation), cible TEXT NOT NULL, -- "membres" ou "compta_journal" type TEXT NOT NULL, -- "json" ou "sql" contenu TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS compromised_passwords_cache -- Cache des hash de mots de passe compromis ( hash TEXT NOT NULL PRIMARY KEY ); CREATE TABLE IF NOT EXISTS compromised_passwords_cache_ranges -- Cache des préfixes de mots de passe compromis ( prefix TEXT NOT NULL PRIMARY KEY, date INTEGER NOT NULL ); |
Added archives/plan_comptable.json version [c496246466].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 | { "1": { "code": 1, "nom": "Classe 1 \u2014 Comptes de capitaux (Fonds propres, emprunts et dettes assimil\u00e9s)", "parent": 0, "position": 1 }, "10": { "code": 10, "nom": "FONDS ASSOCIATIFS ET R\u00c9SERVES", "parent": 1, "position": 1 }, "102": { "code": 102, "nom": "Fonds associatif sans droit de reprise", "parent": 10, "position": 1 }, "1021": { "code": 1021, "nom": "Valeur du patrimoine int\u00e9gr\u00e9", "parent": 102, "position": 1 }, "1022": { "code": 1022, "nom": "Fonds statutaire", "parent": 102, "position": 1 }, "1024": { "code": 1024, "nom": "Apports sans droit de reprise", "parent": 102, "position": 1 }, "103": { "code": 103, "nom": "Fonds associatif avec droit de reprise", "parent": 10, "position": 1 }, "1034": { "code": 1034, "nom": "Apports avec droit de reprise", "parent": 103, "position": 1 }, "105": { "code": 105, "nom": "\u00c9carts de r\u00e9\u00e9valuation", "parent": 10, "position": 1 }, "106": { "code": 106, "nom": "R\u00e9serves", "parent": 10, "position": 1 }, "1063": { "code": 1063, "nom": "R\u00e9serves statutaires ou contractuelles", "parent": 106, "position": 1 }, "1064": { "code": 1064, "nom": "R\u00e9serves r\u00e9glement\u00e9es", "parent": 106, "position": 1 }, "1068": { "code": 1068, "nom": "Autres r\u00e9serves (dont r\u00e9serves pour projet associatif)", "parent": 106, "position": 1 }, "11": { "code": 11, "nom": "REPORT \u00c0 NOUVEAU", "parent": 1, "position": 1 }, "110": { "code": 110, "nom": "Report \u00e0 nouveau (Solde cr\u00e9diteur)", "parent": 11, "position": 1 }, "119": { "code": 119, "nom": "Report \u00e0 nouveau (Solde d\u00e9biteur)", "parent": 11, "position": 1 }, "12": { "code": 12, "nom": "R\u00c9SULTAT NET DE L'EXERCICE", "parent": 1, "position": 1 }, "120": { "code": 120, "nom": "R\u00e9sultat de l'exercice (exc\u00e9dent)", "parent": 12, "position": 1 }, "129": { "code": 129, "nom": "R\u00e9sultat de l'exercice (d\u00e9ficit)", "parent": 12, "position": 1 }, "13": { "code": 13, "nom": "SUBVENTIONS D'INVESTISSEMENT AFFECT\u00c9ES A DES BIENS NON RENOUVELABLES", "parent": 1, "position": 1 }, "131": { "code": 131, "nom": "Subventions d'investissement (renouvelables)", "parent": 13, "position": 1 }, "139": { "code": 139, "nom": "Subventions d'investissement inscrites au compte de r\u00e9sultat", "parent": 13, "position": 1 }, "14": { "code": 14, "nom": "PROVISIONS REGLEMENT\u00c9ES", "parent": 1, "position": 1 }, "15": { "code": 15, "nom": "PROVISIONS", "parent": 1, "position": 1 }, "151": { "code": 151, "nom": "Provisions pour risques", "parent": 15, "position": 1 }, "157": { "code": 157, "nom": "Provisions pour charges \u00e0 r\u00e9partir sur plusieurs exercices", "parent": 15, "position": 1 }, "158": { "code": 158, "nom": "Autres provisions pour charges", "parent": 15, "position": 1 }, "16": { "code": 16, "nom": "EMPRUNTS ET DETTES ASSIMIL\u00c9ES", "parent": 1, "position": 1 }, "164": { "code": 164, "nom": "Emprunts aupr\u00e8s des \u00e9tablissements de cr\u00e9dits", "parent": 16, "position": 1 }, "165": { "code": 165, "nom": "D\u00e9p\u00f4ts et cautionnements re\u00e7us", "parent": 16, "position": 1 }, "167": { "code": 167, "nom": "Emprunts et dettes assorties de conditions particuli\u00e8res", "parent": 16, "position": 1 }, "168": { "code": 168, "nom": "Autres emprunts et dettes assimil\u00e9s", "parent": 16, "position": 1 }, "17": { "code": 17, "nom": "DETTES RATTACH\u00c9ES \u00c0 DES PARTICIPATIONS", "parent": 1, "position": 1 }, "18": { "code": 18, "nom": "COMPTES DE LIAISON DES \u00c9TABLISSEMENTS", "parent": 1, "position": 1 }, "181": { "code": 181, "nom": "Apports permanents entre si\u00e8ge social et \u00e9tablissements", "parent": 18, "position": 1 }, "185": { "code": 185, "nom": "Biens et prestations de services \u00e9chang\u00e9s entre \u00e9tablissements et si\u00e8ge social", "parent": 18, "position": 1 }, "186": { "code": 186, "nom": "Biens et prestations de services \u00e9chang\u00e9s entre \u00e9tablissements (charges)", "parent": 18, "position": 1 }, "187": { "code": 187, "nom": "Biens et prestations de services \u00e9chang\u00e9s entre \u00e9tablissements (produits)", "parent": 18, "position": 1 }, "19": { "code": 19, "nom": "FONDS D\u00c9DI\u00c9S", "parent": 1, "position": 1 }, "194": { "code": 194, "nom": "Fonds d\u00e9di\u00e9s sur subventions de fonctionnement", "parent": 19, "position": 1 }, "195": { "code": 195, "nom": "Fonds d\u00e9di\u00e9s sur dons manuels affect\u00e9s", "parent": 19, "position": 1 }, "197": { "code": 197, "nom": "Fonds d\u00e9di\u00e9s sur legs et donations affect\u00e9s", "parent": 19, "position": 1 }, "198": { "code": 198, "nom": "Exc\u00e9dent disponible apr\u00e8s affectation au projet associatif", "parent": 19, "position": 1 }, "199": { "code": 199, "nom": "Reprise des fonds affect\u00e9s au projet associatif", "parent": 19, "position": 1 }, "2": { "code": 2, "nom": "Classe 2 \u2014 Comptes d'immobilisations", "parent": 0, "position": 2 }, "20": { "code": 20, "nom": "IMMOBILISATIONS INCORPORELLES", "parent": 2, "position": 2 }, "200": { "code": 200, "nom": "Immobilisations incorporelles", "parent": 20, "position": 2 }, "21": { "code": 21, "nom": "IMMOBILISATIONS CORPORELLES", "parent": 2, "position": 2 }, "210": { "code": 210, "nom": "Investissements", "parent": 21, "position": 2 }, "22": { "code": 22, "nom": "IMMOBILISATIONS GREV\u00c9ES DE DROITS", "parent": 2, "position": 2 }, "228": { "code": 228, "nom": "Immobilisations grev\u00e9es de droits", "parent": 22, "position": 2 }, "229": { "code": 229, "nom": "Droits des propri\u00e9taires", "parent": 22, "position": 2 }, "23": { "code": 23, "nom": "IMMOBILISATIONS EN COURS", "parent": 2, "position": 2 }, "231": { "code": 231, "nom": "Immobilisations corporelles en cours", "parent": 23, "position": 2 }, "238": { "code": 238, "nom": "Avances et acomptes vers\u00e9s sur commande d'immobilisations corporelles", "parent": 23, "position": 2 }, "26": { "code": 26, "nom": "PARTICIPATIONS ET CR\u00c9ANCES RATTACH\u00c9ES A DES PARTICIPATIONS", "parent": 2, "position": 2 }, "261": { "code": 261, "nom": "Titres de participation", "parent": 26, "position": 2 }, "27": { "code": 27, "nom": "AUTRES IMMOBILISATIONS FINANCI\u00c8RES", "parent": 2, "position": 2 }, "270": { "code": 270, "nom": "Participations financi\u00e8res", "parent": 27, "position": 2 }, "275": { "code": 275, "nom": "D\u00e9p\u00f4ts et cautionnements vers\u00e9s", "parent": 27, "position": 2 }, "28": { "code": 28, "nom": "AMORTISSEMENTS DES IMMOBILISATIONS", "parent": 2, "position": 2 }, "280": { "code": 280, "nom": "Amortissements des immobilisations incorporelles", "parent": 28, "position": 2 }, "281": { "code": 281, "nom": "Amortissements des immobilisations corporelles", "parent": 28, "position": 2 }, "29": { "code": 29, "nom": "D\u00c9PR\u00c9CIATION DES IMMOBILISATIONS", "parent": 2, "position": 2 }, "290": { "code": 290, "nom": "D\u00e9pr\u00e9ciation des immobilisations incorporelles", "parent": 29, "position": 2 }, "291": { "code": 291, "nom": "D\u00e9pr\u00e9ciation des immobilisations corporelles", "parent": 29, "position": 2 }, "3": { "code": 3, "nom": "Classe 3 \u2014 Comptes de stocks", "parent": 0, "position": 2 }, "31": { "code": 31, "nom": "MATIERES PREMIERES ET FOURNITURES", "parent": 3, "position": 2 }, "311": { "code": 311, "nom": "Mati\u00e8res", "parent": 31, "position": 2 }, "317": { "code": 317, "nom": "Fournitures", "parent": 31, "position": 2 }, "32": { "code": 32, "nom": "AUTRES APPROVISIONNEMENTS", "parent": 3, "position": 2 }, "321": { "code": 321, "nom": "Mati\u00e8res consommables", "parent": 32, "position": 2 }, "322": { "code": 322, "nom": "Fournitures consommables", "parent": 32, "position": 2 }, "33": { "code": 33, "nom": "EN-COURS DE PRODUCTION DE BIENS", "parent": 3, "position": 2 }, "331": { "code": 331, "nom": "Produits en cours", "parent": 33, "position": 2 }, "335": { "code": 335, "nom": "Travaux en cours", "parent": 33, "position": 2 }, "34": { "code": 34, "nom": "EN-COURS DE PRODUCTION DE SERVICES", "parent": 3, "position": 2 }, "35": { "code": 35, "nom": "STOCKS DE PRODUITS", "parent": 3, "position": 2 }, "351": { "code": 351, "nom": "Produits interm\u00e9diaires", "parent": 35, "position": 2 }, "355": { "code": 355, "nom": "Produits finis", "parent": 35, "position": 2 }, "358": { "code": 358, "nom": "Produits r\u00e9siduels", "parent": 35, "position": 2 }, "3581": { "code": 3581, "nom": "D\u00e9chets", "parent": 358, "position": 2 }, "3585": { "code": 3585, "nom": "Rebuts", "parent": 358, "position": 2 }, "3586": { "code": 3586, "nom": "Mati\u00e8re de r\u00e9cup\u00e9ration", "parent": 358, "position": 2 }, "37": { "code": 37, "nom": "STOCKS DE MARCHANDISES", "parent": 3, "position": 2 }, "370": { "code": 370, "nom": "Autres stocks de marchandises", "parent": 37, "position": 2 }, "39": { "code": 39, "nom": "PROVISIONS POUR DEPRECIATION DES STOCKS ET EN-COURS", "parent": 3, "position": 2 }, "391": { "code": 391, "nom": "Provisions pour d\u00e9pr\u00e9ciation des mati\u00e8res premi\u00e8res et fournitures", "parent": 39, "position": 2 }, "4": { "code": 4, "nom": "Classe 4 \u2014 Comptes de tiers", "parent": 0, "position": 3 }, "40": { "code": 40, "nom": "FOURNISSEURS ET COMPTES RATTACH\u00c9S", "parent": 4, "position": 1 }, "401": { "code": 401, "nom": "Fournisseurs", "parent": 40, "position": 1 }, "4010": { "code": 4010, "nom": "Autres fournisseurs", "parent": 401, "position": 1 }, "408": { "code": 408, "nom": "Fournisseurs - Factures non parvenues", "parent": 40, "position": 1 }, "409": { "code": 409, "nom": "Avances aux fournisseurs", "parent": 40, "position": 2 }, "41": { "code": 41, "nom": "USAGERS ET COMPTES RATTACH\u00c9S", "parent": 4, "position": 2 }, "411": { "code": 411, "nom": "Usagers", "parent": 41, "position": 2 }, "4110": { "code": 4110, "nom": "Autres usagers", "parent": 411, "position": 2 }, "419": { "code": 419, "nom": "Avances aux usagers", "parent": 41, "position": 1 }, "42": { "code": 42, "nom": "PERSONNEL ET COMPTES RATTACH\u00c9S", "parent": 4, "position": 1 }, "421": { "code": 421, "nom": "Personnel - R\u00e9mun\u00e9rations dues", "parent": 42, "position": 1 }, "4210": { "code": 4210, "nom": "Autres membres du personnel", "parent": 421, "position": 1 }, "425": { "code": 425, "nom": "Personnel - Avances et acomptes", "parent": 42, "position": 2 }, "428": { "code": 428, "nom": "Personnel - Charges \u00e0 payer et produits \u00e0 recevoir", "parent": 42, "position": 1 }, "43": { "code": 43, "nom": "S\u00c9CURIT\u00c9 SOCIALE ET AUTRES ORGANISMES SOCIAUX", "parent": 4, "position": 1 }, "430": { "code": 430, "nom": "Dettes et cr\u00e9dits envers les organismes sociaux", "parent": 43, "position": 1 }, "431": { "code": 431, "nom": "S\u00e9curit\u00e9 sociale", "parent": 43, "position": 1 }, "437": { "code": 437, "nom": "Autres organismes sociaux", "parent": 43, "position": 1 }, "4372": { "code": 4372, "nom": "Mutuelles", "parent": 437, "position": 1 }, "4373": { "code": 4373, "nom": "Caisse de retraite et de pr\u00e9voyance", "parent": 437, "position": 1 }, "4374": { "code": 4374, "nom": "Caisse d'allocations de ch\u00f4mage - P\u00f4le emploi", "parent": 437, "position": 1 }, "4375": { "code": 4375, "nom": "AGESSA", "parent": 437, "position": 1 }, "4378": { "code": 4378, "nom": "Autres organismes sociaux - Divers", "parent": 437, "position": 1 }, "438": { "code": 438, "nom": "Organismes sociaux - Charges \u00e0 payer et produits \u00e0 recevoir", "parent": 43, "position": 1 }, "4382": { "code": 4382, "nom": "Charges sociales sur cong\u00e9s \u00e0 payer", "parent": 438, "position": 1 }, "4386": { "code": 4386, "nom": "Autres charges \u00e0 payer", "parent": 438, "position": 1 }, "4387": { "code": 4387, "nom": "Produits \u00e0 recevoir", "parent": 438, "position": 2 }, "439": { "code": 439, "nom": "Avances aupr\u00e8s des organismes sociaux", "parent": 43, "position": 1 }, "44": { "code": 44, "nom": "\u00c9TAT ET AUTRES COLLECTIVIT\u00c9S PUBLIQUES", "parent": 4, "position": 2 }, "441": { "code": 441, "nom": "\u00c9tat - Subventions \u00e0 recevoir", "parent": 44, "position": 2 }, "4411": { "code": 4411, "nom": "Subventions d'investissement", "parent": 441, "position": 2 }, "4417": { "code": 4417, "nom": "Subventions d'exploitation", "parent": 441, "position": 2 }, "4418": { "code": 4418, "nom": "Subventions d'\u00e9quilibre", "parent": 441, "position": 2 }, "4419": { "code": 4419, "nom": "Avances sur subventions", "parent": 441, "position": 2 }, "442": { "code": 442, "nom": "\u00c9tat - Imp\u00f4ts et taxes recouvrables sur des tiers", "parent": 44, "position": 1 }, "444": { "code": 444, "nom": "\u00c9tat - Imp\u00f4ts sur les b\u00e9n\u00e9fices", "parent": 44, "position": 2 }, "445": { "code": 445, "nom": "\u00c9tat - Taxes sur le chiffre d'affaires", "parent": 44, "position": 2 }, "4455": { "code": 4455, "nom": "Taxes sur le chiffre d'affaires \u00e0 d\u00e9caisser", "parent": 445, "position": 2 }, "44551": { "code": 44551, "nom": "TVA \u00e0 d\u00e9caisser", "parent": 4455, "position": 2 }, "44558": { "code": 44558, "nom": "Taxes assimil\u00e9es \u00e0 la TVA", "parent": 4455, "position": 2 }, "4456": { "code": 4456, "nom": "Taxes sur le chiffre d'affaires d\u00e9ductibles", "parent": 445, "position": 2 }, "44562": { "code": 44562, "nom": "TVA sur immobilisations", "parent": 4456, "position": 2 }, "44566": { "code": 44566, "nom": "TVA sur autres biens et services", "parent": 4456, "position": 2 }, "4457": { "code": 4457, "nom": "Taxes sur le chiffre d'affaires collect\u00e9es par l'association", "parent": 445, "position": 2 }, "4458": { "code": 4458, "nom": "Taxes sur le chiffre d'affaires \u00e0 r\u00e9gulariser ou en attente", "parent": 445, "position": 2 }, "44581": { "code": 44581, "nom": "Acomptes - R\u00e9gime simplifi\u00e9 d'imposition", "parent": 4458, "position": 2 }, "44582": { "code": 44582, "nom": "Acomptes - R\u00e9gime du forfait", "parent": 4458, "position": 2 }, "44583": { "code": 44583, "nom": "Remboursement de taxes sur le chiffre d'affaires demand\u00e9", "parent": 4458, "position": 2 }, "44584": { "code": 44584, "nom": "TVA r\u00e9cup\u00e9r\u00e9e d'avance", "parent": 4458, "position": 2 }, "44586": { "code": 44586, "nom": "Taxes sur le chiffre d'affaires sur factures non parvenues", "parent": 4458, "position": 2 }, "44587": { "code": 44587, "nom": "Taxes sur le chiffre d'affaires sur factures \u00e0 \u00e9tablir", "parent": 4458, "position": 2 }, "447": { "code": 447, "nom": "Autres imp\u00f4ts, taxes et versements assimil\u00e9s", "parent": 44, "position": 1 }, "4471": { "code": 4471, "nom": "Autres imp\u00f4ts, taxes et versements assimil\u00e9s sur r\u00e9mun\u00e9rations (Administration des imp\u00f4ts)", "parent": 447, "position": 1 }, "44711": { "code": 44711, "nom": "Taxe sur les salaires", "parent": 4471, "position": 1 }, "44713": { "code": 44713, "nom": "Participation des employeurs \u00e0 la formation professionnelle continue", "parent": 4471, "position": 1 }, "44714": { "code": 44714, "nom": "Cotisation par d\u00e9faut d'investissement obligatoire dans la construction", "parent": 4471, "position": 1 }, "44718": { "code": 44718, "nom": "Autres imp\u00f4ts, taxes et versements assimil\u00e9s", "parent": 4471, "position": 1 }, "4473": { "code": 4473, "nom": "Autres imp\u00f4ts, taxes et versements assimil\u00e9s sur r\u00e9mun\u00e9rations (Autres organismes)", "parent": 447, "position": 1 }, "44733": { "code": 44733, "nom": "Participation des employeurs \u00e0 la formation professionnelle continue", "parent": 4473, "position": 1 }, "44734": { "code": 44734, "nom": "Participation des employeurs \u00e0 l'effort de construction (versements \u00e0 fonds perdus)", "parent": 4473, "position": 1 }, "4475": { "code": 4475, "nom": "Autres imp\u00f4ts, taxes et versements assimil\u00e9s (Administration des imp\u00f4ts)", "parent": 447, "position": 1 }, "4477": { "code": 4477, "nom": "Autres imp\u00f4ts, taxes et versements assimil\u00e9s (Autres organismes)", "parent": 447, "position": 1 }, "448": { "code": 448, "nom": "\u00c9tat - Charges \u00e0 payer et produits \u00e0 recevoir", "parent": 44, "position": 1 }, "4482": { "code": 4482, "nom": "Charges fiscales sur cong\u00e9s \u00e0 payer", "parent": 448, "position": 1 }, "4486": { "code": 4486, "nom": "Autres charges \u00e0 payer", "parent": 448, "position": 1 }, "4487": { "code": 4487, "nom": "Produits \u00e0 recevoir", "parent": 448, "position": 2 }, "449": { "code": 449, "nom": "Avances aupr\u00e8s de l'\u00e9tat et des collectivit\u00e9s publiques", "parent": 44, "position": 1 }, "45": { "code": 45, "nom": "CONF\u00c9D\u00c9RATION, F\u00c9D\u00c9RATION, UNIONS ET ASSOCIATIONS AFFILI\u00c9ES", "parent": 4, "position": 3 }, "451": { "code": 451, "nom": "Conf\u00e9d\u00e9ration, f\u00e9d\u00e9ration et associations affili\u00e9es - Compte courant", "parent": 45, "position": 3 }, "455": { "code": 455, "nom": "Soci\u00e9taires - Comptes courants", "parent": 45, "position": 3 }, "46": { "code": 46, "nom": "D\u00c9BITEURS DIVERS ET CR\u00c9DITEURS DIVERS", "parent": 4, "position": 3 }, "467": { "code": 467, "nom": "Autres comptes d\u00e9biteurs et cr\u00e9diteurs", "parent": 46, "position": 3 }, "468": { "code": 468, "nom": "Divers - Charges \u00e0 payer et produits \u00e0 recevoir", "parent": 46, "position": 3 }, "4686": { "code": 4686, "nom": "Charges \u00e0 payer", "parent": 468, "position": 1 }, "4687": { "code": 4687, "nom": "Produits \u00e0 recevoir", "parent": 468, "position": 2 }, "47": { "code": 47, "nom": "COMPTES TRANSITOIRES OU D'ATTENTE", "parent": 4, "position": 3 }, "471": { "code": 471, "nom": "Recettes \u00e0 classer", "parent": 47, "position": 1 }, "472": { "code": 472, "nom": "D\u00e9penses \u00e0 classer et \u00e0 r\u00e9gulariser", "parent": 47, "position": 2 }, "48": { "code": 48, "nom": "COMPTES DE R\u00c9GULARISATION", "parent": 4, "position": 3 }, "481": { "code": 481, "nom": "Charges \u00e0 r\u00e9partir sur plusieurs exercices", "parent": 48, "position": 2 }, "486": { "code": 486, "nom": "Charges constat\u00e9es d'avance", "parent": 48, "position": 2 }, "487": { "code": 487, "nom": "Produits constat\u00e9s d'avance", "parent": 48, "position": 1 }, "49": { "code": 49, "nom": "DEPRECIATION DES COMPTES DE TIERS", "parent": 4, "position": 2 }, "491": { "code": 491, "nom": "D\u00e9pr\u00e9ciation des comptes clients", "parent": 49, "position": 2 }, "496": { "code": 496, "nom": "D\u00e9pr\u00e9ciation des comptes d\u00e9biteurs divers", "parent": 49, "position": 2 }, "5": { "code": 5, "nom": "Classe 5 \u2014 Comptes financiers", "parent": 0, "position": 2 }, "50": { "code": 50, "nom": "VALEURS MOBILI\u00c8RES DE PLACEMENT", "parent": 5, "position": 2 }, "51": { "code": 51, "nom": "BANQUES, \u00c9TABLISSEMENTS FINANCIERS ET ASSIMIL\u00c9S", "parent": 5, "position": 2 }, "511": { "code": 511, "nom": "Valeurs à l'encaissement", "parent": 51, "position": 2 }, "5112": { "code": 5112, "nom": "Chèques à encaisser", "parent": 511, "position": 2 }, "5115": { "code": 5115, "nom": "Paiements par carte à encaisser", "parent": 511, "position": 2 }, "512": { "code": 512, "nom": "Banques", "parent": 51, "position": 2 }, "53": { "code": 53, "nom": "CAISSE", "parent": 5, "position": 2 }, "530": { "code": 530, "nom": "Caisse", "parent": 53, "position": 2 }, "54": { "code": 54, "nom": "R\u00c9GIES D'AVANCES ET ACCR\u00c9DITIFS", "parent": 5, "position": 2 }, "58": { "code": 58, "nom": "VIREMENTS INTERNES", "parent": 5, "position": 2 }, "59": { "code": 59, "nom": "PROVISIONS POUR D\u00c9PR\u00c9CIATION DES COMPTES FINANCIERS", "parent": 5, "position": 2 }, "6": { "code": 6, "nom": "Classe 6 \u2014 Comptes de charges", "parent": 0, "position": 8 }, "60": { "code": 60, "nom": "ACHATS", "parent": 6, "position": 8 }, "601": { "code": 601, "nom": "Achats stock\u00e9s - Mati\u00e8res premi\u00e8res et fournitures", "parent": 60, "position": 8 }, "602": { "code": 602, "nom": "Achats stock\u00e9s - Autres approvisionnements", "parent": 60, "position": 8 }, "604": { "code": 604, "nom": "Achat d'\u00e9tudes et prestations de services", "parent": 60, "position": 8 }, "606": { "code": 606, "nom": "Achats non stock\u00e9s de mati\u00e8res et fournitures", "parent": 60, "position": 8 }, "6061": { "code": 6061, "nom": "Fournitures non stockables (eau, \u00e9nergie...)", "parent": 606, "position": 8 }, "6063": { "code": 6063, "nom": "Fournitures d'entretien et de petit \u00e9quipement", "parent": 606, "position": 8 }, "6064": { "code": 6064, "nom": "Fournitures administratives", "parent": 606, "position": 8 }, "6068": { "code": 6068, "nom": "Autres mati\u00e8res et fournitures", "parent": 606, "position": 8 }, "607": { "code": 607, "nom": "Achats de marchandises", "parent": 60, "position": 8 }, "61": { "code": 61, "nom": "SERVICES EXT\u00c9RIEURS", "parent": 6, "position": 8 }, "611": { "code": 611, "nom": "Sous-traitance g\u00e9n\u00e9rale", "parent": 61, "position": 8 }, "612": { "code": 612, "nom": "Redevances de cr\u00e9dit-bail", "parent": 61, "position": 8 }, "613": { "code": 613, "nom": "Locations", "parent": 61, "position": 8 }, "614": { "code": 614, "nom": "Charges locatives et de co-propri\u00e9t\u00e9", "parent": 61, "position": 8 }, "615": { "code": 615, "nom": "Entretiens et r\u00e9parations", "parent": 61, "position": 8 }, "616": { "code": 616, "nom": "Primes d'assurance", "parent": 61, "position": 8 }, "618": { "code": 618, "nom": "Divers", "parent": 61, "position": 8 }, "62": { "code": 62, "nom": "AUTRES SERVICES EXT\u00c9RIEURS", "parent": 6, "position": 8 }, "621": { "code": 621, "nom": "Personnel ext\u00e9rieur \u00e0 l'association", "parent": 62, "position": 8 }, "622": { "code": 622, "nom": "R\u00e9mun\u00e9rations d'interm\u00e9diaires et honoraires", "parent": 62, "position": 8 }, "6226": { "code": 6226, "nom": "Honoraires", "parent": 622, "position": 8 }, "6227": { "code": 6227, "nom": "Frais d'actes et de contentieux", "parent": 622, "position": 8 }, "6228": { "code": 6228, "nom": "Divers", "parent": 622, "position": 8 }, "623": { "code": 623, "nom": "Publicit\u00e9, publications, relations publiques", "parent": 62, "position": 8 }, "624": { "code": 624, "nom": "Transports de biens et transports collectifs du personnel", "parent": 62, "position": 8 }, "625": { "code": 625, "nom": "D\u00e9placements, missions et r\u00e9ceptions", "parent": 62, "position": 8 }, "626": { "code": 626, "nom": "Frais postaux et de t\u00e9l\u00e9communications", "parent": 62, "position": 8 }, "627": { "code": 627, "nom": "Services bancaires et assimil\u00e9s", "parent": 62, "position": 8 }, "628": { "code": 628, "nom": "Divers", "parent": 62, "position": 8 }, "63": { "code": 63, "nom": "IMP\u00d4TS, TAXES ET VERSEMENTS ASSIMIL\u00c9S", "parent": 6, "position": 8 }, "631": { "code": 631, "nom": "Imp\u00f4ts, taxes et versements assimil\u00e9s sur r\u00e9mun\u00e9rations (Administration des imp\u00f4ts)", "parent": 63, "position": 8 }, "6311": { "code": 6311, "nom": "Taxes sur les salaires", "parent": 631, "position": 8 }, "6313": { "code": 6313, "nom": "Participations des employeurs \u00e0 la formation professionnelle continue", "parent": 631, "position": 8 }, "635": { "code": 635, "nom": "Autres imp\u00f4ts, taxes et versements assimil\u00e9s (Administration des imp\u00f4ts)", "parent": 63, "position": 8 }, "6351": { "code": 6351, "nom": "Imp\u00f4ts directs (sauf imp\u00f4ts sur les b\u00e9n\u00e9fices)", "parent": 635, "position": 8 }, "6353": { "code": 6353, "nom": "Imp\u00f4ts indirects", "parent": 635, "position": 8 }, "637": { "code": 637, "nom": "Autres imp\u00f4ts, taxes et versements assimil\u00e9s (Autres organismes)", "parent": 63, "position": 8 }, "64": { "code": 64, "nom": "CHARGES DE PERSONNEL", "parent": 6, "position": 8 }, "641": { "code": 641, "nom": "R\u00e9mun\u00e9rations du personnel", "parent": 64, "position": 8 }, "643": { "code": 643, "nom": "R\u00e9mun\u00e9rations du personnel artistique et assimil\u00e9s", "parent": 64, "position": 8 }, "645": { "code": 645, "nom": "Charges de s\u00e9curit\u00e9 sociale et de pr\u00e9voyance", "parent": 64, "position": 8 }, "647": { "code": 647, "nom": "Autres charges sociales", "parent": 64, "position": 8 }, "648": { "code": 648, "nom": "Autres charges de personnel", "parent": 64, "position": 8 }, "65": { "code": 65, "nom": "AUTRES CHARGES DE GESTION COURANTE", "parent": 6, "position": 8 }, "652": { "code": 652, "nom": "Licences fédérales", "parent": 652, "position": 8 }, "658": { "code": 658, "nom": "Charges diverses de gestion courante", "parent": 65, "position": 8 }, "66": { "code": 66, "nom": "CHARGES FINANCI\u00c8RES", "parent": 6, "position": 8 }, "661": { "code": 661, "nom": "Charges d'int\u00e9r\u00eats", "parent": 66, "position": 8 }, "67": { "code": 67, "nom": "CHARGES EXCEPTIONNELLES", "parent": 6, "position": 8 }, "671": { "code": 671, "nom": "Charges exceptionnelles sur op\u00e9rations de gestion", "parent": 67, "position": 8 }, "6713": { "code": 6713, "nom": "Dons, lib\u00e9ralit\u00e9s", "parent": 671, "position": 8 }, "678": { "code": 678, "nom": "Autres charges exceptionnelles", "parent": 67, "position": 8 }, "6788": { "code": 6788, "nom": "Charges exceptionnelles diverses", "parent": 678, "position": 8 }, "68": { "code": 68, "nom": "DOTATIONS AUX AMORTISSEMENTS, D\u00c9PR\u00c9CIATIONS, PROVISIONS ET ENGAGEMENTS", "parent": 6, "position": 8 }, "681": { "code": 681, "nom": "Dotations aux amortissements, d\u00e9pr\u00e9ciations et provisions - Charges d'exploitation", "parent": 68, "position": 8 }, "6811": { "code": 6811, "nom": "Dotations aux amortissements des immobilisations incorporelles et corporelles", "parent": 681, "position": 8 }, "68111": { "code": 68111, "nom": "Immobilisations incorporelles", "parent": 6811, "position": 8 }, "68112": { "code": 68112, "nom": "Immobilisations corporelles", "parent": 6811, "position": 8 }, "686": { "code": 686, "nom": "Dotations aux amortissements, d\u00e9pr\u00e9ciations et provisions - Charges financi\u00e8res", "parent": 68, "position": 8 }, "69": { "code": 69, "nom": "PARTICIPATION DES SALARI\u00c9S - IMP\u00d4TS SUR LES B\u00c9N\u00c9FICES ET ASSIMIL\u00c9S", "parent": 6, "position": 8 }, "695": { "code": 695, "nom": "Imp\u00f4ts sur les soci\u00e9t\u00e9s (y compris imp\u00f4ts sur les soci\u00e9t\u00e9s des personnes morales non lucratives)", "parent": 69, "position": 8 }, "7": { "code": 7, "nom": "Classe 7 \u2014 Comptes de produits", "parent": 0, "position": 4 }, "70": { "code": 70, "nom": "VENTES DE PRODUITS FINIS, PRESTATIONS DE SERVICES, MARCHANDISES", "parent": 7, "position": 4 }, "701": { "code": 701, "nom": "Ventes de produits finis", "parent": 70, "position": 4 }, "706": { "code": 706, "nom": "Prestations de services", "parent": 70, "position": 4 }, "707": { "code": 707, "nom": "Ventes de marchandises", "parent": 70, "position": 4 }, "708": { "code": 708, "nom": "Produits des activit\u00e9s annexes", "parent": 70, "position": 4 }, "71": { "code": 71, "nom": "PRODUCTION STOCK\u00c9E (OU D\u00c9STOCKAGE)", "parent": 7, "position": 4 }, "72": { "code": 72, "nom": "PRODUCTION IMMOBILIS\u00c9E", "parent": 7, "position": 4 }, "74": { "code": 74, "nom": "SUBVENTIONS D'EXPLOITATION", "parent": 7, "position": 4 }, "740": { "code": 740, "nom": "Subventions re\u00e7ues", "parent": 74, "position": 4 }, "75": { "code": 75, "nom": "AUTRES PRODUITS DE GESTION COURANTE", "parent": 7, "position": 4 }, "754": { "code": 754, "nom": "Collectes", "parent": 75, "position": 4 }, "756": { "code": 756, "nom": "Cotisations", "parent": 75, "position": 4 }, "758": { "code": 758, "nom": "Produits divers de gestion courante", "parent": 75, "position": 4 }, "7587": { "code": 7587, "nom": "Ventes de dons en nature", "parent": 758, "position": 4 }, "7588": { "code": 7588, "nom": "Autres produits de la g\u00e9n\u00e9rosit\u00e9 du public", "parent": 758, "position": 4 }, "76": { "code": 76, "nom": "PRODUITS FINANCIERS", "parent": 7, "position": 4 }, "760": { "code": 760, "nom": "Produits financiers", "parent": 76, "position": 4 }, "77": { "code": 77, "nom": "PRODUITS EXCEPTIONNELS", "parent": 7, "position": 4 }, "771": { "code": 771, "nom": "Produits exceptionnels sur op\u00e9rations de gestion", "parent": 77, "position": 4 }, "7713": { "code": 7713, "nom": "Lib\u00e9ralit\u00e9s re\u00e7ues", "parent": 771, "position": 4 }, "7715": { "code": 7715, "nom": "Subventions d'\u00e9quilibre", "parent": 771, "position": 4 }, "775": { "code": 775, "nom": "Produits des cessions d'\u00e9l\u00e9ments d'actifs", "parent": 77, "position": 4 }, "778": { "code": 778, "nom": "Autres produits exceptionnels", "parent": 77, "position": 4 }, "7780": { "code": 7780, "nom": "Manifestations diverses", "parent": 778, "position": 4 }, "7788": { "code": 7788, "nom": "Produits exceptionnels divers", "parent": 778, "position": 4 }, "78": { "code": 78, "nom": "REPRISES SUR AMORTISSEMENTS ET PROVISIONS", "parent": 7, "position": 4 }, "79": { "code": 79, "nom": "TRANSFERT DE CHARGES", "parent": 7, "position": 4 }, "791": { "code": 791, "nom": "Transferts de charges d'exploitation", "parent": 79, "position": 4 }, "796": { "code": 796, "nom": "Transferts de charges financi\u00e8res", "parent": 79, "position": 4 }, "797": { "code": 797, "nom": "Transferts de charges exceptionnels", "parent": 79, "position": 4 }, "8": { "code": 8, "nom": "Classe 8 \u00ad\u2014 Comptes sp\u00e9ciaux", "parent": 0, "position": 12 }, "86": { "code": 86, "nom": "R\u00c9PARTITION PAR NATURE DE CHARGES", "parent": 8, "position": 8 }, "861": { "code": 861, "nom": "Mise \u00e0 dispositions gratuites de biens", "parent": 86, "position": 8 }, "862": { "code": 862, "nom": "Prestations", "parent": 86, "position": 8 }, "864": { "code": 864, "nom": "Personnel b\u00e9n\u00e9vole", "parent": 86, "position": 8 }, "87": { "code": 87, "nom": "R\u00c9PARTITION PAR NATURE DE RESSOURCES", "parent": 8, "position": 4 }, "870": { "code": 870, "nom": "B\u00e9n\u00e9volat", "parent": 87, "position": 4 }, "871": { "code": 871, "nom": "Prestations en nature", "parent": 87, "position": 4 }, "875": { "code": 875, "nom": "Dons en nature", "parent": 87, "position": 4 }, "89": { "code": 89, "nom": "BILAN", "parent": 8, "position": 3 }, "890": { "code": 890, "nom": "Bilan d'ouverture", "parent": 89, "position": 3 }, "891": { "code": 891, "nom": "Bilan de clôture", "parent": 89, "position": 3 }, "9": { "code": 9, "nom": "Classe 9 \u2014 Comptes analytiques", "parent": 0, "position": 12 } } |
Modified debian/config.debian.php from [2a98e1b5ea] to [1cd45bbd87].
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | $_ENV['XDG_CONFIG_HOME'] = $home . '/.config'; } if (!file_exists($_ENV['XDG_CONFIG_HOME'] . '/garradin')) { mkdir($_ENV['XDG_CONFIG_HOME'] . '/garradin', 0700, true); } // Data directory: where the data will go if (empty($_ENV['XDG_DATA_HOME'])) { $_ENV['XDG_DATA_HOME'] = $home . '/.local/share'; } if (!file_exists($_ENV['XDG_DATA_HOME'] . '/garradin')) { mkdir($_ENV['XDG_DATA_HOME'] . '/garradin', 0700, true); } | > > > > > | > > | | > > | | | | | | | | | | | | | | | | < | > > > > > | > > | > > | | > > | > > > | | < > | > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | $_ENV['XDG_CONFIG_HOME'] = $home . '/.config'; } if (!file_exists($_ENV['XDG_CONFIG_HOME'] . '/garradin')) { mkdir($_ENV['XDG_CONFIG_HOME'] . '/garradin', 0700, true); } if (file_exists($_ENV['XDG_CONFIG_HOME'] . '/garradin/config.local.php')) { require_once $_ENV['XDG_CONFIG_HOME'] . '/garradin/config.local.php'; } // Data directory: where the data will go if (empty($_ENV['XDG_DATA_HOME'])) { $_ENV['XDG_DATA_HOME'] = $home . '/.local/share'; } if (!file_exists($_ENV['XDG_DATA_HOME'] . '/garradin')) { mkdir($_ENV['XDG_DATA_HOME'] . '/garradin', 0700, true); } if (!defined('Garradin\DATA_ROOT')) { define('Garradin\DATA_ROOT', $_ENV['XDG_DATA_HOME'] . '/garradin'); } // Cache directory: temporary stuff if (empty($_ENV['XDG_CACHE_HOME'])) { $_ENV['XDG_CACHE_HOME'] = $home . '/.cache'; } if (!file_exists($_ENV['XDG_CACHE_HOME'] . '/garradin')) { mkdir($_ENV['XDG_CACHE_HOME'] . '/garradin', 0700, true); } if (!defined('Garradin\CACHE_ROOT')) { define('Garradin\CACHE_ROOT', $_ENV['XDG_CACHE_HOME'] . '/garradin'); } if (!defined('Garradin\DB_FILE')) { $last_file = $_ENV['XDG_CONFIG_HOME'] . '/garradin/last'; if ($_ENV['GARRADIN_STANDALONE'] != 1) { $last_sqlite = trim($_ENV['GARRADIN_STANDALONE']); } else if (file_exists($last_file)) { $last_sqlite = trim(file_get_contents($last_file)); } else { $last_sqlite = $_ENV['XDG_DATA_HOME'] . '/garradin/association.sqlite'; } file_put_contents($last_file, $last_sqlite); define('Garradin\DB_FILE', $last_sqlite); } if (!defined('Garradin\LOCAL_LOGIN')) { define('Garradin\LOCAL_LOGIN', true); } } elseif (isset($_SERVER['SERVER_NAME'])) { if (file_exists('/etc/garradin/config.php')) { require_once '/etc/garradin/config.php'; } if (!defined('Garradin\DATA_ROOT')) { define('Garradin\DATA_ROOT', '/var/lib/garradin'); } if (!defined('Garradin\CACHE_ROOT')) { define('Garradin\CACHE_ROOT', '/var/cache/garradin'); } } if (!defined('Garradin\SECRET_KEY')) { if (file_exists(CACHE_ROOT . '/key')) { define('Garradin\SECRET_KEY', trim(file_get_contents(CACHE_ROOT . '/key'))); } else { define('Garradin\SECRET_KEY', base64_encode(random_bytes(64))); file_put_contents(CACHE_ROOT . '/key', SECRET_KEY); } } |
Modified debian/makedeb.sh from [242f467b69] to [00b4e03f70].
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 | CODEDIR=${DEBLOCALPREFIX}/share/${PACKAGE_DEBNAME} mkdir -p ${CODEDIR} cp -r ${SRCDIR}/* ${CODEDIR} cp ${THISDIR}/config.debian.php ${CODEDIR}/config.local.php rm -rf ${CODEDIR}/*.sqlite ${CODEDIR}/cache ${CODEDIR}/www/squelettes cp ${THISDIR}/garradin.png "${CODEDIR}" # Cleaning files that will be copied to /usr/share/doc | > > > > | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | CODEDIR=${DEBLOCALPREFIX}/share/${PACKAGE_DEBNAME} mkdir -p ${CODEDIR} cp -r ${SRCDIR}/* ${CODEDIR} cp ${THISDIR}/config.debian.php ${CODEDIR}/config.local.php rm -rf ${CODEDIR}/*.sqlite ${CODEDIR}/cache ${CODEDIR}/www/squelettes cp ${THISDIR}/garradin.png "${CODEDIR}" mkdir -p "${DEBROOT}/var/lib/${PACKAGE_DEBNAME}" mkdir -p "${DEBROOT}/var/cache/${PACKAGE_DEBNAME}" mkdir -p "${DEBROOT}/etc/${PACKAGE_DEBNAME}" # Cleaning files that will be copied to /usr/share/doc #rm -f ${CODEDIR}/../{README.md,COPYING} cd $DEBROOT || { echo "Debian dest dir [$DEBROOT] not found. :(" exit 2 } rm -fr DEBIAN |
︙ | ︙ | |||
60 61 62 63 64 65 66 | echo "Creating .deb package [${DEBFILE}]..." echo "Generating md5 sums..." find ${DEBLOCALPREFIX} -type f -exec md5sum {} \; > DEBIAN/md5sums true && { echo "Generating Debian-specific files..." | | > > > > > > > > > > > > > > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | echo "Creating .deb package [${DEBFILE}]..." echo "Generating md5 sums..." find ${DEBLOCALPREFIX} -type f -exec md5sum {} \; > DEBIAN/md5sums true && { echo "Generating Debian-specific files..." cp ${THISDIR}/../COPYING ${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/copyright } || { echo "Fail." exit 1 } true && { cat <<EOF > DEBIAN/postinst #!/bin/sh chown www-data:www-data /var/lib/garradin /var/cache/garradin chown root:www-data /etc/garradin chmod g=rX,o= /etc/garradin chmod ug=rwX,o= /var/lib/garradin /var/cache/garradin EOF chmod +x DEBIAN/postinst } true && { CHANGELOG=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/changelog.gz cat <<EOF | gzip -c > ${CHANGELOG} ${PACKAGE_DEBNAME} ${PACKAGE_DEB_VERSION}; urgency=low |
︙ | ︙ | |||
86 87 88 89 90 91 92 | } # doc. DOCDIR=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME} true && { echo "Generating doc..." | | | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | } # doc. DOCDIR=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME} true && { echo "Generating doc..." cp ${THISDIR}/../README.md ${DOCDIR} a2x --doctype manpage --format manpage ${THISDIR}/manpage.txt mkdir -p ${DEBLOCALPREFIX}/share/man/man1 gzip -c ${THISDIR}/garradin.1 > ${DEBLOCALPREFIX}/share/man/man1/${PACKAGE_DEBNAME}.1.gz rm -f ${THISDIR}/garradin.1 } || { echo "Fail." exit 1 } true && { CONTROL=DEBIAN/control echo "Generating ${CONTROL}..." cat <<EOF > ${CONTROL} Package: ${PACKAGE_DEBNAME} Section: web Priority: optional Maintainer: Garradin <garradin@kd2.org> Architecture: ${DEB_ARCH_NAME} Depends: dash | bash, php-cli (>=7.2), php-sqlite3 Version: ${PACKAGE_DEB_VERSION} Suggests: www-browser, php-gd Homepage: http://dev.kd2.org/garradin/ Description: Garradin is a tool to manage non-profit organizations. It's only available in french. Description-fr: Gestionnaire d'association en interface web ou CLI. Garradin est un gestionnaire d'association à but non lucratif. |
︙ | ︙ |
Added doc/dev/odoo_accounts.sql version [6c994995cd].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 | -- Schéma Odoo (PgSQL) pour info sur la compta -- Pour les écritures, deux tables : move et move_line -- Utilisation de deux colonnes "debit" et "credit" -- https://github.com/odoo/odoo/blob/11.0/addons/account/data/data_account_type.xml -- https://www.odoo.com/documentation/11.0/webservices/localization.html CREATE TABLE public.account_account_type ( id integer NOT NULL, name character varying NOT NULL, include_initial_balance boolean, type character varying NOT NULL, note text, create_uid integer, create_date timestamp without time zone, write_uid integer, write_date timestamp without time zone ); COPY public.account_account_type (id, name, include_initial_balance, type, note, create_uid, create_date, write_uid, write_date) FROM stdin; 1 Receivable t receivable \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 2 Payable t payable \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 3 Bank and Cash t liquidity \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 4 Credit Card t liquidity \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 5 Current Assets t other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 6 Non-current Assets t other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 7 Prepayments t other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 8 Fixed Assets t other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 9 Current Liabilities t other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 10 Non-current Liabilities t other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 11 Equity t other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 12 Current Year Earnings t other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 13 Other Income f other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 14 Income f other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 15 Depreciation f other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 16 Expenses f other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 17 Cost of Revenue f other \N 1 2019-02-14 15:05:35.697512 1 2019-02-14 15:05:35.697512 \. COPY public.account_account (id, name, currency_id, code, deprecated, user_type_id, internal_type, last_time_entries_checked, reconcile, note, company_id, group_id, create_uid, create_date, write_uid, write_date) FROM stdin; 1 Virements Internes \N 580000 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 2 Capital souscrit - non appelé \N 101100 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 3 Capital souscrit - appelé non versé \N 101200 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 4 Capital non amorti \N 101310 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 5 Capital amorti \N 101320 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 6 Capital souscrit soumis à des réglementations particulières \N 101800 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 7 Primes d'émission \N 104100 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 8 Primes de fusion \N 104200 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 10 Primes de conversion d'obligations en actions \N 104400 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 11 Bons de souscription d'actions \N 104500 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 12 Réserve spéciale de réévaluation \N 105100 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 13 Écart de réévaluation libre \N 105200 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 15 Écarts de réévaluation (autres opérations légales) \N 105500 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 16 Autres écarts de réévaluation en France \N 105700 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 17 Autres écarts de réévaluation à l'étranger \N 105800 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 18 Réserve légale proprement dite \N 106110 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 19 Plus-values nettes à long terme \N 106120 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 20 Réserves indisponibles \N 106200 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 22 Plus-values nettes à long terme \N 106410 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 23 Réserves consécutives à l'octroi de subventions d'investissement \N 106430 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 24 Autres réserves réglementées \N 106480 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 25 Réserve de propre assureur \N 106810 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 26 Réserves diverses \N 106880 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 27 Écarts d'équivalence \N 107000 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 28 Compte de l'exploitant \N 108000 f 11 other \N f Capital pour une Entreprise Individuelle 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 29 Actionnaires : capital souscrit - non appelé \N 109000 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 31 Report à nouveau (solde débiteur) \N 119000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 30 Report à nouveau (solde créditeur) \N 110000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 9 Primes d'apport \N 104300 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 14 Réserve de réévaluation \N 105300 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 21 Réserves statutaires ou contractuelles \N 106300 f 11 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 32 Résultat de l'exercice (bénéfice) \N 120000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 33 Résultat de l'exercice (perte) \N 129000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 34 Subventions d'équipement - État \N 131100 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 35 Subventions d'équipement - Régions \N 131200 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 37 Subventions d'équipement - Communes \N 131400 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 38 Subventions d'équipement - Collectivités publiques \N 131500 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 39 Subventions d'équipement - Entreprises publiques \N 131600 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 40 Subventions d'équipement - Entreprises et organismes privés \N 131700 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 41 Subventions d'équipement - Autres \N 131800 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 42 Autres subventions d'investissement (même ventilation que celle du compte 131) \N 138000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 43 Subventions d'équipement inscrites au compte de résultat - État \N 139110 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 44 Subventions d'équipement inscrites au compte de résultat - Régions \N 139120 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 45 Subventions d'équipement inscrites au compte de résultat - Départements \N 139130 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 46 Subventions d'équipement inscrites au compte de résultat - Communes \N 139140 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 47 Subventions d'équipement inscrites au compte de résultat - Collectivités publiques \N 139150 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 48 Subventions d'équipement inscrites au compte de résultat - Entreprises publiques \N 139160 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 49 Subventions d'équipement inscrites au compte de résultat - Entreprises et organismes privés \N 139170 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 50 Subventions d'équipement inscrites au compte de résultat - Autres \N 139180 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 51 Autres subventions d'investissement (même ventilation que celle du compte 1391) \N 139800 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 53 Provisions pour investissement (participation des salariés) \N 142400 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 54 Provisions réglementées relatives aux stocks - Hausse de prix \N 143100 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 55 Provisions réglementées relatives aux stocks - Fluctuation des cours \N 143200 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 56 Provisions réglementées relatives aux autres éléments de l'actif \N 144000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 57 Amortissements dérogatoires \N 145000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 58 Provision spéciale de réévaluation \N 146000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 36 Subventions d'équipement - Départements \N 131300 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 52 Provisions reconstitution des gisements miniers et pétroliers \N 142300 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 719 Bla bla \N 512002 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:11:18.063543 1 2019-02-14 15:11:18.063543 59 Plus-values réinvesties \N 147000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 60 Autres provisions réglementées \N 148000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 61 Provisions pour litiges \N 151100 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 62 Provisions pour garanties données aux clients \N 151200 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 64 Provisions pour amendes et pénalités \N 151400 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 65 Provisions pour pertes de change \N 151500 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 66 Provisions pour pertes sur contrats \N 151600 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 67 Autres provisions pour risques \N 151800 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 69 Provisions pour restructurations \N 154000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 70 Provisions pour impôts \N 155000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 71 Provisions pour renouvellement des immobilisations (entreprises concessionnaires) \N 156000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 72 Provisions pour charges à répartir sur plusieurs exercices - Gros entretien ou grandes révisions \N 157200 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 73 Provisions pour remises en état \N 158100 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 76 Emprunts auprès des établissements de crédit \N 164000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 77 Dépôts \N 165100 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 78 Cautionnements \N 165500 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 79 Participation des salariés aux résultats - Comptes bloqués \N 166100 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 80 Participation des salariés aux résultats - Fonds de participation \N 166200 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 81 Emprunts et dettes assortis de conditions particulières - Emissions de titres participatifs \N 167100 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 82 Emprunts et dettes assortis de conditions particulières - Avances conditionnées de l'État \N 167400 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 83 Emprunts et dettes assortis de conditions particulières - Emprunts participatifs \N 167500 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 84 Autres emprunts et dettes assimilées - Autres emprunts \N 168100 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 85 Autres emprunts et dettes assimilées - Rentes viagères capitalisées \N 168500 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 86 Autres emprunts et dettes assimilées - Autres dettes \N 168700 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 74 Emprunts obligataires convertibles \N 161000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 63 Provisions pour pertes sur marchés à terme \N 151300 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 68 Provisions pour pensions et obligations similaires \N 153000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 75 Autres emprunts obligataires \N 163000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 87 Intérêts courus sur emprunts obligataires convertibles \N 168810 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 88 Intérêts courus sur autres emprunts obligataires \N 168830 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 89 Intérêts courus sur emprunts auprès des établissements de crédit \N 168840 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 90 Intérêts courus sur dépôts et cautionnements reçus \N 168850 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 91 Intérêts courus sur participation des salariés aux résultats \N 168860 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 92 Intérêts courus sur emprunts et dettes assortis de conditions particulières \N 168870 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 93 Intérêts courus sur autres emprunts et dettes assimilées \N 168880 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 94 Primes de remboursement des obligations \N 169000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 96 Dettes rattachées à des participations (hors groupe) \N 174000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 97 Dettes rattachées à des sociétés en participation - Principal \N 178100 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 98 Dettes rattachées à des sociétés en participation - Intérêts courus \N 178800 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 100 Biens et prestations de services échangés entre établissements (charges) \N 186000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 101 Biens et prestations de services échangés entre établissements (produits) \N 187000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 102 Comptes de liaison des sociétés en participation \N 188000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 103 Immobilisations incorporelles - Frais d'établissement - Frais de constitution \N 201100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 104 Immobilisations incorporelles - Frais d'établissement - Frais de prospection \N 201210 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 105 Immobilisations incorporelles - Frais d'établissement - Frais de publicité \N 201220 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 108 Immobilisations incorporelles - Concessions et droits similaires, brevets, licences, marques, procédés, logiciels, droits et valeurs similaires \N 205000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 109 Immobilisations incorporelles - Droit au bail \N 206000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 110 Immobilisations incorporelles - Fonds commercial \N 207000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 111 Autres immobilisations incorporelles \N 208000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 95 Dettes rattachées à des participations (groupe) \N 171000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 237 Études en cours E 1 \N 341100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 99 Comptes de liaison des établissements \N 181000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 106 Immobilisations incorporelles - Frais d'augmentation de capital et d'opérations diverses (fusions, scissions, transformations) \N 201300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 107 Immobilisations incorporelles - Frais de recherche et de développement \N 203000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 112 Immobilisations corporelles - Terrains nus \N 211100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 113 Immobilisations corporelles - Terrains aménagés \N 211200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 115 Immobilisations corporelles - Carrières \N 211410 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 116 Immobilisations corporelles - Terrains bâtis - Ensembles immobiliers industriels \N 211510 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 117 Immobilisations corporelles - Terrains bâtis - Ensembles immobiliers administratifs et commerciaux \N 211550 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 118 Immobilisations corporelles - Terrains bâtis affectés aux opérations professionnelles \N 211581 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 119 Immobilisations corporelles - Terrains bâtis affectés aux opérations non professionnelles \N 211588 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 120 Immobilisations corporelles - Compte d'ordre sur immobilisations \N 211600 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 121 Immobilisations corporelles - Agencements et aménagements de terrains (même ventilation que celle du compte 211) \N 212000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 122 Immobilisations corporelles - Bâtiments - Ensembles immobiliers industriels \N 213110 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 123 Immobilisations corporelles - Bâtiments - Ensembles immobiliers administratifs et commerciaux \N 213150 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 124 Immobilisations corporelles - Bâtiments affectés aux opérations professionnelles \N 213181 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 125 Immobilisations corporelles - Bâtiments affectés aux opérations non professionnelles \N 213188 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 126 Immobilisations corporelles - Installations générales, agencements, aménagements des constructions (même ventilation que celle du compte 2131) \N 213500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 127 Immobilisations corporelles - Ouvrages d'infrastructure - Voies de terre \N 213810 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 128 Immobilisations corporelles - Ouvrages d'infrastructure - Voies de fer \N 213820 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 129 Immobilisations corporelles - Ouvrages d'infrastructure - Voies d'eau \N 213830 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 130 Immobilisations corporelles - Ouvrages d'infrastructure - Barrages \N 213840 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 131 Immobilisations corporelles - Ouvrages d'infrastructure - Pistes d'aérodromes \N 213850 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 132 Immobilisations corporelles - Constructions sur sol d'autrui (même ventilation que celle du compte 213) \N 214000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 133 Immobilisations corporelles - Installations complexes spécialisées sur sol propre \N 215110 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 134 Immobilisations corporelles - Installations complexes spécialisées sur sol d'autrui \N 215140 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 114 Immobilisations corporelles - Sous-sols et sur-sols \N 211300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 135 Immobilisations corporelles - Installations à caractère spécifique sur sol propre \N 215310 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 136 Immobilisations corporelles - Installations à caractère spécifique sur sol d'autrui \N 215340 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 137 Immobilisations corporelles - Matériels industriels \N 215400 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 138 Immobilisations corporelles - Outillage industriel \N 215500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 139 Immobilisations corporelles - Agencements et aménagements des matériels et outillage industriels \N 215700 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 140 Immobilisations corporelles - Installations générales agencements aménagements divers \N 218100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 141 Immobilisations corporelles - Matériel de transport \N 218200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 143 Immobilisations corporelles - Mobilier \N 218400 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 144 Immobilisations corporelles - Cheptel \N 218500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 145 Immobilisations corporelles - Emballages récupérables \N 218600 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 146 Immobilisations mises en concession \N 220000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 147 Immobilisations corporelles en cours - Terrains \N 231200 f 5 other \N f Pas d'amortissement sur les terrains 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 149 Immobilisations corporelles en cours - Installations techniques matériel et outillage industriels \N 231500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 150 Autres immobilisations corporelles en cours \N 231800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 151 Immobilisations incorporelles en cours \N 232000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 152 Avances et acomptes versés sur commandes d'immobilisations incorporelles \N 237000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 153 Avances et acomptes versés sur commandes d'immobilisations corporelles - Terrains \N 238200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 155 Avances et acomptes versés sur commandes d'immobilisations corporelles - Installations techniques matériel et outillage industriels \N 238500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 156 Avances et acomptes versés sur commandes d'immobilisations corporelles - Autres immobilisations corporelles \N 238800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 157 Parts dans des entreprises liées et créances sur des entreprises liées \N 250000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 158 Titres de participation - Actions \N 261100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 159 Autres titres de participation \N 261800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 142 Immobilisations corporelles - Matériel de bureau et matériel informatique \N 218300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 148 Immobilisations corporelles en cours - Constructions \N 231300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 154 Avances et acomptes versés sur commandes d'immobilisations corporelles - Constructions \N 238300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 160 Titres évalués par équivalence \N 262000 f 5 other \N f Pas d'amortissement sur les titres évalués par équivalence 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 161 Autres formes de participation \N 266000 f 5 other \N f Pas d'amortissement sur les titres évalués par équivalence 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 162 Créances rattachées à des participations (groupe) \N 267100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 163 Créances rattachées à des participations (hors groupe) \N 267400 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 164 Versements représentatifs d'apports non capitalisés (appel de fonds) \N 267500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 166 Autres créances rattachées à des participations \N 267700 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 167 Créances rattachées à des participations - Intérêts courus \N 267800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 168 Créances rattachées à des sociétés en participation - Principal \N 268100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 169 Créances rattachées à des sociétés en participation - Intérêts courus \N 268800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 170 Versements restant à effectuer sur titres de participation non libérés \N 269000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 171 Titres immobilisés autres que les titres immobilisés de l'activité de portefeuille - Actions \N 271100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 172 Titres immobilisés autres que les titres immobilisés de l'activité de portefeuille - Autres titres \N 271800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 173 Titres immobilisés - Obligations \N 272100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 174 Titres immobilisés - Bons \N 272200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 176 Prêts participatifs \N 274100 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 177 Prêts aux associés \N 274200 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 179 Autres prêts \N 274800 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 180 Dépôts \N 275100 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 181 Cautionnements \N 275500 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 182 Autres créances immobilisées - Créances diverses \N 276100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 183 Autres créances immobilisées - Intérêts courus sur titres immobilisés (droits de créance) \N 276820 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 184 Autres créances immobilisées - Intérêts courus sur prêts \N 276840 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 185 Autres créances immobilisées - Intérêts courus sur dépôts et cautionnements \N 276850 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 186 Autres créances immobilisées - Intérêts courus sur créances diverses \N 276880 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 187 Actions propres ou parts propres \N 277100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 175 Titres immobilisés de l'activité de portefeuille \N 273000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 178 Prêts au personnel \N 274300 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 165 Avances consolidables \N 267600 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 188 Actions propres ou parts propres en voie d'annulation \N 277200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 189 Versements restant à effectuer sur titres immobilisés non libérés \N 279000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 190 Amortissements des immobilisations incorporelles - Frais d'établissement (même ventilation que celle du compte 201) \N 280100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 192 Amortissements des immobilisations incorporelles - Concessions et droits similaires, brevets, licences, logiciels, droits et valeurs similaires \N 280500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 193 Amortissements des immobilisations incorporelles - Fonds commercial \N 280700 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 194 Amortissements des autres immobilisations incorporelles \N 280800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 195 Amortissements des immobilisations corporelles - Terrains de gisement \N 281100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 196 Amortissements des immobilisations corporelles - Agencements aménagements de terrains (même ventilation que celle du compte 212) \N 281200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 198 Amortissements des immobilisations corporelles - Constructions sur sol d'autrui (même ventilation que celle du compte 214) \N 281400 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 199 Amortissements des immobilisations corporelles - Installations matériel et outillage industriels (même ventilation que celle du compte 215) \N 281500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 200 Amortissements des autres immobilisations corporelles (même ventilation que celle du compte 218) \N 281800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 201 Amortissements des immobilisations mises en concession \N 282000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 202 Dépréciations des immobilisations incorporelles - Marques, procédés, droits et valeurs similaires \N 290500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 203 Dépréciations des immobilisations incorporelles - Droit au bail \N 290600 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 204 Dépréciations des immobilisations incorporelles - Fonds commercial \N 290700 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 205 Dépréciations des autres immobilisations incorporelles \N 290800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 206 Dépréciations des immobilisations corporelles - Terrains (autres que terrains de gisement) \N 291100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 207 Dépréciations des immobilisations mises en concession \N 292000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 208 Dépréciations des immobilisations corporelles en cours \N 293100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 209 Dépréciations des immobilisations incorporelles en cours \N 293200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 191 Amortissements des immobilisations incorporelles - Frais de recherche et de développement \N 280300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 197 Amortissements des immobilisations corporelles - Constructions (même ventilation que celle du compte 213) \N 281300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 210 Provisions pour dépréciation des titres de participation \N 296100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 211 Provisions pour dépréciation des autres formes de participation \N 296600 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 212 Provisions pour dépréciation des créances rattachées à des participations (même ventilation que celle du compte 267) \N 296700 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 213 Provisions pour dépréciation des créances rattachées à des sociétés en participation (même ventilation que celle du compte 268) \N 296800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 214 Provisions pour dépréciation des titres immobilisés autres que les titres immobilisés de l'activité de portefeuille - droit de propriété (ventilation : 271) \N 297100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 215 Provisions pour dépréciation des titres immobilisés - droit de créance (même ventilation que celle du compte 272) \N 297200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 217 Provisions pour dépréciation des prêts (même ventilation que celle du compte 274) \N 297400 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 218 Provisions pour dépréciation des dépôts et cautionnements versés (même ventilation que celle du compte 275) \N 297500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 221 Matières premières (ou groupe) B \N 312000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 222 Fournitures A, B, C, .. \N 317000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 223 Matières consommables (ou groupe) C \N 321100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 224 Matières consommables (ou groupe) D \N 321200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 225 Combustibles \N 322100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 226 Produits d'entretien \N 322200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 228 Fournitures de magasin \N 322400 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 229 Fournitures de bureau \N 322500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 230 Emballages perdus \N 326100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 231 Emballages récupérables non identifiables \N 326500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 232 Emballages à usage mixte \N 326700 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 233 Produit en cours P 1 \N 331100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 234 Produit en cours P 2 \N 331200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 235 Travaux en cours T 1 \N 335100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 236 Travaux en cours T 2 \N 335200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 220 Matières premières (ou groupe) A \N 311000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 216 Provisions pour dépréciation des titres immobilisés de l'activité de portefeuille \N 297300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 227 Fournitures d'atelier et d usine \N 322300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 219 Provisions pour dépréciation des autres créances immobilisées (même ventilation que celle du compte 276) \N 297600 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 238 Études en cours E 2 \N 341200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 239 Prestations de services en cours S 1 \N 345100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 240 Prestations de services en cours S 2 \N 345200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 241 Stocks produits intermédiaires (ou groupe) A \N 351100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 242 Stocks produits intermédiaires (ou groupe) B \N 351200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 243 Stocks produits finis (ou groupe) A \N 355100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 244 Stocks produits finis (ou groupe) B \N 355200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 245 Stocks produits résiduels - Déchets \N 358100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 246 Stocks produits résiduels - Rebuts \N 358500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 247 Stocks produits résiduels - Matières de récupération \N 358600 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 248 Stocks provenant d'immobilisations \N 360000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 250 Stocks de marchandises (ou groupe) B \N 372000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 251 Stocks en voie d'acheminement \N 380000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 252 Provisions pour dépréciation des matières premières (ou groupe) A \N 391100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 253 Provisions pour dépréciation des matières premières (ou groupe) B \N 391200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 254 Provisions pour dépréciation des fournitures A, B, C, .. \N 391700 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 255 Provisions pour dépréciation des matières consommables (même ventilation que celle du compte 321) \N 392100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 256 Provisions pour dépréciation des fournitures consommables (même ventilation que celle du compte 322) \N 392200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 257 Provisions pour dépréciation des emballages (même ventilation que celle du compte 326) \N 392600 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 258 Provisions pour dépréciation des produits en cours (même ventilation que celle du compte 331) \N 393100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 259 Provisions pour dépréciation des travaux en cours (même ventilation que celle du compte 335) \N 393500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 260 Provisions pour dépréciation des études en cours (même ventilation que celle du compte 341) \N 394100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 261 Provisions pour dépréciation des prestations de services en cours (même ventilation que celle du compte 345) \N 394500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 262 Provisions pour dépréciation des produits intermédiaires (même ventilation que celle du compte 351) \N 395100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 263 Provisions pour dépréciation des produits finis (même ventilation que celle du compte 355) \N 395500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 249 Stocks de marchandises (ou groupe) A \N 371000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 264 Provisions pour dépréciation des stocks de marchandises (ou groupe) A \N 397100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 265 Provisions pour dépréciation des stocks de marchandises (ou groupe) B \N 397200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 266 Fournisseurs et comptes rattachés \N 400000 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 267 Fournisseurs - Achats de biens et prestations de services \N 401100 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 268 Fournisseurs - Retenues de garantie \N 401700 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 270 Fournisseurs - Achats d'immobilisations \N 404100 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 271 Fournisseurs d'immobilisations - Retenues de garantie \N 404700 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 272 Fournisseurs d'immobilisations - Effets à payer \N 405000 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 273 Factures non parvenues - Fournisseurs \N 408100 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 274 Factures non parvenues - Fournisseurs d'immobilisations \N 408400 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 275 Factures non parvenues - Fournisseurs - Intérêts courus \N 408800 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 276 Fournisseurs débiteurs - Créances pour emballages et matériel à rendre \N 409600 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 277 Fournisseurs débiteurs - Autres avoirs des fournisseurs d'exploitation \N 409710 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 278 Fournisseurs débiteurs - Autres avoirs des fournisseurs d'immobilisations \N 409740 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 279 Fournisseurs débiteurs - Rabais, remises, ristournes à obtenir et autres avoirs non encore reçus \N 409800 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 281 Clients - Ventes de biens ou de prestations de services \N 411100 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 282 Clients - Retenues de garantie \N 411700 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 284 Clients douteux ou litigieux \N 416000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 285 Clients - Factures à établir \N 418100 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 286 Clients - Intérêts courus non encore facturés \N 418800 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 287 Clients créditeurs - Avances et acomptes reçus sur commandes \N 419100 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 288 Clients créditeurs - Dettes pour emballages et matériels consignés \N 419600 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 289 Clients créditeurs - Autres avoirs \N 419700 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 290 Clients créditeurs - Rabais, remises, ristournes à accorder et autres avoirs à établir \N 419800 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 280 Clients et comptes rattachés \N 410000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 269 Fournisseurs - Effets à payer \N 403000 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 283 Clients - Effets à recevoir \N 413000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 292 Comités d'entreprise, d'établissement \N 422000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 293 Participation des salariés aux résultats - Réserve spéciale \N 424600 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 294 Participation des salariés aux résultats - Comptes courants \N 424800 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 295 Personnel - Avances et acomptes \N 425000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 296 Personnel - Dépôts \N 426000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 297 Personnel - Oppositions \N 427000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 298 Personnel - Dettes provisionnées pour congés à payer \N 428200 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 299 Personnel - Dettes provisionnées pour participation des salariés aux résultats \N 428400 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 300 Personnel - Autres charges à payer \N 428600 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 301 Personnel - Produits à recevoir \N 428700 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 303 Autres organismes sociaux \N 437000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 304 Charges sociales sur congés à payer \N 438200 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 305 Organismes sociaux - Autres charges à payer \N 438600 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 306 Organismes sociaux - Produits à recevoir \N 438700 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 307 État - Subventions à recevoir - Subventions d'investissement \N 441100 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 308 État - Subventions à recevoir - Subventions d'exploitation \N 441700 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 309 État - Subventions à recevoir - Subventions d'équilibre \N 441800 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 310 État - Subventions à recevoir - Avances sur subventions \N 441900 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 311 État - Impôts et taxes recouvrables sur des tiers - Obligataires \N 442400 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 312 État - Impôts et taxes recouvrables sur des tiers - Associés \N 442500 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 313 Créances sur l'État résultant de la suppression de la règle du décalage d'un mois en matière de TVA \N 443100 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 314 État - Intérêts courus sur créances figurant au compte 4431 \N 443800 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 315 État - Impôts sur les bénéfices \N 444000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 316 TVA due intracommunautaire (Taux Normal) \N 445201 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 317 TVA due intracommunautaire (Taux Intermédiaire) \N 445202 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 318 TVA due intracommunautaire (Autre taux) \N 445203 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 319 TVA due imports \N 445204 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 291 Personnel - Rémunérations dues \N 421000 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 302 Sécurité Sociale \N 431000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 320 TVA à décaisser \N 445510 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 321 Taxes assimilées à la TVA \N 445580 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 322 TVA déductible sur immobilisations \N 445620 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 323 TVA déductible transférée par d'autres entreprises \N 445630 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 324 TVA déductible sur autres biens et services \N 445660 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 325 TVA déductible intracommunautaire \N 445662 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 326 TVA déductible imports \N 445663 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 327 Crédit de TVA à reporter \N 445670 f 5 other \N t Si le remboursement n'a pas été demandé 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 328 Taxes déductibles assimilées à la TVA \N 445680 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 329 TVA collectée (Taux Normal) \N 445711 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 330 TVA collectée (Taux Intermédiaire) \N 445712 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 331 TVA collectée (Autre taux) \N 445713 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 332 Taxes collectées assimilées à la TVA \N 445780 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 333 Taxes sur le chiffre d'affaires à régulariser ou en attente \N 445800 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 334 Acomptes - Régime simplifié d'imposition \N 445810 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 335 Acomptes - Régime du forfait \N 445820 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 336 Remboursement de taxes sur le chiffre d'affaires demandé \N 445830 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 337 TVA récupérée d'avance \N 445840 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 338 Taxes sur le chiffre d'affaires sur factures non parvenues \N 445860 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 339 Taxes sur le chiffre d'affaires sur factures à établir \N 445870 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 340 Obligations cautionnées \N 446000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 341 Autres impôts, taxes et versements assimilés \N 447000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 342 État - Charges fiscales sur congés à payer \N 448200 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 343 État - Charges à payer \N 448600 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 344 État - Produits à recevoir \N 448700 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 345 Quotas d'émission à restituer à l'État \N 449000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 347 Associés - Comptes courants - Principal \N 455100 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 348 Associés - Comptes courants - Intérêts courus \N 455800 f 2 payable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 349 Associés - Comptes d'apport en société - Apports en nature \N 456110 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 346 Groupe \N 451000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 350 Associés - Comptes d'apport en société - Apports en numéraire \N 456150 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 351 Actionnaires - Capital souscrit et appelé, non versé \N 456210 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 352 Associés - Capital appelé, non versé \N 456250 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 354 Associés - Versements anticipés \N 456400 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 355 Actionnaires défaillants \N 456600 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 356 Associés - Capital à rembourser \N 456700 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 357 Associés - Dividendes à payer \N 457000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 358 Associés - Opérations faites en commun et en GIE - Opérations courantes \N 458100 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 359 Associés - Opérations faites en commun et en GIE - Intérêts courus \N 458800 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 360 Créances sur cessions d'immobilisations \N 462000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 361 Dettes sur acquisitions de valeurs mobilières de placement \N 464000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 362 Créances sur cessions de valeurs mobilières de placement \N 465000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 363 Autres comptes débiteurs ou créditeurs \N 467000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 364 Charges à payer \N 468600 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 365 Produits à recevoir \N 468700 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 367 Différence de conversion - Actif - Diminution des créances \N 476100 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 368 Différence de conversion - Actif - Augmentation des dettes \N 476200 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 369 Différence de conversion - Actif - Différences compensées par couverture de change \N 476800 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 370 Différences de conversion - Passif - Augmentation des créances \N 477100 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 371 Différences de conversion - Passif - Diminution des dettes \N 477200 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 372 Différences de conversion - Passif - Différences compensées par couverture de change \N 477800 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 373 Autres comptes transitoires \N 478000 f 9 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 374 Charges à répartir sur plusieurs exercices - Frais d'émission des emprunts \N 481600 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 375 Charges constatées d'avance \N 486000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 376 Produits constatés d'avance \N 487000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 377 Comptes de répartition périodique des charges \N 488600 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 366 Compte d'attente \N 471000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 353 Associés - Versements reçus sur augmentation de capital \N 456300 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 378 Comptes de répartition périodique des produits \N 488700 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 379 Quotas d'émission alloués par l'État \N 489000 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 381 Provisions pour dépréciation des comptes du groupe \N 495100 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 382 Provisions pour dépréciation des comptes courants des associés \N 495500 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 383 Provisions pour dépréciation des opérations faites en commun et en GIE \N 495800 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 384 Provisions pour dépréciation des créances sur cessions d'immobilisations \N 496200 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 385 Provisions pour dépréciation des créances sur cessions de valeurs mobilières de placement \N 496500 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 386 Provisions pour dépréciation - Autres comptes débiteurs \N 496700 f 1 receivable \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 388 Valeurs mobilières de placement - Actions propres \N 502000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 389 Valeurs mobilières de placement - Titres cotés \N 503100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 390 Valeurs mobilières de placement - Titres non cotés \N 503500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 391 Valeurs mobilières de placement - Autres titres conférant un droit de propriété \N 504000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 392 Obligations et bons émis par la société et rachetés par elle \N 505000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 393 Obligations cotés \N 506100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 394 Obligations non cotés \N 506500 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 395 Bons du Trésor et bons de caisse à court terme \N 507000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 396 Autres valeurs mobilières de placement \N 508100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 397 Bons de souscription \N 508200 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 398 Intérêts courus sur obligations, bons et valeurs assimilées \N 508800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 399 Versements restant à effectuer sur valeurs mobilières de placement non libérées \N 509000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 400 Coupons échus à l'encaissement \N 511100 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 401 Chèques à encaisser \N 511200 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 403 Effets à l'escompte \N 511400 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 404 Banques - Comptes en devises \N 512400 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 405 Chèques postaux \N 514000 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 380 Provisions pour dépréciation des comptes de clients \N 491000 f 9 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 387 Valeurs mobilières de placement - Parts dans entreprises liées \N 501000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 402 Effets à l'encaissement \N 511300 f 5 other \N t \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 406 Caisses du Trésor et des établissements publics \N 515000 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 407 Sociétés de bourse \N 516000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 408 Autres organismes financiers \N 517000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 409 Intérêts courus à payer \N 518100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 410 Intérêts courus à recevoir \N 518800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 411 Concours bancaires courants - Crédit de mobilisation de créances commerciales (CMCC) \N 519100 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 413 Concours bancaires courants - Intérêts courus sur concours bancaires courants \N 519800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 414 Instruments de trésorerie \N 520000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 415 Caisse en monnaie nationale \N 531100 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 416 Caisse en devises \N 531400 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 417 Caisse succursale (ou usine) A \N 532000 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 419 Régies d'avances et accréditifs \N 540000 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 421 Provisions pour dépréciation des autres titres conférant un droit de propriété \N 590400 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 422 Provisions pour dépréciation des obligations \N 590600 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 423 Provisions pour dépréciation des autres valeurs mobilières de placement et créances assimilées (provisions) \N 590800 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 424 Achats stockés - Matières premières (ou groupe) A \N 601100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 425 Achats stockés - matières premières (ou groupe) B \N 601200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 426 Achats stockés - Fournitures A, B, C, .. \N 601700 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 427 Achats stockés - Matières consommables (ou groupe) C \N 602110 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 428 Achats stockés - Matières consommables (ou groupe) D \N 602120 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 429 Achats stockés - Combustibles \N 602210 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 430 Achats stockés - Produits d'entretien \N 602220 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 431 Achats stockés - Fournitures d'atelier et d'usine \N 602230 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 432 Achats stockés - Fournitures de magasin \N 602240 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 433 Achats stockés - Fournitures de bureau \N 602250 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 434 Achats stockés - Emballages perdus \N 602610 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 412 Concours bancaires courants - Mobilisation de créances nées à l'étranger \N 519300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 418 Caisse succursale (ou usine) B \N 533000 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 420 Provisions pour dépréciation des actions \N 590300 f 5 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 435 Achats stockés - Emballages récupérables non identifiables \N 602650 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 436 Achats stockés - Emballages à usage mixte \N 602670 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 437 Variation des stocks de matières premières (et fournitures) \N 603100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 438 Variation des stocks des autres approvisionnements \N 603200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 439 Variation des stocks de marchandises \N 603700 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 440 Achats d'études et prestations de services \N 604000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 441 Achats de matériel équipements et travaux \N 605000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 442 Fournitures non stockables (eau, énergie...) \N 606100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 444 Fournitures administratives \N 606400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 445 Achats autres matières et fournitures \N 606800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 446 Achats de marchandises (ou groupe) A \N 607100 f 16 other \N f Pour achats France 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 447 Achats de marchandises (ou groupe) B \N 607200 f 16 other \N f Pour déclaration TVA intracommunautaire 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 448 Frais accessoires incorporés aux achats \N 608000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 449 Rabais, remises et ristournes obtenus sur achats de matières premières (et fournitures) \N 609100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 450 Rabais, remises et ristournes obtenus sur achats d'autres approvisionnements stockés \N 609200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 451 Rabais, remises et ristournes obtenus sur achats d'études et prestations de services \N 609400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 452 Rabais, remises et ristournes obtenus sur achats de matériel, équipements et travaux \N 609500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 453 Rabais, remises et ristournes obtenus sur achats d'approvisionnements non stockés \N 609600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 454 Rabais, remises et ristournes obtenus sur achats de marchandises \N 609700 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 455 Rabais, remises et ristournes non affectés \N 609800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 457 Redevances de crédit-bail mobilier \N 612200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 458 Redevances de crédit-bail immobilier \N 612500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 459 Locations immobilières \N 613200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 460 Locations mobilières \N 613500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 461 Locations malis sur emballages \N 613600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 462 Charges locatives et de copropriété \N 614000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 456 Sous-traitance générale \N 611000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 443 Fournitures d'entretien et de petit équipement \N 606300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 463 Entretien et réparations sur biens immobiliers \N 615200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 464 Entretien et réparations sur biens mobiliers \N 615500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 465 Maintenance \N 615600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 466 Assurance multirisques \N 616100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 467 Assurance obligatoire dommage construction \N 616200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 468 Assurance transport sur achats \N 616360 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 469 Assurance transport sur ventes \N 616370 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 470 Assurance transport sur autres biens \N 616380 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 471 Assurance risques d'exploitation \N 616400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 472 Assurance insolvabilité clients \N 616500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 473 Études et recherches \N 617000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 474 Documentation générale \N 618100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 476 Frais de colloques, séminaires, conférences \N 618500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 477 Rabais, remises et ristournes obtenus sur services extérieurs \N 619000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 478 Personnel intérimaire \N 621100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 479 Personnel détaché ou prêté à l'entreprise \N 621400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 480 Commissions et courtages sur achats \N 622100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 481 Commissions et courtages sur ventes \N 622200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 482 Rémunérations des transitaires \N 622400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 483 Rémunérations d'affacturage \N 622500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 484 Honoraires \N 622600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 485 Frais d'actes et de contentieux \N 622700 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 486 Rémunérations d'intermédiaires et honoraires - Divers \N 622800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 487 Annonces et insertions \N 623100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 488 Échantillons \N 623200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 490 Cadeaux à la clientèle \N 623400 f 16 other \N f Attention déclaration DAS fin d'année 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 491 Primes \N 623500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 492 Catalogues et imprimés \N 623600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 493 Publications \N 623700 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 494 Publicité, publications, relations publiques - Divers (pourboires, dons courants...) \N 623800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 475 Documentation technique \N 618300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 489 Foires et expositions \N 623300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 495 Transports sur achats \N 624100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 496 Transports sur ventes \N 624200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 498 Transports administratifs \N 624400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 499 Transports collectifs du personnel \N 624700 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 500 Transports divers \N 624800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 501 Voyages et déplacements \N 625100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 502 Frais de déménagement \N 625500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 503 Missions \N 625600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 504 Réceptions \N 625700 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 505 Frais postaux et frais de télécommunications \N 626000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 506 Frais sur titres (achat, vente, garde) \N 627100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 507 Commissions et frais sur émission d'emprunts \N 627200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 508 Frais sur effets \N 627500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 510 Autres frais et commissions sur prestations de services \N 627800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 511 Concours divers (cotisations...) \N 628100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 512 Frais de recrutement de personnel \N 628400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 513 Rabais, remises et ristournes obtenus sur autres services extérieurs \N 629000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 514 Taxe sur les salaires \N 631100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 515 Taxe d'apprentissage \N 631200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 517 Cotisation pour défaut d'investissement obligatoire dans la construction \N 631400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 518 Autres impôts, taxes et versements assimilés sur rémunérations (administrations des impôts) \N 631800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 519 Versement de transport \N 633100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 520 Allocation logement \N 633200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 522 Participation des employeurs à l'effort de construction \N 633400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 523 Versements libératoires ouvrant droit à l'exonération de la taxe d'apprentissage \N 633500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 524 Autres impôts, taxes et versements assimilés sur rémunérations (autres organismes) \N 633800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 497 Transports entre établissements ou chantiers \N 624300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 516 Participation des employeurs à la formation professionnelle continue \N 631300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 521 Participation des employeurs à la formation professionnelle continue \N 633300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 509 Location de coffres \N 627600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 525 Cotisation foncière des entreprises \N 635111 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 526 Cotisation sur la valeur ajoutée des entreprises \N 635112 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 527 Taxes foncières \N 635120 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 528 Autres impôts locaux \N 635130 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 529 Taxe sur les véhicules des sociétés \N 635140 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 530 Taxes sur le chiffre d'affaires non récupérables \N 635200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 532 Droits de mutation \N 635410 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 533 Autres droits \N 635800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 534 Contribution sociale de solidarité à la charge des sociétés \N 637100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 535 Taxes perçues par les organismes publics internationaux \N 637200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 536 Impôts et taxes exigibles à l'étranger \N 637400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 537 Taxes diverses (autres organismes) \N 637800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 538 Salaires et appointements \N 641100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 539 Congés payés \N 641200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 541 Indemnités et avantages divers \N 641400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 542 Supplément familial \N 641500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 543 Rémunération du travail de l'exploitant \N 644000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 544 Cotisations à l'URSSAF \N 645100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 545 Cotisations aux mutuelles \N 645200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 547 Cotisations aux ASSEDIC \N 645400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 548 Cotisations aux autres organismes sociaux \N 645800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 549 Cotisations sociales personnelles de l'exploitant \N 646000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 550 Prestations directes \N 647100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 551 Versements aux comités d'entreprise et d'établissement \N 647200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 553 Versements aux autres oeuvres sociales \N 647400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 554 Médecine du travail, pharmacie \N 647500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 555 Autres charges de personnel \N 648000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 556 Crédit d’Impôt Compétitivité Emploi (CICE) \N 649000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 531 Impôts indirects \N 635300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 540 Primes et gratifications \N 641300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 546 Cotisations aux caisses de retraites \N 645300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 552 Versements aux comités d'hygiène et de sécurité \N 647300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 557 Redevances pour concessions brevets, licences, marques, procédés, logiciels \N 651100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 558 Droits d'auteur et de reproduction \N 651600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 559 Autres droits et valeurs similaires \N 651800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 561 Créances de l'exercice \N 654100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 562 Créances des exercices antérieurs \N 654400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 563 Quote-part de bénéfice transférée (comptabilité du gérant) \N 655100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 564 Quote-part de perte supportée (comptabilité des associés non gérants) \N 655500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 565 Charges diverses de gestion courante \N 658000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 566 Intérêts des emprunts et dettes assimilées \N 661160 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 567 Intérêts des dettes rattachées à des participations \N 661170 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 568 Intérêts des comptes courants et des dépôts créditeurs \N 661500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 569 Intérêts bancaires et sur opérations de financement (escompte, ...) \N 661600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 570 Intérêts des obligations cautionnées \N 661700 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 571 Intérêts des dettes commerciales \N 661810 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 572 Intérêts des dettes diverses \N 661880 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 573 Pertes sur créances liées à des participations \N 664000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 574 Escomptes accordés \N 665000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 575 Pertes de change \N 666000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 576 Charges nettes sur cessions de valeurs mobilières de placement \N 667000 f 16 other \N f (contrepartie 767) 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 577 Autres charges financières \N 668000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 578 Charges exceptionnelles - Pénalités sur marchés (et dédits payés sur achats et ventes) \N 671100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 579 Charges exceptionnelles - Pénalités, amendes fiscales et pénales \N 671200 f 16 other \N f PV code de la route non déductibles 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 581 Charges exceptionnelles - Créances devenues irrécouvrables dans l'exercice \N 671400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 582 Charges exceptionnelles - Subventions accordées \N 671500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 583 Charges exceptionnelles - Rappels d'impôts (autres qu'impôts sur les bénéfices) \N 671700 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 584 Autres charges exceptionnelles sur opération de gestion \N 671800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 560 Jetons de présence \N 653000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 580 Charges exceptionnelles - Dons, libéralités \N 671300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 585 Charges exceptionnelles sur exercices antérieurs (en cours d'exercice seulement) \N 672000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 586 Valeurs comptables des éléments d'actif cédés - Immobilisations incorporelles \N 675100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 587 Valeurs comptables des éléments d'actif cédés - Immobilisations corporelles \N 675200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 588 Valeurs comptables des éléments d'actif cédés - Immobilisations financières \N 675600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 589 Valeurs comptables des éléments d'actif cédés - Autres éléments d'actif \N 675800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 590 Charges exceptionnelles - Malis provenant de clauses d'indexation \N 678100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 591 Charges exceptionnelles - Lots \N 678200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 593 Charges exceptionnelles diverses \N 678800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 594 Dotations aux amortissements sur immobilisations incorporelles \N 681110 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 595 Dotations aux amortissements sur immobilisations corporelles \N 681120 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 596 Dotations aux amortissements des charges d'exploitation à répartir \N 681200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 597 Dotations aux provisions pour risques et charges d'exploitation \N 681500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 598 Dotations aux dépréciations des immobilisations incorporelles \N 681610 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 599 Dotations aux dépréciations des immobilisations corporelles \N 681620 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 600 Dotations aux dépréciations des stocks et en-cours \N 681730 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 601 Dotations aux dépréciations des créances \N 681740 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 602 Dotations aux amortissements des primes de remboursement des obligations \N 686100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 603 Dotations aux provisions pour risques et charges financiers \N 686500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 604 Dotations aux dépréciations des immobilisations financières \N 686620 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 605 Dotations aux dépréciations des valeurs mobilières de placement \N 686650 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 606 Autres dotations aux amortissements, dépréciations et provisions - Charges financières \N 686800 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 607 Dotations aux amortissements exceptionnels des immobilisations \N 687100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 608 Dotations aux provisions réglementées exceptionnelles (immobilisations) - Amortissements dérogatoires \N 687250 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 592 Charges exceptionnelles - Malis provenant du rachat par l'entreprise d'actions et obligations émises par elle-même \N 678300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 609 Dotations aux provisions réglementées exceptionnelles (stocks) \N 687300 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 610 Dotations aux autres provisions réglementées exceptionnelles \N 687400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 611 Dotations aux provisions exceptionnelles \N 687500 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 614 Impôts sur les bénéfices dus en France \N 695100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 615 Contribution additionnelle à l'impôt sur les bénéfices \N 695200 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 616 Impôts sur les bénéfices dus à l'étranger \N 695400 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 617 Supplément d'impôt sur les sociétés lié aux distributions \N 696000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 618 Imposition forfaitaire annuelle des sociétés \N 697000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 619 Intégration fiscale - Charges \N 698100 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 620 Intégration fiscale - Produits \N 698900 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 621 Produits, Reports en arrière des déficits \N 699000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 622 Ventes de produits finis (ou groupe) A \N 701100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 623 Ventes de produits finis (ou groupe) B \N 701200 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 624 Ventes de produits intermédiaires \N 702000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 626 Ventes de travaux de catégorie (ou activité) A \N 704100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 627 Ventes de travaux de catégorie (ou activité) B \N 704200 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 628 Ventes d'études \N 705000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 629 Ventes de prestations de services \N 706000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 630 Ventes de marchandises (ou groupe) A \N 707100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 631 Ventes de marchandises (ou groupe) B \N 707200 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 633 Produits des services exploités dans l'intérêt du personnel \N 708100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 634 Commissions et courtages \N 708200 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 636 Mise à disposition de personnel facturée \N 708400 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 637 Ports et frais accessoires facturés \N 708500 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 638 Bonis sur reprises d'emballages consignés \N 708600 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 639 Bonifications obtenues des clients et primes sur ventes \N 708700 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 613 Participation des salariés aux résultats \N 691000 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 625 Ventes de produits résiduels \N 703000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 632 Ventes de marchandises à l'exportation \N 707300 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 635 Locations diverses \N 708300 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 612 Dotations aux dépréciations exceptionnelles \N 687600 f 16 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 640 Autres produits d'activités annexes (cessions d'approvisionnements...) \N 708800 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 641 Rabais, remises et ristournes sur ventes de produits finis \N 709100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 642 Rabais, remises et ristournes sur ventes de produits intermédiaires \N 709200 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 643 Rabais, remises et ristournes sur travaux \N 709400 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 644 Rabais, remises et ristournes sur études \N 709500 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 645 Rabais, remises et ristournes sur prestations de services \N 709600 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 646 Rabais, remises et ristournes sur ventes de marchandises \N 709700 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 647 Rabais, remises et ristournes sur produits des activités annexes \N 709800 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 648 Variation des en-cours de production de biens - Produits en cours \N 713310 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 649 Variation des en-cours de production de biens - Travaux en cours \N 713350 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 650 Variation des en-cours de production de services - Études en cours \N 713410 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 651 Variation des en-cours de production de services - Prestations de services en cours \N 713450 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 652 Variation des stocks de produits intermédiaires \N 713510 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 653 Variation des stocks de produits finis \N 713550 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 654 Variation des stocks de produits résiduels \N 713580 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 656 Production immobilisée - Immobilisations corporelles \N 722000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 657 Subventions d'exploitation \N 740000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 658 Redevances pour concessions, brevets, licences, marques, procédés, logiciels \N 751100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 659 Droits d'auteur et de reproduction \N 751600 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 660 Redevances pour autres droits et valeurs similaires \N 751800 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 661 Revenus des immeubles non affectés aux activités professionnelles \N 752000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 663 Ristournes perçues des coopératives (provenant des excédents) \N 754000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 664 Quote-part de perte transférée (comptabilité du gérant) \N 755100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 665 Quote-part de bénéfice attribuée (comptabilité des associés non-gérants) \N 755500 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 666 Produits divers de gestion courante \N 758000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 655 Production immobilisée - Immobilisations incorporelles \N 721000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 662 Jetons de présence et rémunérations d'administrateurs, gérants.. \N 753000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 667 Revenus des titres de participation \N 761100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 668 Revenus sur autres formes de participation \N 761600 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 669 Revenus des titres immobilisés \N 762100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 670 Revenus des prêts \N 762600 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 671 Revenus des créances immobilisées \N 762700 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 672 Revenus des créances commerciales \N 763100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 673 Revenus des créances diverses \N 763800 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 674 Revenus des valeurs mobilières de placement \N 764000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 675 Escomptes obtenus \N 765000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 676 Gains de change \N 766000 f 13 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 677 Produits nets sur cessions de valeurs mobilières de placement \N 767000 f 14 other \N f (contrepartie 667) 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 678 Autres produits financiers \N 768000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 679 Produits exceptionnels - Dédits et pénalités perçus sur achats et sur ventes \N 771100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 681 Produits exceptionnels - Rentrées sur créances amorties \N 771400 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 682 Produits exceptionnels - Subventions d'équilibre \N 771500 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 683 Produits exceptionnels - Dégrèvements d'impôts autres qu'impôts sur les bénéfices \N 771700 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 684 Autres produits exceptionnels sur opérations de gestion \N 771800 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 685 Produits exceptionnels sur exercices antérieurs (en cours d'exercice seulement) \N 772000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 686 Produits exceptionnels des cessions d'éléments d'actif - Immobilisations incorporelles \N 775100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 687 Produits exceptionnels des cessions d'éléments d'actif - Immobilisations corporelles \N 775200 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 688 Produits exceptionnels des cessions d'éléments d'actif - Immobilisations financières \N 775600 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 689 Produits exceptionnels des cessions d'éléments d'actif - Autres éléments d'actif \N 775800 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 690 Produits exceptionnels - Quote-part des subventions d'investissement virée au résultat de l'exercice \N 777000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 691 Produits exceptionnels - Bonis provenant de clauses d'indexation \N 778100 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 692 Produits exceptionnels - Lots \N 778200 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 680 Produits exceptionnels - Libéralités reçues \N 771300 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 693 Produits exceptionnels - Bonis provenant du rachat par l'entreprise d'actions et d'obligations émises par elle-même \N 778300 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 694 Produits exceptionnels divers \N 778800 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 695 Reprises sur amortissements des immobilisations incorporelles \N 781110 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 696 Reprises sur amortissements des immobilisations corporelles \N 781120 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 697 Reprises sur provisions d'exploitation \N 781500 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 698 Reprises sur dépréciations des immobilisations incorporelles \N 781610 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 699 Reprises sur dépréciations des immobilisations corporelles \N 781620 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 700 Reprises sur dépréciations des actifs circulants - Stocks et en-cours \N 781730 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 701 Reprises sur dépréciations des actifs circulants - Créances \N 781740 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 702 Reprises sur provisions financières \N 786500 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 703 Reprises sur dépréciations des immobilisations financières \N 786620 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 704 Reprises sur dépréciations des valeurs mobilières de placement \N 786650 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 705 Reprises sur provisions réglementées (immobilisations) - Amortissements dérogatoires \N 787250 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 706 Reprises sur provisions réglementées (immobilisations) - Provision spéciale de réévaluation \N 787260 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 707 Reprises sur provisions réglementées (immobilisations) - Plus-values réinvesties \N 787270 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 709 Reprises sur autres provisions réglementées \N 787400 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 710 Reprises sur provisions exceptionnelles \N 787500 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 713 Transferts de charges financières \N 796000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 714 Transferts de charges exceptionnelles \N 797000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 716 Banque \N 512001 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 717 Profits/pertes non distribués \N 999999 f 12 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:06:53.166234 712 Transferts de charges d'exploitation \N 791000 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 708 Reprises sur provisions réglementées (stocks) \N 787300 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 715 Espèces \N 530001 f 3 liquidity \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 711 Reprises sur dépréciations exceptionnelles \N 787600 f 14 other \N f \N 1 \N 1 2019-02-14 15:06:53.166234 1 2019-02-14 15:09:48.936423 \. |
Added doc/manuel/Comptabilité avancée (partie double).md version [4caaa3768c].
> > > > > > > | 1 2 3 4 5 6 7 | # Comptabilité avancée (partie double) ## Fonctionnement général Par défaut les opérations sont enregistrées en tant que brouillon (dans le *brouillard*) et peuvent être modifiées ou supprimées. Il faut valider les opérations pour les rendre définitivées. Une opération validée ne peut plus être modifiée ou supprimée. En cas d'erreur il faudra créer une nouvelle écriture corrective. |
Added doc/manuel/Sauvegarde et restauration.md version [a2332341db].
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # Sauvegarde et restauration ## Messages d'erreur ### Le fichier fourni est corrompu. Certaines clés étrangères référencent des lignes qui n'existent pas. Ce message indiquent que certaines lignes dans une table font référence à des lignes d'une autre table qui n'existent pas. Cette erreur se produit lorsque des modifications manuelles ont été apportées à une base de données. Pour trouver les lignes qui sont invalides, utiliser un outil de gestion de base de données SQLite et lancer la commande suivante : PRAGMA schema.integrity_check; |
Deleted src/COPYING version [78e50e186b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/Makefile from [cf4731ac96] to [530c679c07].
|
| | | | > | > > > > > > | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | .PHONY: dev-server release deps publish check-dependencies test minify KD2_FILE := https://fossil.kd2.org/kd2fw/uv/KD2-7.2.zip deps: $(eval TMP_KD2=$(shell mktemp -d)) #cd ${TMP_KD2} wget ${KD2_FILE} -O ${TMP_KD2}/kd2.zip rm -rf "include/lib/KD2" unzip "${TMP_KD2}/kd2.zip" -d include/lib rm -rf ${TMP_KD2} dev-server: php -S localhost:8082 -t www www/_route.php test: find . -name '*.php' -print0 | xargs -0 -n1 php -l > /dev/null release: test minify $(eval VERSION=$(shell cat VERSION)) rm -rf /tmp/garradin-build mkdir -p /tmp/garradin-build fossil zip ${VERSION} /tmp/garradin-build/src.zip --name garradin unzip -d /tmp/garradin-build /tmp/garradin-build/src.zip cd include/lib; \ rsync --files-from=dependencies.list -r ./ /tmp/garradin-build/garradin/src/include/lib/ mv www/admin/static/mini.css /tmp/garradin-build/garradin/src/www/admin/static/admin.css cd /tmp/garradin-build/garradin/src/www/admin/static; \ rm -f styles/[0-9]*.css; \ rm -f font/*.css font/*.json cd /tmp/garradin-build/garradin/src; \ rm -f Makefile include/lib/KD2/data/countries.en.json mv /tmp/garradin-build/garradin/src /tmp/garradin-build/garradin-${VERSION} @#cd /tmp/garradin-build/; zip -r -9 garradin-${VERSION}.zip garradin-${VERSION}; @#mv -f /tmp/garradin-build/garradin-${VERSION}.zip ./ tar cjvfh garradin-${VERSION}.tar.bz2 -C /tmp/garradin-build garradin-${VERSION} deb: cd ../debian; ./makedeb.sh publish: release deb $(eval VERSION=$(shell cat VERSION)) fossil uv sync #fossil uv ls | fgrep -v 'garradin-0.8.5' | grep '^garradin-.*\.(tar\.bz2|deb)' | xargs fossil uv rm fossil uv add garradin-${VERSION}.tar.bz2 cd ../debian && fossil uv add garradin-${VERSION}-*.deb fossil uv sync check-dependencies: grep -hEo '^use \\?KD2\\[^; ]+|\\KD2\\[^\(:; ]+' -R include/lib/Garradin www | sed -r 's/^use \\?KD2\\|^\\KD2\\//' | sort | uniq minify: cat `ls www/admin/static/styles/[0-9]*.css` | sed 's/\.\.\///' > www/admin/static/mini.css yui-compressor --nomunge www/admin/static/mini.css -o www/admin/static/mini.css |
Deleted src/README version [b24af5ed67].
|
| < < < < < < < < < < < < < |
Modified src/VERSION from [bef1ccc9e8] to [fe6e76a10d].
|
| | | 1 | 1.0.0-rc3 |
Modified src/config.dist.php from [7d9b8d58eb] to [870f095e02].
︙ | ︙ | |||
15 16 17 18 19 20 21 | /** * Clé secrète, doit être unique à chaque instance de Garradin * * Ceci est utilisé afin de sécuriser l'envoi de formulaires * (protection anti-CSRF). * | > > > | | > | > | | | > | | > | > | | > | > > > > > > > > | > | > | > | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | /** * Clé secrète, doit être unique à chaque instance de Garradin * * Ceci est utilisé afin de sécuriser l'envoi de formulaires * (protection anti-CSRF). * * Cette valeur peut être modifiée sans autre impact que la déconnexion des utilisateurs * actuellement connectés. * * Si cette constante n'est définie, Garradin ajoutera automatiquement * une valeur aléatoire dans le fichier config.local.php. */ //const SECRET_KEY = '3xUhIgGwuovRKOjVsVPQ5yUMfXUSIOX2GKzcebsz5OINrYC50r'; /** * Se connecter automatiquement avec l'ID de membre indiqué * Exemple: LOCAL_LOGIN = 42 connectera automatiquement le membre n°42 * Attention à ne pas utiliser en production ! * * Il est aussi possible de mettre "LOCAL_LOGIN = -1" pour se connecter * avec le premier membre trouvé qui peut gérer la configuration (et donc * modifier les droits des membres). * * Défault : false (connexion automatique désactivée) */ //const LOCAL_LOGIN = false; /** * Autoriser (ou non) l'import de sauvegarde qui a été modifiée ? * * Si mis à true, un avertissement et une confirmation seront demandés * Si mis à false, tout fichier SQLite importé qui ne comporte pas une signature * valide (hash SHA1) sera refusé. * * Ceci ne s'applique qu'à la page "Sauvegarde et restauration" de l'admin, * il est toujours possible de restaurer une base de données non signée en * la recopiant à la place du fichier association.sqlite * * Défaut : true */ //const ALLOW_MODIFIED_IMPORT = true; /** * Doit-on suggérer à l'utilisateur d'utiliser la version chiffrée du site ? * * 1 ou true = affiche un message de suggestion sur l'écran de connexion invitant à utiliser le site chiffré * (conseillé si vous avez un certificat auto-signé ou peu connu type CACert) * 2 = rediriger automatiquement sur la version chiffrée pour l'administration (mais pas le site public) * 3 = rediriger automatiquement sur la version chiffrée pour administration et site public * false ou 0 = aucune version chiffrée disponible, donc ne rien proposer ni rediriger * * Défaut : false */ //const PREFER_HTTPS = false; /** * Répertoire où se situe le code source de Garradin * * Défaut : répertoire racine de Garradin (__DIR__) */ //const ROOT = __DIR__; /** * Répertoire où sont situées les données de Garradin * (incluant la base de données SQLite, les sauvegardes, le cache et les fichiers locaux) * * Défaut : identique à ROOT */ //const DATA_ROOT = ROOT; /** * Répertoire où est situé le cache (fichiers temporaires utilisés pour accélérer le chargement des pages) * * Défaut : sous-répertoire 'cache' de DATA_ROOT */ //const CACHE_ROOT = ROOT . '/cache'; /** * Emplacement du fichier de base de données de Garradin * * Défaut : DATA_ROOT . '/association.sqlite' */ //const DB_FILE = DATA_ROOT . '/association.sqlite'; /** * Emplacement de stockage des plugins * * Défaut : DATA_ROOT . '/plugins' */ //const PLUGINS_ROOT = DATA_ROOT . '/plugins'; /** * Plugins fixes qui ne peuvent être désinstallés par l'utilisateur * (séparés par une virgule) * * Ils seront aussi réinstallés en cas de restauration de sauvegarde, * s'ils ne sont pas dans la sauvegarde. * * Exemple : PLUGINS_SYSTEM = 'gestion_emails,factures' * * Défaut : aucun (chaîne vide) */ //const PLUGINS_SYSTEM = ''; /** * Adresse URI de la racine du site Garradin * (doit se terminer par un slash) * * Défaut : découverte automatique à partir de SCRIPT_NAME */ |
︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | //const WWW_URL = 'http://garradin.chezmoi.tld' . WWW_URI; /** * Adresse URL HTTP(S) de l'admin Garradin * * Défaut : WWW_URL + 'admin/' */ //const ADMIN_URL = 'https://admin.garradin.chezmoi.tld/'; /** * Affichage des erreurs * Si "true" alors un message expliquant l'erreur et comment rapporter le bug s'affiche * en cas d'erreur. Sinon rien ne sera affiché. * * Défaut : false * * Il est fortement conseillé de mettre cette valeur à false en production ! */ | > > | > | > | > | > | | > | > | > | > | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | //const WWW_URL = 'http://garradin.chezmoi.tld' . WWW_URI; /** * Adresse URL HTTP(S) de l'admin Garradin * * Défaut : WWW_URL + 'admin/' */ //const ADMIN_URL = 'https://admin.garradin.chezmoi.tld/'; /** * Affichage des erreurs * Si "true" alors un message expliquant l'erreur et comment rapporter le bug s'affiche * en cas d'erreur. Sinon rien ne sera affiché. * * Défaut : false * * Il est fortement conseillé de mettre cette valeur à false en production ! */ //const SHOW_ERRORS = false; /** * Envoi des erreurs par e-mail * * Si renseigné, un email sera envoyé à l'adresse indiquée à chaque fois qu'une erreur * d'exécution sera rencontrée. * Si "false" alors aucun email ne sera envoyé. * Note : les erreurs sont déjà toutes loguées dans error.log à la racine de DATA_ROOT * * Défaut : false */ //const MAIL_ERRORS = false; /** * Envoi des erreurs à une API compatible AirBrake/Errbit * * Si renseigné avec une URL HTTP(S) valide, chaque erreur système sera envoyée * automatiquement à cette URL. * * Si laissé à null, aucun rapport ne sera envoyé. * * Défaut : null */ //const ERRORS_REPORT_URL = null; /** * Activation de la page permettant de visualiser et rapporter les erreurs présentes * dans le error.log. * * Conseillé de mettre à false si vous ne voulez pas que les administrateurs de votre * instance puissent voir les erreurs système. * * Défaut : true * (Afin d'aider au rapport de bugs des instances auto-hébergées) */ //const ERRORS_ENABLE_LOG_VIEW = true; /** * Utilisation de cron pour les tâches automatiques * * Si "true" on s'attend à ce qu'une tâche automatisée appelle * le script cron.php à la racine toutes les 24 heures. Sinon Garradin * effectuera les actions automatiques quand quelqu'un se connecte à * l'administration ou visite le site. * * Défaut : false */ //const USE_CRON = false; /** * Activation de l'envoi de fichier directement par le serveur web. * (X-SendFile) * * Permet d'améliorer la rapidité d'envoi des fichiers. * Supporte les serveurs web suivants : * - Apache avec mod_xsendfile (paquet libapache2-mod-xsendfile) * - Lighttpd * * N'activer que si vous êtes sûr que le module est installé et activé (sinon * les fichiers ne pourront être vus ou téléchargés). * Nginx n'est PAS supporté, car X-Accel-Redirect ne peut gérer que des fichiers * qui sont *dans* le document root du vhost, ce qui n'est pas le cas ici. * * Pour activer X-SendFile mettre dans la config du virtualhost de Garradin: * XSendFile On * XSendFilePath /var/www/garradin * * (remplacer le chemin par le répertoire racine de Garradin) * * Détails : https://tn123.org/mod_xsendfile/ * * Défaut : false */ //const ENABLE_XSENDFILE = false; /** * Serveur NTP utilisé pour les connexions avec TOTP * (utilisé seulement si le code OTP fourni est faux) * * Désactiver (false) si vous êtes sûr que votre serveur est toujours à l'heure. * * Défaut : fr.pool.ntp.org */ //const NTP_SERVER = 'fr.pool.ntp.org'; /** * Hôte du serveur SMTP, mettre à false (défaut) pour utiliser la fonction * mail() de PHP * * Défaut : false */ //const SMTP_HOST = false; /** * Port du serveur SMTP * * 25 = port standard pour connexion non chiffrée (465 pour Gmail) * 587 = port standard pour connexion SSL * * Défaut : 587 */ //const SMTP_PORT = 587; /** * Login utilisateur pour le server SMTP * * mettre à null pour utiliser un serveur local ou anonyme * * Défaut : null |
︙ | ︙ | |||
270 271 272 273 274 275 276 | * NONE = pas de chiffrement * SSL = connexion SSL native * TLS = connexion TLS native (le plus sécurisé) * STARTTLS = utilisation de STARTTLS (moyennement sécurisé) * * Défaut : STARTTLS */ | > | > | > > > | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | * NONE = pas de chiffrement * SSL = connexion SSL native * TLS = connexion TLS native (le plus sécurisé) * STARTTLS = utilisation de STARTTLS (moyennement sécurisé) * * Défaut : STARTTLS */ //const SMTP_SECURITY = 'STARTTLS'; /** * Activer les sauvegardes automatiques * * Utile à désactiver si vous avez déjà des sauvegardes effectuées * automatiquement au niveau du système. * * Sinon les sauvegardes seront effectuées soit par la tâche cron * soit à l'affichage de la page d'accueil (si nécessaire). * * Voir paramètre USE_CRON aussi * * Défaut : true */ //const ENABLE_AUTOMATIC_BACKUPS = true; /** * Couleur primaire de l'interface admin par défaut * (peut être personnalisée dans la configuration) * * Défaut : #9c4f15 */ //const ADMIN_COLOR1 = '#20787a'; /** * Couleur secondaire de l'interface admin * Défaut : #d98628 */ //const ADMIN_COLOR2 = '#85b9ba'; /** * Image de fond par défaut de l'interface admin * * Cette URL doit être absolue (http://...) ou relative à l'admin (/admin/static...) * * Attention si l'image est sur un domaine différent vous devrez activer l'entête CORS: * Access-Control-Allow-Origin "*" * * sinon la personnalisation des couleurs ne fonctionnera pas * * Défaut : [ADMIN_URL]static/gdin_bg.png */ //const ADMIN_BACKGROUND_IMAGE = 'http://mon-asso.fr/fond_garradin.png'; |
Modified src/cron.php from [8c598487d9] to [d355372705].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php namespace Garradin; require_once __DIR__ . '/include/init.php'; // Exécution des tâches automatiques if (ENABLE_AUTOMATIC_BACKUPS && $config->get('frequence_sauvegardes') && $config->get('nombre_sauvegardes')) { $s = new Sauvegarde; $s->auto(); } // Exécution des rappels automatiques | > > < < < < | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php namespace Garradin; use Garradin\Services\Reminders; require_once __DIR__ . '/include/init.php'; // Exécution des tâches automatiques if (ENABLE_AUTOMATIC_BACKUPS && $config->get('frequence_sauvegardes') && $config->get('nombre_sauvegardes')) { $s = new Sauvegarde; $s->auto(); } // Exécution des rappels automatiques Reminders::sendPending(); |
Deleted src/include/data/0.7.0.sql version [acaa57e895].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/0.7.2.sql version [ba4b5fbcc7].
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/0.8.0.sql version [34e1625504].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/0.8.3.sql version [68c67cd1a9].
|
| < < < < < < < < < < < |
Deleted src/include/data/0.8.4.sql version [107bec2b2d].
|
| < < < |
Deleted src/include/data/0.9.0.sql version [9f23495ff4].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/data/0.9.1.sql version [8d911832a5].
|
| < < < < < < < < < < < < < < |
Added src/include/data/1.0.0-beta6_migration.sql version [13c95a32fe].
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ALTER TABLE fichiers_membres RENAME TO fichiers_membres_old; ALTER TABLE fichiers_wiki_pages RENAME TO fichiers_wiki_pages_old; ALTER TABLE fichiers_acc_transactions RENAME TO fichiers_acc_transactions_old; .read 1.0.0_schema.sql INSERT INTO fichiers_membres SELECT * FROM fichiers_membres_old; INSERT INTO fichiers_wiki_pages SELECT * FROM fichiers_wiki_pages_old; INSERT INTO fichiers_acc_transactions SELECT * FROM fichiers_acc_transactions_old; DROP TABLE fichiers_membres_old; DROP TABLE fichiers_wiki_pages_old; DROP TABLE fichiers_acc_transactions_old; |
Added src/include/data/1.0.0-beta8_migration.sql version [ff1b70a076].
> > | 1 2 | UPDATE acc_accounts SET type = 11 WHERE code = '120'; UPDATE acc_accounts SET type = 12 WHERE code = '129'; |
Added src/include/data/1.0.0-rc3_migration.sql version [46b4d521e5].
> | 1 | UPDATE acc_transactions SET type = 0 WHERE type = 6; |
Added src/include/data/1.0.0_migration.sql version [ee5739a872].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | ALTER TABLE membres_operations RENAME TO membres_operations_old; ALTER TABLE membres_categories RENAME TO membres_categories_old; DROP TABLE fichiers_compta_journal; -- Inutilisé à ce jour -- Fix: comptes de clôture et fermeture UPDATE compta_comptes SET libelle = 'Bilan d''ouverture' WHERE id = '890' AND libelle = 'Bilan de clôture'; INSERT OR REPLACE INTO compta_comptes (id, parent, libelle, position) VALUES ('891', '89', 'Bilan de clôture', 0); -- N'est pas utilisé DELETE FROM config WHERE cle = 'categorie_dons' OR cle = 'categorie_cotisations'; .read 1.0.0_schema.sql -------- MIGRATION COMPTA --------- INSERT INTO acc_charts (id, country, code, label) VALUES (1, 'FR', 'PCGA1999', 'Plan comptable associatif 1999'); -- Migration comptes de code comme identifiant à ID unique -- Inversement valeurs actif/passif et produit/charge INSERT INTO acc_accounts (id, id_chart, code, label, position, user) SELECT NULL, 1, id, libelle, CASE position WHEN 1 THEN 2 WHEN 2 THEN 1 WHEN 3 THEN 3 WHEN 4 THEN 5 WHEN 8 THEN 4 -- Suppression de la position "charge ou produit" qui n'a aucun sens WHEN 12 THEN 0 ELSE 0 END, CASE WHEN plan_comptable = 1 THEN 0 ELSE 1 END FROM compta_comptes; -- Migrations projets vers comptes analytiques INSERT INTO acc_accounts (id_chart, code, label, position, user, type) VALUES (1, '99', 'Projets', 0, 1, 0); INSERT INTO acc_accounts (id_chart, code, label, position, user, type) SELECT 1, '99' || substr('0000' || id, -4), libelle, 0, 1, 7 FROM compta_projets; -- Mise à jour de la position pour les comptes de tiers qui peuvent varier actif ou passif UPDATE acc_accounts SET position = 3 WHERE code IN (4010, 4110, 4210, 428, 438); -- Mise à jour position comptes bancaires, qui peuvent être à découvert et donc changer de côté au bilan UPDATE acc_accounts SET position = 3 WHERE code LIKE '512%'; -- Migration comptes bancaires UPDATE acc_accounts SET type = 1 WHERE code IN (SELECT id FROM compta_comptes_bancaires); -- Caisse UPDATE acc_accounts SET type = 2 WHERE code = '530'; -- Chèques et carte à encaisser UPDATE acc_accounts SET type = 3 WHERE code = '5112' OR code = '5113'; -- Comptes d'ouverture et de clôture UPDATE acc_accounts SET type = 9, position = 0 WHERE code = '890'; UPDATE acc_accounts SET type = 10, position = 0 WHERE code = '891'; -- Comptes de tiers UPDATE acc_accounts SET type = 4 WHERE code IN (SELECT id FROM compta_comptes WHERE id LIKE '4%' AND plan_comptable = 0 AND desactive = 0); -- Recopie des mouvements INSERT INTO acc_transactions (id, label, notes, reference, date, id_year, id_creator) SELECT id, libelle, remarques, numero_piece, date, id_exercice, id_auteur FROM compta_journal; -- Recettes UPDATE acc_transactions SET type = 1 WHERE id IN (SELECT id FROM compta_journal WHERE id_categorie IN (SELECT id FROM compta_categories WHERE type = 1)); -- Dépenses UPDATE acc_transactions SET type = 2 WHERE id IN (SELECT id FROM compta_journal WHERE id_categorie IN (SELECT id FROM compta_categories WHERE type = -1)); -- Virements UPDATE acc_transactions SET type = 3 WHERE id IN (SELECT id FROM compta_journal WHERE (compte_credit IN ('530', '5112', '5115') OR compte_credit LIKE '512%') AND (compte_debit IN ('530', '5112', '5115') OR compte_debit LIKE '512%')); -- Dettes UPDATE acc_transactions SET type = 4 WHERE id IN (SELECT id FROM compta_journal WHERE compte_debit LIKE '6%' AND compte_credit LIKE '4%'); -- Créances UPDATE acc_transactions SET type = 5 WHERE id IN (SELECT id FROM compta_journal WHERE compte_credit LIKE '7%' AND compte_debit LIKE '4%'); -- Création des lignes associées aux mouvements INSERT INTO acc_transactions_lines (id_transaction, id_account, debit, credit, reference, id_analytical) SELECT id, (SELECT id FROM acc_accounts WHERE code = compte_credit), 0, CAST(REPLACE(montant * 100, '.0', '') AS INT), numero_cheque, CASE WHEN id_projet IS NOT NULL THEN (SELECT id FROM acc_accounts WHERE code = '99' || substr('0000' || id_projet, -4)) ELSE NULL END FROM compta_journal; INSERT INTO acc_transactions_lines (id_transaction, id_account, debit, credit, reference, id_analytical) SELECT id, (SELECT id FROM acc_accounts WHERE code = compte_debit), CAST(REPLACE(montant * 100, '.0', '') AS INT), 0, numero_cheque, CASE WHEN id_projet IS NOT NULL THEN (SELECT id FROM acc_accounts WHERE code = '99' || substr('0000' || id_projet, -4)) ELSE NULL END FROM compta_journal; -- Recopie des descriptions de catégories dans la table des comptes, et mise des comptes en signets -- +Fix éventuels types qui ne correspondent pas à leur type… (@Fred C.) (... a.position = X) -- Revenus UPDATE acc_accounts SET type = 6, description = (SELECT description FROM compta_categories WHERE compte = acc_accounts.code) WHERE id IN (SELECT a.id FROM acc_accounts a INNER JOIN compta_categories c ON c.compte = a.code AND c.type = 1 AND a.position = 5); -- Dépenses UPDATE acc_accounts SET type = 5, description = (SELECT description FROM compta_categories WHERE compte = acc_accounts.code) WHERE id IN (SELECT a.id FROM acc_accounts a INNER JOIN compta_categories c ON c.compte = a.code AND c.type = -1 AND c.compte NOT LIKE '4%' AND a.position = 4); -- Tiers UPDATE acc_accounts SET type = 4, description = (SELECT description FROM compta_categories WHERE compte = acc_accounts.code) WHERE id IN (SELECT a.id FROM acc_accounts a INNER JOIN compta_categories c ON c.compte = a.code AND c.type = -1 AND c.compte LIKE '4%'); -- Recopie des opérations, mais le nom a changé pour acc_transactions_users INSERT INTO acc_transactions_users SELECT * FROM membres_operations_old; -- Recopie des exercices, mais la date de fin ne peut être nulle INSERT INTO acc_years (id, label, start_date, end_date, closed, id_chart) SELECT id, libelle, debut, CASE WHEN fin IS NULL THEN date(debut, '+1 year') ELSE fin END, cloture, 1 FROM compta_exercices; -- Recopie des catégories, on supprime la colonne id_cotisation_obligatoire INSERT INTO membres_categories SELECT id, nom, droit_wiki, droit_membres, droit_compta, droit_inscription, droit_connexion, droit_config, cacher FROM membres_categories_old; DROP TABLE membres_categories_old; -- Transfert des rapprochements UPDATE acc_transactions_lines SET reconciled = 1 WHERE id_transaction IN (SELECT id_operation FROM compta_rapprochement); --------- MIGRATION COTISATIONS ---------- INSERT INTO services SELECT id, intitule, description, duree, debut, fin FROM cotisations; INSERT INTO services_fees (id, label, amount, id_service, id_account, id_year) SELECT id, intitule, CASE WHEN montant IS NOT NULL THEN CAST(montant*100 AS integer) ELSE NULL END, id, (SELECT id FROM acc_accounts WHERE code = (SELECT compte FROM compta_categories WHERE id = id_categorie_compta)), (SELECT MAX(id) FROM acc_years WHERE closed = 0) FROM cotisations; INSERT INTO services_users SELECT cm.id, cm.id_membre, cm.id_cotisation, cm.id_cotisation, 1, NULL, cm.date, CASE WHEN c.duree IS NOT NULL THEN date(cm.date, '+'||c.duree||' days') WHEN c.fin IS NOT NULL THEN c.fin ELSE NULL END FROM cotisations_membres cm INNER JOIN cotisations c ON c.id = cm.id_cotisation; INSERT INTO services_reminders SELECT * FROM rappels; INSERT INTO services_reminders_sent SELECT id, id_membre, id_cotisation, CASE WHEN id_rappel IS NULL THEN (SELECT MAX(id) FROM rappels) ELSE id_rappel END, date FROM rappels_envoyes GROUP BY id_membre, id_cotisation, id_rappel; DROP TABLE cotisations; DROP TABLE cotisations_membres; DROP TABLE rappels; DROP TABLE rappels_envoyes; -- Suppression inutilisées DROP TABLE compta_rapprochement; DROP TABLE compta_journal; DROP TABLE compta_categories; DROP TABLE compta_comptes; DROP TABLE compta_exercices; DROP TABLE membres_operations_old; DROP TABLE compta_projets; DROP TABLE compta_comptes_bancaires; DROP TABLE compta_moyens_paiement; |
Added src/include/data/1.0.0_schema.sql version [2cb870482b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | CREATE TABLE IF NOT EXISTS config ( -- Configuration de Garradin cle TEXT PRIMARY KEY NOT NULL, valeur TEXT ); CREATE TABLE IF NOT EXISTS membres_categories -- Catégories de membres ( id INTEGER PRIMARY KEY NOT NULL, nom TEXT NOT NULL, droit_wiki INTEGER NOT NULL DEFAULT 1, droit_membres INTEGER NOT NULL DEFAULT 1, droit_compta INTEGER NOT NULL DEFAULT 1, droit_inscription INTEGER NOT NULL DEFAULT 0, droit_connexion INTEGER NOT NULL DEFAULT 1, droit_config INTEGER NOT NULL DEFAULT 0, cacher INTEGER NOT NULL DEFAULT 0 ); -- Membres de l'asso -- Table dynamique générée par l'application -- voir Garradin\Membres\Champs.php CREATE TABLE IF NOT EXISTS membres_sessions -- Sessions ( selecteur TEXT NOT NULL, hash TEXT NOT NULL, id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, expire INT NOT NULL, PRIMARY KEY (selecteur, id_membre) ); CREATE TABLE IF NOT EXISTS services -- Types de services (cotisations) ( id INTEGER PRIMARY KEY NOT NULL, label TEXT NOT NULL, description TEXT NULL, duration INTEGER NULL CHECK (duration IS NULL OR duration > 0), -- En jours start_date TEXT NULL CHECK (start_date IS NULL OR date(start_date) = start_date), end_date TEXT NULL CHECK (end_date IS NULL OR (date(end_date) = end_date AND date(end_date) >= date(start_date))) ); CREATE TABLE IF NOT EXISTS services_fees ( id INTEGER PRIMARY KEY NOT NULL, label TEXT NOT NULL, description TEXT NULL, amount INTEGER NULL, formula TEXT NULL, -- Formule de calcul du montant de la cotisation, si cotisation dynamique (exemple : membres.revenu_imposable * 0.01) id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE, id_account INTEGER NULL REFERENCES acc_accounts (id) ON DELETE SET NULL CHECK (id_account IS NULL OR id_year IS NOT NULL), -- NULL si le type n'est pas associé automatiquement à la compta id_year INTEGER NULL REFERENCES acc_years (id) ON DELETE SET NULL -- NULL si le type n'est pas associé automatiquement à la compta ); CREATE TABLE IF NOT EXISTS services_users -- Enregistrement des cotisations et activités ( id INTEGER NOT NULL PRIMARY KEY, id_user INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE, id_fee INTEGER NULL REFERENCES services_fees (id) ON DELETE CASCADE, paid INTEGER NOT NULL DEFAULT 0, expected_amount INTEGER NULL, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), expiry_date TEXT NULL CHECK (date(expiry_date) IS NULL OR date(expiry_date) = expiry_date) ); CREATE UNIQUE INDEX IF NOT EXISTS su_unique ON services_users (id_user, id_service, date); CREATE INDEX IF NOT EXISTS su_service ON services_users (id_service); CREATE INDEX IF NOT EXISTS su_fee ON services_users (id_fee); CREATE INDEX IF NOT EXISTS su_paid ON services_users (paid); CREATE INDEX IF NOT EXISTS su_expiry ON services_users (expiry_date); CREATE TABLE IF NOT EXISTS services_reminders -- Rappels de devoir renouveller une cotisation ( id INTEGER NOT NULL PRIMARY KEY, id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE, delay INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel subject TEXT NOT NULL, body TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS services_reminders_sent -- Enregistrement des rappels envoyés à qui et quand ( id INTEGER NOT NULL PRIMARY KEY, id_user INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE, id_reminder INTEGER NOT NULL REFERENCES services_reminders (id) ON DELETE CASCADE, date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date) ); CREATE UNIQUE INDEX IF NOT EXISTS srs_index ON services_reminders_sent (id_user, id_service, id_reminder, date); CREATE INDEX IF NOT EXISTS srs_reminder ON services_reminders_sent (id_reminder); CREATE INDEX IF NOT EXISTS srs_user ON services_reminders_sent (id_user); -- -- WIKI -- CREATE TABLE IF NOT EXISTS wiki_pages -- Pages du wiki ( id INTEGER PRIMARY KEY NOT NULL, uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki) titre TEXT NOT NULL, date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation), date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification), parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte) droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe) droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe) ); CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri); CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4 -- Table dupliquée pour chercher une page ( id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire titre TEXT NOT NULL, contenu TEXT NULL, -- Contenu de la dernière révision FOREIGN KEY (id) REFERENCES wiki_pages(id) ); CREATE TABLE IF NOT EXISTS wiki_revisions -- Révisions du contenu des pages ( id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE, revision INTEGER NULL, id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL, contenu TEXT NOT NULL, modification TEXT NULL, -- Description des modifications effectuées chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date), PRIMARY KEY(id_page, revision) ); CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page); CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur); -- Triggers pour synchro avec table wiki_pages CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages BEGIN DELETE FROM wiki_recherche WHERE id = old.id; END; CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages BEGIN UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id; END; -- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1 BEGIN UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page; END; -- Si le contenu est chiffré, la recherche n'affiche pas de contenu CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1 BEGIN UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page; END; -- -- COMPTA -- CREATE TABLE IF NOT EXISTS acc_charts -- Plans comptables : il peut y en avoir plusieurs ( id INTEGER NOT NULL PRIMARY KEY, country TEXT NOT NULL, code TEXT NULL, -- NULL = plan comptable créé par l'utilisateur label TEXT NOT NULL, archived INTEGER NOT NULL DEFAULT 0 -- 1 = archivé, non-modifiable ); CREATE TABLE IF NOT EXISTS acc_accounts -- Comptes des plans comptables ( id INTEGER NOT NULL PRIMARY KEY, id_chart INTEGER NOT NULL REFERENCES acc_charts ON DELETE CASCADE, code TEXT NOT NULL, -- peut contenir des lettres, eg. 53A, 53B, etc. label TEXT NOT NULL, description TEXT NULL, position INTEGER NOT NULL, -- position actif/passif/charge/produit type INTEGER NOT NULL DEFAULT 0, -- Type de compte spécial : banque, caisse, en attente d'encaissement, etc. user INTEGER NOT NULL DEFAULT 1 -- 1 = fait partie du plan comptable original, 0 = a été ajouté par l'utilisateur ); CREATE UNIQUE INDEX IF NOT EXISTS acc_accounts_codes ON acc_accounts (code, id_chart); CREATE INDEX IF NOT EXISTS acc_accounts_type ON acc_accounts (type); CREATE INDEX IF NOT EXISTS acc_accounts_position ON acc_accounts (position); CREATE TABLE IF NOT EXISTS acc_years -- Exercices ( id INTEGER NOT NULL PRIMARY KEY, label TEXT NOT NULL, start_date TEXT NOT NULL CHECK (date(start_date) IS NOT NULL AND date(start_date) = start_date), end_date TEXT NOT NULL CHECK (date(end_date) IS NOT NULL AND date(end_date) = end_date), closed INTEGER NOT NULL DEFAULT 0, id_chart INTEGER NOT NULL REFERENCES acc_charts (id) ); CREATE INDEX IF NOT EXISTS acc_years_closed ON acc_years (closed); CREATE TABLE IF NOT EXISTS acc_transactions -- Opérations comptables ( id INTEGER PRIMARY KEY NOT NULL, type INTEGER NOT NULL DEFAULT 0, -- Type d'écriture, 0 = avancée (normale) status INTEGER NOT NULL DEFAULT 0, -- Statut (bitmask) label TEXT NOT NULL, notes TEXT NULL, reference TEXT NULL, -- N° de pièce comptable date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date), validated INTEGER NOT NULL DEFAULT 0, -- 1 = écriture validée, non modifiable hash TEXT NULL, prev_hash TEXT NULL, id_year INTEGER NOT NULL REFERENCES acc_years(id), id_creator INTEGER NULL REFERENCES membres(id) ON DELETE SET NULL, id_related INTEGER NULL REFERENCES acc_transactions(id) ON DELETE SET NULL -- écriture liée (par ex. remboursement d'une dette) ); CREATE INDEX IF NOT EXISTS acc_transactions_year ON acc_transactions (id_year); CREATE INDEX IF NOT EXISTS acc_transactions_date ON acc_transactions (date); CREATE INDEX IF NOT EXISTS acc_transactions_related ON acc_transactions (id_related); CREATE INDEX IF NOT EXISTS acc_transactions_type ON acc_transactions (type); CREATE INDEX IF NOT EXISTS acc_transactions_status ON acc_transactions (status); CREATE TABLE IF NOT EXISTS acc_transactions_lines -- Lignes d'écritures d'une opération ( id INTEGER PRIMARY KEY NOT NULL, id_transaction INTEGER NOT NULL REFERENCES acc_transactions (id) ON DELETE CASCADE, id_account INTEGER NOT NULL REFERENCES acc_accounts (id), -- N° du compte dans le plan comptable credit INTEGER NOT NULL, debit INTEGER NOT NULL, reference TEXT NULL, -- Référence de paiement, eg. numéro de chèque label TEXT NULL, reconciled INTEGER NOT NULL DEFAULT 0, id_analytical INTEGER NULL REFERENCES acc_accounts(id) ON DELETE SET NULL, CONSTRAINT line_check1 CHECK ((credit * debit) = 0), CONSTRAINT line_check2 CHECK ((credit + debit) > 0) ); CREATE INDEX IF NOT EXISTS acc_transactions_lines_account ON acc_transactions_lines (id_account); CREATE INDEX IF NOT EXISTS acc_transactions_lines_analytical ON acc_transactions_lines (id_analytical); CREATE INDEX IF NOT EXISTS acc_transactions_lines_reconciled ON acc_transactions_lines (reconciled); CREATE TABLE IF NOT EXISTS acc_transactions_users -- Liaison des écritures et des membres ( id_user INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, id_transaction INTEGER NOT NULL REFERENCES acc_transactions (id) ON DELETE CASCADE, id_service_user INTEGER NULL REFERENCES services_users (id) ON DELETE SET NULL, PRIMARY KEY (id_user, id_transaction) ); CREATE INDEX IF NOT EXISTS acc_transactions_users_service ON acc_transactions_users (id_service_user); CREATE TABLE IF NOT EXISTS plugins ( id TEXT NOT NULL PRIMARY KEY, officiel INTEGER NOT NULL DEFAULT 0, nom TEXT NOT NULL, description TEXT NULL, auteur TEXT NULL, url TEXT NULL, version TEXT NOT NULL, menu INTEGER NOT NULL DEFAULT 0, menu_condition TEXT NULL, config TEXT NULL ); CREATE TABLE IF NOT EXISTS plugins_signaux -- Association entre plugins et signaux (hooks) ( signal TEXT NOT NULL, plugin TEXT NOT NULL REFERENCES plugins (id), callback TEXT NOT NULL, PRIMARY KEY (signal, plugin) ); CREATE TABLE IF NOT EXISTS fichiers -- Données sur les fichiers ( id INTEGER NOT NULL PRIMARY KEY, nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg) type TEXT NULL, -- Type MIME image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime); CREATE TABLE IF NOT EXISTS fichiers_contenu -- Contenu des fichiers ( id INTEGER NOT NULL PRIMARY KEY, hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier taille INTEGER NOT NULL, -- Taille en octets contenu BLOB NULL ); CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash); CREATE TABLE IF NOT EXISTS fichiers_membres -- Associations entre fichiers et membres (photo de profil par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id) ON DELETE CASCADE, id INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE, PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_wiki_pages -- Associations entre fichiers et pages du wiki ( fichier INTEGER NOT NULL REFERENCES fichiers (id) ON DELETE CASCADE, id INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE, PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS fichiers_acc_transactions -- Associations entre fichiers et journal de compta (pièce comptable par exemple) ( fichier INTEGER NOT NULL REFERENCES fichiers (id) ON DELETE CASCADE, id INTEGER NOT NULL REFERENCES acc_transactions (id) ON DELETE CASCADE, PRIMARY KEY(fichier, id) ); CREATE TABLE IF NOT EXISTS recherches -- Recherches enregistrées ( id INTEGER NOT NULL PRIMARY KEY, id_membre INTEGER NULL REFERENCES membres (id) ON DELETE CASCADE, -- Si non NULL, alors la recherche ne sera visible que par le membre associé intitule TEXT NOT NULL, creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(creation) IS NOT NULL AND datetime(creation) = creation), cible TEXT NOT NULL, -- "membres" ou "compta" type TEXT NOT NULL, -- "json" ou "sql" contenu TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS compromised_passwords_cache -- Cache des hash de mots de passe compromis ( hash TEXT NOT NULL PRIMARY KEY ); CREATE TABLE IF NOT EXISTS compromised_passwords_cache_ranges -- Cache des préfixes de mots de passe compromis ( prefix TEXT NOT NULL PRIMARY KEY, date INTEGER NOT NULL ); |
Deleted src/include/data/categories_comptables.sql version [7430a75c4a].
|
| < < < < < < < < < < < < < < < < < < < < < < < |
Added src/include/data/charts/fr_1999.csv version [38d9f67e8d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | code,label,description,position,type 1,"Classe 1 — Comptes de capitaux (Fonds propres, emprunts et dettes assimilés)",,Passif, 10,FONDS ASSOCIATIFS ET RÉSERVES,,Passif, 102,Fonds associatif sans droit de reprise,,Passif, 1021,Valeur du patrimoine intégré,,Passif, 1022,Fonds statutaire,,Passif, 1024,Apports sans droit de reprise,,Passif, 103,Fonds associatif avec droit de reprise,,Passif, 1034,Apports avec droit de reprise,,Passif, 105,Écarts de réévaluation,,Passif, 106,Réserves,,Passif, 1063,Réserves statutaires ou contractuelles,,Passif, 1064,Réserves réglementées,,Passif, 1068,Autres réserves (dont réserves pour projet associatif),,Passif, 11,REPORT À NOUVEAU,,Passif, 110,Report à nouveau (Solde créditeur),,Passif, 119,Report à nouveau (Solde débiteur),,Passif, 12,RÉSULTAT NET DE L'EXERCICE,,Passif, 120,Résultat de l'exercice (excédent),,Passif,Résultat excédentaire 129,Résultat de l'exercice (déficit),,Passif,Résultat déficitaire 13,SUBVENTIONS D'INVESTISSEMENT AFFECTÉES A DES BIENS NON RENOUVELABLES,,Passif, 131,Subventions d'investissement (renouvelables),,Passif, 139,Subventions d'investissement inscrites au compte de résultat,,Passif, 14,PROVISIONS REGLEMENTÉES,,Passif, 15,PROVISIONS,,Passif, 151,Provisions pour risques,,Passif, 157,Provisions pour charges à répartir sur plusieurs exercices,,Passif, 158,Autres provisions pour charges,,Passif, 16,EMPRUNTS ET DETTES ASSIMILÉES,,Passif, 164,Emprunts auprès des établissements de crédits,,Passif, 165,Dépôts et cautionnements reçus,,Passif, 167,Emprunts et dettes assorties de conditions particulières,,Passif, 168,Autres emprunts et dettes assimilés,,Passif, 17,DETTES RATTACHÉES À DES PARTICIPATIONS,,Passif, 18,COMPTES DE LIAISON DES ÉTABLISSEMENTS,,Passif, 181,Apports permanents entre siège social et établissements,,Passif, 185,Biens et prestations de services échangés entre établissements et siège social,,Passif, 186,Biens et prestations de services échangés entre établissements (charges),,Passif, 187,Biens et prestations de services échangés entre établissements (produits),,Passif, 19,FONDS DÉDIÉS,,Passif, 194,Fonds dédiés sur subventions de fonctionnement,,Passif, 195,Fonds dédiés sur dons manuels affectés,,Passif, 197,Fonds dédiés sur legs et donations affectés,,Passif, 198,Excédent disponible après affectation au projet associatif,,Passif, 199,Reprise des fonds affectés au projet associatif,,Passif, 2,Classe 2 — Comptes d'immobilisations,,Actif, 20,IMMOBILISATIONS INCORPORELLES,,Actif, 200,Immobilisations incorporelles,,Actif, 21,IMMOBILISATIONS CORPORELLES,,Actif, 210,Investissements,,Actif, 22,IMMOBILISATIONS GREVÉES DE DROITS,,Actif, 228,Immobilisations grevées de droits,,Actif, 229,Droits des propriétaires,,Actif, 23,IMMOBILISATIONS EN COURS,,Actif, 231,Immobilisations corporelles en cours,,Actif, 238,Avances et acomptes versés sur commande d'immobilisations corporelles,,Actif, 26,PARTICIPATIONS ET CRÉANCES RATTACHÉES A DES PARTICIPATIONS,,Actif, 261,Titres de participation,,Actif, 27,AUTRES IMMOBILISATIONS FINANCIÈRES,,Actif, 270,Participations financières,,Actif, 275,Dépôts et cautionnements versés,,Actif, 28,AMORTISSEMENTS DES IMMOBILISATIONS,,Actif, 280,Amortissements des immobilisations incorporelles,,Actif, 281,Amortissements des immobilisations corporelles,,Actif, 29,DÉPRÉCIATION DES IMMOBILISATIONS,,Actif, 290,Dépréciation des immobilisations incorporelles,,Actif, 291,Dépréciation des immobilisations corporelles,,Actif, 3,Classe 3 — Comptes de stocks,,Actif, 31,MATIERES PREMIERES ET FOURNITURES,,Actif, 311,Matières,,Actif, 317,Fournitures,,Actif, 32,AUTRES APPROVISIONNEMENTS,,Actif, 321,Matières consommables,,Actif, 322,Fournitures consommables,,Actif, 33,EN-COURS DE PRODUCTION DE BIENS,,Actif, 331,Produits en cours,,Actif, 335,Travaux en cours,,Actif, 34,EN-COURS DE PRODUCTION DE SERVICES,,Actif, 35,STOCKS DE PRODUITS,,Actif, 351,Produits intermédiaires,,Actif, 355,Produits finis,,Actif, 358,Produits résiduels,,Actif, 3581,Déchets,,Actif, 3585,Rebuts,,Actif, 3586,Matière de récupération,,Actif, 37,STOCKS DE MARCHANDISES,,Actif, 370,Autres stocks de marchandises,,Actif, 39,PROVISIONS POUR DEPRECIATION DES STOCKS ET EN-COURS,,Actif, 391,Provisions pour dépréciation des matières premières et fournitures,,Actif, 4,Classe 4 — Comptes de tiers,,Actif ou passif, 40,FOURNISSEURS ET COMPTES RATTACHÉS,,Passif, 401,Fournisseurs,,Passif, 4010,Autres fournisseurs,,Actif ou passif,Tiers 408,Fournisseurs - Factures non parvenues,,Passif, 409,Avances aux fournisseurs,,Actif, 41,USAGERS ET COMPTES RATTACHÉS,,Actif, 411,Usagers,,Actif, 4110,Autres usagers,,Actif ou passif,Tiers 419,Avances aux usagers,,Passif, 42,PERSONNEL ET COMPTES RATTACHÉS,,Passif, 421,Personnel - Rémunérations dues,,Passif, 4210,Autres membres du personnel,,Actif ou passif, 425,Personnel - Avances et acomptes,,Actif, 428,Personnel - Charges à payer et produits à recevoir,,Actif ou passif, 43,SÉCURITÉ SOCIALE ET AUTRES ORGANISMES SOCIAUX,,Passif, 430,Dettes et crédits envers les organismes sociaux,,Passif, 431,Sécurité sociale,,Passif, 437,Autres organismes sociaux,,Passif, 4372,Mutuelles,,Passif, 4373,Caisse de retraite et de prévoyance,,Passif, 4374,Caisse d'allocations de chômage - Pôle emploi,,Passif, 4375,AGESSA,,Passif, 4378,Autres organismes sociaux - Divers,,Passif, 438,Organismes sociaux - Charges à payer et produits à recevoir,,Actif ou passif, 4382,Charges sociales sur congés à payer,,Passif, 4386,Autres charges à payer,,Passif, 4387,Produits à recevoir,,Actif, 439,Avances auprès des organismes sociaux,,Passif, 44,ÉTAT ET AUTRES COLLECTIVITÉS PUBLIQUES,,Actif, 441,État - Subventions à recevoir,,Actif, 4411,Subventions d'investissement,,Actif, 4417,Subventions d'exploitation,,Actif, 4418,Subventions d'équilibre,,Actif, 4419,Avances sur subventions,,Actif, 442,État - Impôts et taxes recouvrables sur des tiers,,Passif, 444,État - Impôts sur les bénéfices,,Actif, 445,État - Taxes sur le chiffre d'affaires,,Actif, 4455,Taxes sur le chiffre d'affaires à décaisser,,Actif, 44551,TVA à décaisser,,Actif, 44558,Taxes assimilées à la TVA,,Actif, 4456,Taxes sur le chiffre d'affaires déductibles,,Actif, 44562,TVA sur immobilisations,,Actif, 44566,TVA sur autres biens et services,,Actif, 4457,Taxes sur le chiffre d'affaires collectées par l'association,,Actif, 4458,Taxes sur le chiffre d'affaires à régulariser ou en attente,,Actif, 44581,Acomptes - Régime simplifié d'imposition,,Actif, 44582,Acomptes - Régime du forfait,,Actif, 44583,Remboursement de taxes sur le chiffre d'affaires demandé,,Actif, 44584,TVA récupérée d'avance,,Actif, 44586,Taxes sur le chiffre d'affaires sur factures non parvenues,,Actif, 44587,Taxes sur le chiffre d'affaires sur factures à établir,,Actif, 447,"Autres impôts, taxes et versements assimilés",,Passif, 4471,"Autres impôts, taxes et versements assimilés sur rémunérations (Administration des impôts)",,Passif, 44711,Taxe sur les salaires,,Passif, 44713,Participation des employeurs à la formation professionnelle continue,,Passif, 44714,Cotisation par défaut d'investissement obligatoire dans la construction,,Passif, 44718,"Autres impôts, taxes et versements assimilés",,Passif, 4473,"Autres impôts, taxes et versements assimilés sur rémunérations (Autres organismes)",,Passif, 44733,Participation des employeurs à la formation professionnelle continue,,Passif, 44734,Participation des employeurs à l'effort de construction (versements à fonds perdus),,Passif, 4475,"Autres impôts, taxes et versements assimilés (Administration des impôts)",,Passif, 4477,"Autres impôts, taxes et versements assimilés (Autres organismes)",,Passif, 448,État - Charges à payer et produits à recevoir,,Passif, 4482,Charges fiscales sur congés à payer,,Passif, 4486,Autres charges à payer,,Passif, 4487,Produits à recevoir,,Actif, 449,Avances auprès de l'état et des collectivités publiques,,Passif, 45,"CONFÉDÉRATION, FÉDÉRATION, UNIONS ET ASSOCIATIONS AFFILIÉES",,Actif ou passif, 451,"Confédération, fédération et associations affiliées - Compte courant",,Actif ou passif, 455,Sociétaires - Comptes courants,,Actif ou passif, 46,DÉBITEURS DIVERS ET CRÉDITEURS DIVERS,,Actif ou passif, 467,Autres comptes débiteurs et créditeurs,,Actif ou passif, 468,Divers - Charges à payer et produits à recevoir,,Actif ou passif, 4686,Charges à payer,,Passif, 4687,Produits à recevoir,,Actif, 47,COMPTES TRANSITOIRES OU D'ATTENTE,,Actif ou passif, 471,Recettes à classer,,Passif, 472,Dépenses à classer et à régulariser,,Actif, 48,COMPTES DE RÉGULARISATION,,Actif ou passif, 481,Charges à répartir sur plusieurs exercices,,Actif, 486,Charges constatées d'avance,,Actif, 487,Produits constatés d'avance,,Passif, 49,DEPRECIATION DES COMPTES DE TIERS,,Actif, 491,Dépréciation des comptes clients,,Actif, 496,Dépréciation des comptes débiteurs divers,,Actif, 5,Classe 5 — Comptes financiers,,Actif, 50,VALEURS MOBILIÈRES DE PLACEMENT,,Actif, 51,"BANQUES, ÉTABLISSEMENTS FINANCIERS ET ASSIMILÉS",,Actif, 511,Valeurs à l'encaissement,,Actif, 5112,Chèques à encaisser,,Actif,Attente d'encaissement 5115,Paiements par carte à encaisser,,Actif, 512,Banques,,Actif ou passif, 53,CAISSE,,Actif, 530,Caisse,,Actif,Caisse 54,RÉGIES D'AVANCES ET ACCRÉDITIFS,,Actif, 58,VIREMENTS INTERNES,,Actif, 59,PROVISIONS POUR DÉPRÉCIATION DES COMPTES FINANCIERS,,Actif, 6,Classe 6 — Comptes de charges,,Charge, 60,ACHATS,,Charge, 601,Achats stockés - Matières premières et fournitures,,Charge, 602,Achats stockés - Autres approvisionnements,,Charge, 604,Achat d'études et prestations de services,,Charge,Dépenses 606,Achats non stockés de matières et fournitures,,Charge, 6061,"Fournitures non stockables (eau, énergie...)","Facture d'eau, d'opérateur électrique, etc.",Charge,Dépenses 6063,Fournitures d'entretien et de petit équipement,,Charge,Dépenses 6064,Fournitures administratives,"Cartouches d'encre, papier, matériel bureautique, etc.",Charge,Dépenses 6068,Autres matières et fournitures,,Charge,Dépenses 607,Achats de marchandises,Marchandises destinées à être revendues en l'état.,Charge,Dépenses 61,SERVICES EXTÉRIEURS,,Charge, 611,Sous-traitance générale,,Charge, 612,Redevances de crédit-bail,,Charge, 613,Locations,Locations versées pour un local ou du matériel.,Charge,Dépenses 614,Charges locatives et de co-propriété,,Charge, 615,Entretiens et réparations,,Charge, 616,Primes d'assurance,,Charge,Dépenses 618,Divers,,Charge, 62,AUTRES SERVICES EXTÉRIEURS,,Charge, 621,Personnel extérieur à l'association,,Charge, 62141,Mises à disposition de personnel salarié,,Charge,Dépenses 622,Rémunérations d'intermédiaires et honoraires,,Charge, 6226,Honoraires,,Charge, 6227,Frais d'actes et de contentieux,"Insertion au Journal Officiel, frais de justice, etc.",Charge,Dépenses 6228,Divers,,Charge, 623,"Publicité, publications, relations publiques","Bulletins, affiches, communication, etc.",Charge,Dépenses 624,Transports de biens et transports collectifs du personnel,,Charge, 625,"Déplacements, missions et réceptions","Billet SNCF, remboursement de frais kilométrique, etc.",Charge,Dépenses 626,Frais postaux et de télécommunications,"Facture d'accès à Internet, timbres, etc.",Charge,Dépenses 627,Services bancaires et assimilés,Frais bancaires,Charge,Dépenses 628,Divers,,Charge,Dépenses 63,"IMPÔTS, TAXES ET VERSEMENTS ASSIMILÉS",,Charge, 631,"Impôts, taxes et versements assimilés sur rémunérations (Administration des impôts)",,Charge, 6311,Taxes sur les salaires,,Charge, 6313,Participations des employeurs à la formation professionnelle continue,,Charge, 635,"Autres impôts, taxes et versements assimilés (Administration des impôts)",,Charge, 6351,Impôts directs (sauf impôts sur les bénéfices),,Charge, 6353,Impôts indirects,,Charge, 637,"Autres impôts, taxes et versements assimilés (Autres organismes)",,Charge, 64,CHARGES DE PERSONNEL,,Charge, 641,Rémunérations du personnel,,Charge, 643,Rémunérations du personnel artistique et assimilés,,Charge, 645,Charges de sécurité sociale et de prévoyance,,Charge, 647,Autres charges sociales,,Charge, 648,Autres charges de personnel,,Charge, 65,AUTRES CHARGES DE GESTION COURANTE,,Charge, 652,Licences fédérales,Licences payées pour les adhérents (par exemple fédération sportive etc.),Charge,Dépenses 658,Charges diverses de gestion courante,,Charge,Dépenses 66,CHARGES FINANCIÈRES,,Charge, 661,Charges d'intérêts,,Charge, 67,CHARGES EXCEPTIONNELLES,,Charge, 670,Charges exceptionnelles,Autres dépenses exceptionnelles,Charge,Dépenses 671,Charges exceptionnelles sur opérations de gestion,,Charge, 6713,"Dons, libéralités",,Charge, 678,Autres charges exceptionnelles,,Charge, 6788,Charges exceptionnelles diverses,,Charge, 68,"DOTATIONS AUX AMORTISSEMENTS, DÉPRÉCIATIONS, PROVISIONS ET ENGAGEMENTS",,Charge, 681,"Dotations aux amortissements, dépréciations et provisions - Charges d'exploitation",,Charge, 6811,Dotations aux amortissements des immobilisations incorporelles et corporelles,,Charge, 68111,Immobilisations incorporelles,,Charge, 68112,Immobilisations corporelles,,Charge, 686,"Dotations aux amortissements, dépréciations et provisions - Charges financières",,Charge, 69,PARTICIPATION DES SALARIÉS - IMPÔTS SUR LES BÉNÉFICES ET ASSIMILÉS,,Charge, 695,Impôts sur les sociétés (y compris impôts sur les sociétés des personnes morales non lucratives),,Charge, 7,Classe 7 — Comptes de produits,,Produit, 70,"VENTES DE PRODUITS FINIS, PRESTATIONS DE SERVICES, MARCHANDISES",,Produit, 701,Ventes de produits finis,Vente de produits fabriqués par l'association.,Produit,Recettes 706,Prestations de services,,Produit,Recettes 707,Ventes de marchandises,,Produit,Recettes 708,Produits des activités annexes,,Produit, 71,PRODUCTION STOCKÉE (OU DÉSTOCKAGE),,Produit, 72,PRODUCTION IMMOBILISÉE,,Produit, 74,SUBVENTIONS D'EXPLOITATION,,Produit, 740,Subventions reçues,,Produit,Recettes 75,AUTRES PRODUITS DE GESTION COURANTE,,Produit, 754,Collectes,,Produit,Recettes 756,Cotisations,,Produit,Recettes 758,Produits divers de gestion courante,,Produit, 7587,Ventes de dons en nature,,Produit, 7588,Autres produits de la générosité du public,,Produit, 76,PRODUITS FINANCIERS,,Produit, 760,Produits financiers,,Produit, 77,PRODUITS EXCEPTIONNELS,,Produit, 771,Produits exceptionnels sur opérations de gestion,,Produit, 7713,Libéralités reçues,,Produit, 7715,Subventions d'équilibre,,Produit, 775,Produits des cessions d'éléments d'actifs,,Produit, 778,Autres produits exceptionnels,,Produit, 7780,Manifestations diverses,"Revenus provenant de manifestations au profit de l'association : droit d'entrée, location d'emplacement en vide grenier, ventes, etc.",Produit,Recettes 7788,Produits exceptionnels divers,,Produit, 78,REPRISES SUR AMORTISSEMENTS ET PROVISIONS,,Produit, 79,TRANSFERT DE CHARGES,,Produit, 791,Transferts de charges d'exploitation,,Produit, 796,Transferts de charges financières,,Produit, 797,Transferts de charges exceptionnels,,Produit, 8,Classe 8 — Comptes spéciaux,,, 86,RÉPARTITION PAR NATURE DE CHARGES,,Charge, 861,Mise à dispositions gratuites de biens,,Charge, 862,Prestations,,Charge, 864,Personnel bénévole,,Charge, 87,RÉPARTITION PAR NATURE DE RESSOURCES,,Produit, 870,Bénévolat,,Produit, 871,Prestations en nature,,Produit, 875,Dons en nature,,Produit, 89,BILAN,,, 890,Bilan d'ouverture,,,Ouverture 891,Bilan de clôture,,,Clôture 9,Classe 9 — Comptes analytiques,,, 99,Projets,,,Analytique |
Added src/include/data/charts/fr_2018.csv version [7724166e91].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | code,label,description,position,type 1,"Classe 1 — Comptes de capitaux (Fonds propres, emprunts et dettes assimilés)",,Passif, 10,FONDS ASSOCIATIFS ET RÉSERVES,,Passif, 102,Fonds associatifs sans droit de reprise,,Passif, 1021,Première situation nette établie,,Passif, 1022,Fonds statutaires,,Passif, 1023,Dotations non consomptibles,,Passif, 10231,Dotations non consomptibles initiales,,Passif, 10232,Dotations non consomptibles complémentaires,,Passif, 1024,Autres fonds propres sans droit de reprise,,Passif, 103,Fonds associatif avec droit de reprise,,Passif, 1032,Fonds statutaires,,Passif, 1034,Autres fonds propres avec droit de reprise,,Passif, 105,Ecarts de réévaluation,,Passif, 1051,Ecarts réévaluation sur biens sans dt reprise,,Passif, 1052,Ecarts réévaluation sur biens avec dt reprise,,Passif, 106,Réserves,,Passif, 1062,Réserves indisponibles,,Passif, 1063,Réserves statutaires,,Passif, 1064,Réserves réglementées,,Passif, 1068,Réserves pour projet de l’entité,,Passif, 108,Dotations consomptibles,,Passif, 1081,Dotations consomptibles,,Passif, 1089,Dot. consomptibles inscrites au cpte de résul,,Passif, 11,REPORT à NOUVEAU,,Passif, 110,Report à nouveau (Solde créditeur),,Passif, 119,Report à nouveau (Solde débiteur),,Passif, 12,RÉSULTAT NET DE L'EXERCICE,,Passif, 120,Résultat de l'exercice (excédent),,Passif,Résultat excédentaire 129,Résultat de l'exercice (déficit),,Passif,Résultat déficitaire 13,SUBVENTIONS D'INVESTISSEMENTS,,Passif, 131,Subventions d'équipement,,Passif, 139,Subventions inscrites au compte de résultat,,Passif, 14,PROVISIONS RÉGLEMENTÉES,,Passif, 148,Autres provisions réglementées,,Passif, 15,PROVISIONS POUR RISQUES ET CHARGES,,Passif, 151,Provisions pour risques,,Passif, 152,Provisions pour charges sur legs ou donations,,Passif, 153,Provisions pour pensions et obligations simil,,Passif, 155,Provisions pour impôts,,Passif, 157,Provisions pour charges à répartir,,Passif, 158,Autres provisions pour charges,,Passif, 16,EMPRUNTS ET DETTES ASSIMILÉES,,Passif, 163,Autres emprunts obligataires,,Passif, 1631,Titres associatifs et assimilés,,Passif, 164,Emprunts auprès des établissements de crédit,,Passif, 165,Dépôts et cautionnements reçus,,Passif, 1651,Dépôts,,Passif, 1655,Cautionnements,,Passif, 167,Emprunts et dettes sous conditions particulières,,Passif, 168,Autres emprunts et dettes assimilées,,Passif, 18,COMPTES DE LIAISONS,,Passif, 181,Apports permanents siège-établissements,,Passif, 185,Biens & PS échangés siège-établissements,,Passif, 186,Biens & PS entre établissements - Charges,,Passif, 187,Biens & PS entre établissements - Produits,,Passif, 19,FONDS DÉDIÉS OU REPORTÉS,,Passif, 191,Fonds reportés liés aux legs ou donations,,Passif, 1911,Legs ou donations,,Passif, 1912,Donations temporaires d’usufruit,,Passif, 194,Fonds dédiés sur subventions fonctionnement,,Passif, 195,F.d. / contributions financières autres org.,,Passif, 196,F.d. / ressources liées à la générosité,,Passif, 2,Classe 2 — Comptes d'immobilisations,,Actif, 20,IMMOBILISATIONS INCORPORELLES,,Actif, 201,Frais d'établissement,,Actif, 203,Frais de recherche et de développement,,Actif, 204,Donations temporaires d’usufruit,,Actif, 205,"Brevets, licences, marques...",,Actif, 206,Droit au bail,,Actif, 208,Autres immobilisations incorporelles,,Actif, 21,IMMOBILISATIONS CORPORELLES,,Actif, 211,Terrains,,Actif, 212,Agencements / aménagements de terrains,,Actif, 2131,Bâtiments,,Actif, 2135,"Installations, agencements...de constructions",,Actif, 214,Constructions sur sol d'autrui,,Actif, 215,"Installations techniques, matériel, outillage",,Actif, 2154,Matériel industriel,,Actif, 2155,Outillage industriel,,Actif, 218,Autres immobilisations corporelles,,Actif, 2181,"Installations, agencements, aménagem. divers",,Actif, 2182,Matériel de transport,,Actif, 2183,Matériel bureau et informatique,,Actif, 2184,Mobilier,,Actif, 23,IMMOBILISATIONS EN COURS,,Actif, 231,Immobilisations corporelles en cours,,Actif, 238,"Avances, acomptes sur immobilis. corporelles",,Actif, 24,BIEN DESTINÉS À ÊTRE CÉDÉS,,Actif, 240,Biens reçus par legs ou donations à céder,,Actif, 26,PARTICIPATIONS ET CRÉANCES RATTACHÉES,,Actif, 261,Titres de participation,,Actif, 266,Autres formes de participation,,Actif, 267,Créances rattachées à des participations,,Actif, 269,Versements restants sur participations,,Actif, 27,IMMOBILISATIONS FINANCIERES,,Actif, 271,Titres immobilisés (droit de propriété),,Actif, 272,Titres immobilisés (droit de créance),,Actif, 274,Prêts,,Actif, 2742,Prêts aux partenaires,,Actif, 275,Dépôts et cautionnements versés,,Actif, 276,Autres créances immobilisées,,Actif, 28,AMORTISSEMENTS DES IMMOBILISAT,,Actif, 2801,Amt. frais d'établissement,,Actif, 2804,Amt. donations temporaires d’usufruit,,Actif, 2805,"Amt brevets, licences, marques...",,Actif, 2806,Amt. droit au bail,,Actif, 2808,Amt. autres immo.incorporelles,,Actif, 2812,"Amt.agencements, aménagements de terrains",,Actif, 28131,Amortissements bâtiments,,Actif, 28135,"Amt. installations, agencements...",,Actif, 2814,Amt.constructions sur sol d'autrui,,Actif, 2815,"Amt instal. techniques, matériel, outillage",,Actif, 28181,"Amt. intallations, agencements, aménagements",,Actif, 28182,Amt. matériel de transport,,Actif, 28183,"Amortiss.matériel de bureau, informatique",,Actif, 28184,Amortissements du mobilier,,Actif, 29,DÉPRÉCIATIONS DES IMMOBILISATIONS,,Actif, 2904,Donations temporaires d'usufruit,,Actif, 2905,"Brevets, licences, marques...",,Actif, 2906,Droit au bail,,Actif, 2908,Autres immobilisations incorporelles,,Actif, 2911,Terrains,,Actif, 2931,Immobilisations corporelles en cours,,Actif, 294,Biens reçus par legs ou donations à céder,,Actif, 2961,Titres de participations,,Actif, 2966,Autres formes de participations,,Actif, 2967,Créances rattachées à des participations,,Actif, 2971,Titres immobilisés (droit de propriété),,Actif, 2972,Titres immobilisés (droit de créance),,Actif, 2974,Prêts,,Actif, 2975,Dépôts et cautionnements versés,,Actif, 2976,Autres créances immobilisées,,Actif, 3,Classe 3 — Comptes de stocks,,Actif, 31,MATIÈRES PREMIÈRES ET FOURNITURES,,Actif, 318,Matières premières et fournitures,,Actif, 32,AUTRES APPROVISIONNEMENTS,,Actif, 321,Matières consommables,,Actif, 322,Fournitures consommables,,Actif, 326,Emballages,,Actif, 33,EN-COURS DE PRODUCTION DE BIENS,,Actif, 331,Produits en cours,,Actif, 335,Travaux en cours,,Actif, 34,EN-COURS DE PROUCTION DE SERVICES,,Actif, 341,Etudes en cours,,Actif, 345,Prestations de services en cours,,Actif, 35,STOCKS DE PRODUITS,,Actif, 351,Produits intermédiaires,,Actif, 355,Produits finis,,Actif, 358,Produits résiduels,,Actif, 37,STOCKS DE MARCHANDISES,,Actif, 370,Stocks de marchandises,,Actif, 39,PROVISIONS PR DÉPRECIATIONS STOCKS & EN-COURS,,Actif, 391,Matières premières et fournitures,,Actif, 392,Autres approvisionnements,,Actif, 393,En-cours de production de biens,,Actif, 394,En-cours de production de services,,Actif, 395,Stocks de produits,,Actif, 397,Stocks de marchandises,,Actif, 4,Classe 4 — Comptes de tiers,,Actif ou passif, 40,FOURNISSEURS ET COMPTES RATTACHÉS,,Actif ou passif, 401,Fournisseurs,,Actif ou passif, 4010,Autres fournisseurs,,Actif ou passif,Tiers 403,Fournisseurs - Effets à payer,,Passif, 404,Fournisseurs d'immobilisations,,Actif ou passif, 405,Fournisseurs d'immos - Effets à payer,,Passif, 408,Fournisseurs - Factures non parvenues,,Passif, 4091,Fournisseurs - Avances & acomptes,,Actif, 41,USAGERS ET COMPTES RATTACHÉS,,Actif ou passif, 411,Usagers,,Actif ou passif, 4110,Autres usagers,Pour les dettes ou créances des membres,Actif ou passif,Tiers 413,Usagers - Effets à recevoir,,Actif, 416,Usagers douteux ou litigieux,,Actif, 418,Usagers non encore facturés,,Actif, 4191,Usagers créditeurs : Avances et acomptes,,Passif, 42,PERSONNEL ET COMPTES RATTACHÉS,,Actif ou passif, 421,Personnel : Rémunérations dues,,Passif, 4210,Autres membres du personnel,Dettes dûes aux salarié⋅e⋅s,Actif ou passif,Tiers 422,"Comités d'entreprise, d'établissement",,Actif ou passif, 425,Personnel : Avances & acomptes,,Actif, 427,Personnel - Oppositions,,Passif, 4286,Personnel- Charges à payer,,Passif, 4287,Personnel- Produits à recevoir,,Actif, 43,SÉCURITÉ SOCIALE & AUTRES ORGANISMES SOCIAUX,,Passif, 431,Sécurité sociale,,Passif, 4372,Mutuelles,,Passif, 4373,Caisses de retraites et de prévoyance,,Passif, 4378,Autres organismes sociaux,,Passif, 44,ETAT ET AUTRES COLLECTIVITÉS PUBLIQUES,,Actif, 441,Etat - Subventions à recevoir,,Actif, 4421,Prélèvements à la source- Impôt sur le revenu,,Actif ou passif, 444,Etat - Impôts sur les bénéfices,,Actif ou passif, 4452,TVA due intracommunautaire,,Actif ou passif, 4455,Taxes sur CA à décaisser,,Actif, 44562,TVA déductible sur immobilisations,,Actif, 44566,TVA déductible sur autres biens et services,,Actif, 44571,TVA normale collectée,,Actif, 445711,TVA réduite collectée,,Actif, 445712,TVA super-réduite collectée,,Actif, 445713,TVA intermédiaire collectée,,Actif, 4458,Taxe sur CA à régulariser ou en attente,,Actif, 447,"Autres impôts, taxes et versements assimilés",,Actif, 4486,Etat - Charges à payer,,Passif, 4487,Etat - Produits à recevoir,,Actif, 45,"CONFÉDÉRATION, FEDERATION, UNIONS...AFFILIÉES",,Actif ou passif, 451,"Confédération, fédération at assoc. affiliées",,Actif ou passif, 455,Partenaires - comptes courants,,Actif ou passif, 46,DEBITEURS DIVERS ET CREDIT.DVS,,Actif ou passif, 461,Créances reçues par legs ou donations,,Actif, 466,Dettes des legs ou donations,,Passif, 4671,Débiteurs divers,,Actif ou passif, 4672,Créditeurs divers,,Actif ou passif, 4681,Frais des bénévoles,,Actif ou passif, 4686,Divers - Charges à payer,,Passif, 4687,Divers - Produits à recevoir,,Actif, 47,COMPTES D'ATTENTE,,Actif ou passif, 4715,Compte de transit,,Actif ou passif, 4718,Compte d'attente,,Actif ou passif, 48,COMPTES DE REGULARISATION,,Actif ou passif, 481,Charges à répartir,,Passif, 486,Charges constatées d'avance,,Passif, 487,Produits constatés d'avance,,Actif, 49,DÉPRECIATIONS DES COMPTES DE TIERS,,Actif ou passif, 491,Prov. pour dépreciation des comptes d'usagers,,Passif, 496,Prov. pour dépreci. cptes débiteurs divers,,Passif, 5,Classe 5 — Comptes financiers,,Actif, 50,VALEURS MOBILIERES DE PLACEMENT,,Actif, 503,Actions,,Actif, 506,Obligations,,Actif, 508,Autres VMP et créances assimilées,,Actif, 51,"BANQUES, ETABLISSEMENTS FINANCIERS",,Actif, 5112,Chèques à encaisser,,Actif,Attente d'encaissement 5115,Paiements par carte à encaisser,,Actif, 512,Banques,,Actif ou passif, 5186,Intérêts courus à payer,,Passif, 5187,Intérêts courus à recevoir,,Actif, 53,Caisses,,Actif ou passif, 530,Caisse,,Actif,Caisse 58,VIREMENTS INTERNES,,Actif ou passif, 580,Virements internes,,Actif ou passif, 59,DEPRECIATIONS DES COMPTES FINANCIERS,,Actif ou passif, 5903,Actions,,Actif ou passif, 5906,Obligations,,Actif ou passif, 5908,Autres VMP et créances assimilées,,Actif ou passif, 6,Classe 6 — Comptes de charges,,Charge, 60,ACHATS (SAUF 603),,Charge, 601,Achats stockés - Matières premières et fournitures,,Charge, 6010,Achats stockés de matières et fournitures,,Charge, 6011,Achats stockés - Matières premières,,Charge, 6017,Achats stockés - Fournitures,,Charge, 602,Achats stockés - Autres approvisionnements,,Charge, 6021,Achats stockés - Matières consommables,,Charge, 60221,Achats stockés - Combustibles,,Charge, 60222,Achats stockés - Produits d'entretien,,Charge, 60223,Achats stockés - Fournitures d'atelier,,Charge, 60224,Achats stockés - Fournitures de magasin,,Charge, 60225,Fournitures de bureau,,Charge, 6026,Achats stockés - Emballages,,Charge, 603,Variations de stocks,,Charge, 6031,Variations de stocks matières & fournitures,,Charge, 6032,Variations stocks autres approvisionnements,,Charge, 6037,Variations de stocks de marchandises,,Charge, 604,Achats d'études et prestations de services,,Charge, 605,"Achats matériel, équipements & travaux",,Charge, 606,Achats non stockés de matières et fournitures,,Charge, 6061,"Fournitures non stockables (eau, énergie...)","Facture d'eau, d’électricité, etc.",Charge,Dépenses 60611,Eau,,Charge, 60612,Electricité,,Charge, 60613,Chauffage,,Charge, 6063,Fournitures d'entretien et petit équipement,"Vis, et matériel de bricolage (sauf outils) par exemple",Charge,Dépenses 6064,Fournitures administratives,"Cartouches d'encre, papier, matériel bureautique, etc.",Charge,Dépenses 6065,Petits logiciels,Par exemple contribution à un logiciel de gestion associative génial :-),Charge,Dépenses 6068,Autres fournitures & matières,,Charge,Dépenses 607,Achats de marchandises,Marchandises destinées à être revendues en l'état.,Charge,Dépenses 608,Frais accessoires d'achats,,Charge, 60811,Frais accessoires d'achats sur matières,,Charge, 60817,Frais accessoires d'achats sur fournitures,,Charge, 609,"Rabais, remises et ristournes sur achats",,Charge, 6091,RRR sur achats matières et fournitures,,Charge, 6092,RRR sur achats et autres approvisionnements,,Charge, 6097,RRR sur achats de marchandises,,Charge, 61,SERVICES EXTERIEURS,,Charge, 611,Sous-traitance générale,,Charge, 6122,Redevance crédit-bail mobilier,,Charge, 6125,Redevances crédit-bail immobilier,,Charge, 6132,Locations immobilières,Locations versées pour un local ou du matériel.,Charge,Dépenses 6135,Locations mobilières,,Charge, 6136,Malis sur emballages,,Charge, 614,Charges locatives et de copropriété,,Charge, 6152,Entretien sur biens immobiliers,,Charge, 6155,Entretien sur biens mobiliers,,Charge, 6156,Maintenance,,Charge, 616,Primes d'assurance,"Frais d’assurance local, activité, etc.",Charge,Dépenses 6161,Primes d'assurances mutirisques,,Charge, 6164,Primes d'assurances / risques d'exploitation,,Charge, 6165,Primes d'assurances / insolvabilité usagers,,Charge, 6168,Autres assurances,,Charge, 617,Etudes et recherches,,Charge, 6181,Documentation générale,,Charge, 6183,Documentation technique,,Charge, 6185,"Frais de colloques, séminaires, conférences",,Charge, 6187,Prestations administratives,,Charge, 62,AUTRES SERVICES EXTERIEURS,,Charge, 621,Personnel extérieur à l'association,,Charge, 6211,Personnel intérimaire,,Charge, 6214,Personnel détaché ou prêté à l'association,,Charge, 62141,Mises à disposition de personnel salarié,Frais de mise à disposition via un groupement d’employeurs,Charge,Dépenses 622,Rémunérations d'intermédiaires et honoraires,,Charge, 6221,Commissions ... sur achats,,Charge, 6222,Commissions... sur ventes,,Charge, 6226,Honoraires,,Charge, 62264,Honoraires sur legs ou donations à céder,,Charge, 6227,Frais d'actes et de contentieux,,Charge, 6228,Rémunérations div .intermédiaires & honor.,,Charge, 623,"Publicité, publications, relations publiques","Bulletins, affiches, communication, etc.",Charge,Dépenses 6231,Annonces et insertions,,Charge, 6232,Fêtes et cérémonies,,Charge, 6233,Foires et expositions,,Charge, 6234,Cadeaux,,Charge, 6236,Catalogues et imprimés,,Charge, 6237,Publications,,Charge, 6238,"Divers : pourboires, dons courants",,Charge, 624,Transports de biens...,,Charge, 6241,Transports sur achats,,Charge, 6242,Transports sur ventes,,Charge, 6243,Transports entre établissements,,Charge, 6244,Transports administratifs,,Charge, 6247,Transports collectifs du personnel,,Charge, 6248,Transports divers,,Charge, 625,"Déplacements, missions et réceptions","Billet de train, remboursement de frais kilométrique, etc.",Charge,Dépenses 6251,Voyages et déplacements,,Charge, 6255,Frais de déménagement,,Charge, 6256,Frais de missions,,Charge, 6257,"Frais de réceptions, représentations",,Charge, 626,Frais postaux et de télécommunications,"Facture d'accès à Internet, timbres, etc.",Charge,Dépenses 6261,Liaisons spécialisées,,Charge, 6263,"Affranchissements, frais postaux",,Charge, 6265,Téléphone,,Charge, 627,Services bancaires et assimilés,Frais bancaires,Charge,Dépenses 628,Divers,,Charge,Dépenses 6281,Cotisations (liées à l'activité économique),,Charge, 6284,Frais de recrutement du personnel,,Charge, 63,"IMPÔTS, TAXES ET VERSEMENTS ASSIMILÉS",,Charge, 631,Sur rémunérations - administration des impôts,,Charge, 6311,Taxe sur les salaires,,Charge, 633,Sur rémunérations - autres organismes,,Charge, 6331,Versement de transport,,Charge, 6332,Allocation logement,,Charge, 6333,Formation professionnelle continue,,Charge, 6334,Participations employeurs à l'effort de const,,Charge, 635,Autres - Administration des impôts,,Charge, 63512,Taxes foncières,,Charge, 63513,Autres impôts locaux,,Charge, 6354,Droits d'enregistrement et de timbre,,Charge, 637,Autres - Autres organismes,,Charge, 64,CHARGES DE PERSONNEL,,Charge, 641,Rémunérations du personnel,,Charge, 6411,"Salaires, appointements",,Charge, 6412,Congés payés,,Charge, 6413,Primes et gratifications,,Charge, 6414,Indemnités et avantages divers,,Charge, 6415,Supplément familial,,Charge, 645,Charges de sécurité sociale et de prévoyance,,Charge, 6451,Cotisations à l'URSSAF,,Charge, 6452,Cotisations aux mutuelles,,Charge, 6453,Cotisations caisses de retraites et de prévoy,,Charge, 6458,Cotisations aux autres organismes sociaux,,Charge, 647,Autres charges sociales,,Charge, 6472,Versements aux comités d'entreprise et d'étab,,Charge, 6473,Versement aux comités d'hygiène et de sécurit,,Charge, 6474,Versements aux autres oeuvres sociales,,Charge, 6475,"Médecine du travail, pharmacie",,Charge, 648,Autres charges de personnel,,Charge, 6481,Indemnités du personnel de culte,,Charge, 6485,Charges sociales sur indemnités de culte,,Charge, 6488,Autres charges de personnel,,Charge, 65,AUTRES CHARGES DE GESTION COURANTE,,Charge, 6511,"Redevances pour concessions, brevets, licenc.",,Charge, 6516,Droits d'auteur et de reproduction,,Charge, 6518,Autres droits et valeurs similaires,,Charge, 652,Licences fédérales,Licences payées pour les adhérents (par exemple fédération sportive etc.),Charge,Dépenses 653,Charges de la générosité du public,,Charge, 6531,Autres charges sur legs ou donations,,Charge, 654,Pertes sur créances irrécouvrables,,Charge, 655,Quotes-parts sur opérations faites en commun,,Charge, 657,Aides financières,,Charge, 6571,Aides financières octroyées,,Charge, 6572,Quotes-parts de générosité reversée,,Charge, 658,Charges diverses de gestion courante,,Charge,Dépenses 6586,Cotisations (vie statutaire),,Charge, 6588,Charges diverses de gestion courante,,Charge, 66,CHARGES FINANCIERES,,Charge, 661,Charges d'intérêts,,Charge, 665,Escomptes accordés,,Charge, 666,Pertes de changes,,Charge, 667,Charges nettes sur cessions de VMP,,Charge, 668,Autres charges financières,,Charge, 67,CHARGES EXEPTIONNELLES,,Charge, 670,Charges exceptionnelles,Autres dépenses exceptionnelles,Charge,Dépenses 6712,"Pénalités, amendes fiscales at pénales",,Charge, 6713,"Dons, libéralités",,Charge, 6714,Créances devenues irrécouvrables,,Charge, 6718,Autres charges exceptionnelles de gestion,,Charge, 673,Apports ou affectations en numéraire,,Charge, 675,Valeurs comptables des éléments d'actifs cédés,,Charge, 6750,Valeurs comptables des actifs cédés,,Charge, 6754,Immobilisations reçues par legs ou donations,,Charge, 678,Autres charges exceptionnelles sur opération en capital,,Charge, 68,"DOT. AUX AMORTISS., DÉPRÉC. ET ENGAGEMENTS",,Charge, 6811,Dot. aux amortissements des immobilisations,,Charge, 6812,Dot. aux amortissements charges à répartir,,Charge, 6815,Dot. aux provisions d'exploitation,,Charge, 6816,Dot. provisions pour dépréciations des immos,,Charge, 68164,Dot. pr dépréc. d’actifs reçus par legs ou donations,,Charge, 6817,Dot. aux dépréciations des actifs circulants,,Charge, 68173,Dotations dépréciations stocks et en-cours,,Charge, 68174,Dotations dépréciations créances,,Charge, 686,Dot. aux amort. & prov. - Charges financières,,Charge, 68662,Dot. aux amort. & prov immos financières,,Charge, 68665,Dot. aux amort. & prov VMP,,Charge, 687,Dot. aux amort. & prov. - Charges exceptionn.,,Charge, 689,Reports en fonds dédiés,,Charge, 6891,Reports en fonds reportés,,Charge, 6894,Reports en fonds dédiés / subventions d’exploitation,,Charge, 6895,Reports en fds dédiés / contributions financières d'autres organismes,,Charge, 6896,Reports en fds dédiés / ressources générosité,,Charge, 69,IMPÔTS SUR LES BENEFICES,,Charge, 695,IS sur personnes non lucratives,,Charge, 7,Classe 7 — Comptes de produits,,Produit, 70,"VENTES PROD.FINIS, MARCHANDISES, PRESTATIONS",,Produit, 701,Ventes de produits finis,Vente de produits fabriqués par l'association.,Produit,Recettes 702,Ventes de produits intermédiaires,,Produit, 703,Ventes de produits résiduels,,Produit, 704,Travaux,,Produit, 705,Etudes,,Produit, 706,Prestations de services,,Produit,Recettes 7063,Parrainages,,Produit, 707,Ventes de marchandises,Ventes de produits achetés et revendus en l’état,Produit,Recettes 7073,Ventes de dons en nature,,Produit, 708,Produits des activités annexes,,Produit, 7081,Produits des prestations fournies au personne,,Produit, 7083,Locations diverses,,Produit, 7085,Ports et frais accessoires facturés,,Produit, 7088,Autres produits d'activités annexes,,Produit, 709,RRR accordés,,Produit, 7091,RRR sur ventes de produits finis,,Produit, 7092,RRR sur ventes de produits intermédiaires,,Produit, 7094,RRR sur travaux,,Produit, 7095,RRR sur études,,Produit, 7096,RRR sur prest.de services,,Produit, 7097,RRR sur ventes marchandises,,Produit, 71,PRODUCTION STOCKEE,,Produit, 713,"Variation de stocks (en-cours, productions)",,Produit, 7133,Variation des en-cours de production de biens,,Produit, 7134,Variation des en-cours de production services,,Produit, 7135,Variations de stocks de produits,,Produit, 72,PRODUCTION IMMOBILISEE,,Produit, 721,Production immobilisée incorporelle,,Produit, 722,Production immobilisée corporelle,,Produit, 73,CONCOURS PUBLICS,,Produit, 730,Concours publics,,Produit, 74,SUBVENTION D'EXPLOITATION,,Produit, 740,Subventions reçues,,Produit,Recettes 748,Subventions d'exploitation diverses,,Produit, 75,AUTRES PRODUITS DE GESTION COURANTE,,Produit, 751,"Redevances pour concessions, licences...",,Produit, 753,Versements des fondateurs ou consommation dot,,Produit, 7531,Versements des fondateurs,,Produit, 7532,Quotes-parts de dotation consomptible virée a,,Produit, 754,Ressources liées à la générosité du public,Dons reçus,Produit,Recettes 7541,Dons manuels,,Produit, 75411,Dons manuels,,Produit, 75412,Abandons de frais par les bénévoles,,Produit, 7542,Mécénats,,Produit, 7543,"Legs, donations et assurances-vie",,Produit, 75431,Assurances-vie,,Produit, 75432,Legs ou donations,,Produit, 75433,Autres produits sur legs ou donations,,Produit, 755,Contributions financières,,Produit, 7551,Contributions financières d’autres organismes,,Produit, 7552,Quotes-parts de générosité reçues,,Produit, 756,Cotisations,Cotisations des adherent⋅e⋅s,Produit,Recettes 7561,Cotisations sans contrepartie,,Produit, 7562,Cotisations avec contrepartie,,Produit, 757,Gains de change / créances et dettes d’exploitation,,Produit, 758,Produits divers de gestion courante,,Produit, 7588,Autres produits divers de gestion courante,,Produit, 76,PRODUITS FINANCIERS,,Produit, 761,Produits des participations,,Produit, 762,Produits des autres immobilisat. financières,,Produit, 763,Revenus des autres créances,,Produit, 764,Revenus des VMP,,Produit, 765,Escomptes obtenus,,Produit, 766,Gains de change,,Produit, 767,Produits nets sur cession VMP,,Produit, 768,Autres produits financiers,,Produit, 77,PRODUITS EXCEPTIONNELS,,Produit, 771,Produits exception. sur opération de gestion,,Produit, 7713,Libéralités perçues,,Produit, 7718,Autres produits exception. sur op. de gestion,,Produit, 775,Produits des cessions d'actif,,Produit, 7754,Immos reçues en legs ou donations à céder,,Produit, 777,QP subvention d'investissement virée au résul,,Produit, 778,Autres produits exceptionnels,,Produit, 7780,Manifestations diverses,"Revenus provenant de manifestations au profit de l'association : droit d'entrée, location d'emplacement en vide grenier, ventes, etc.",Produit,Recettes 78,"REPRISES SUR AMORT., DÉPRÉC., ENGAGEMENTS",,Produit, 781,Reprises / amt & prov. d'exploitation,,Produit, 7811,Amt immos corporelles & incorporelles,,Produit, 7815,Reprises sur provisions d'exploitation,,Produit, 7816,Déprec. immos corporelles & incorporelles,,Produit, 78164,Reprises dépréc. d’actifs reçus par legs ou donations destinés à être cédés,,Produit, 7817,Dépréciations actifs circulant,,Produit, 786,Reprises / amt & prov. financiers,,Produit, 7865,Risques & charges financiers,,Produit, 7866,Déprec.des éléments financiers,,Produit, 787,Reprises sur amt & prov. exceptionnelles,,Produit, 7872,Provisions réglementées - Immobilisations,,Produit, 7873,Provisions réglementées - stocks,,Produit, 7874,Autres provisions réglementées,,Produit, 7875,Risques et charges,,Produit, 7876,Dépréciations exceptionnelles,,Produit, 789,Utilisations fds reportés et de fds dédiés,,Produit, 7891,Utilisations de fonds reportés,,Produit, 7894,Utilisations des fonds dédiés / subventions,,Produit, 7895,Utilisations des fds dédiés / contributions,,Produit, 7896,Utilisations des fds dédiés / générosité,,Produit, 79,TRANSFERT DE CHARGES,,Produit, 791,Transferts de charges d'exploitation,,Produit, 796,Transferts de charges financières,,Produit, 797,Transferts de charges exceptionnelles,,Produit, 8,Classe 8 — Comptes spéciaux,,, 86,EMPLOIS CONTRIBUTIONS VOLONTAIRES EN NATURE,,, 860,Secours en nature,,, 8601,Alimentaires,,, 8602,Vestimentaires,,, 861,Mise à dispositions gratuites de biens,,, 8611,Locaux,,, 8612,Matériels,,, 862,Prestations,,, 864,Personnel bénévole,,, 87,CONTRIBUTIONS VOLONTAIRES EN NATURE,,, 870,Dons en nature,,, 871,Prestations en nature,,, 875,Bénévolat,,,Bénévolat 89,COMPTES DE BILAN,,, 890,Bilan d'ouverture,,,Ouverture 891,Bilan de clôture,,,Clôture 9,Classe 9 — Comptes analytiques,,, 90,COMPTES RÉFLÉCHIS,,, 906,Charges réfléchies,,, 907,Produits réfléchis,,, 99,Projets,,,Analytique |
Deleted src/include/data/plan_comptable.json version [4d7e33a414].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/include/data/schema.sql from [c8df01c2dd] to [bdddcd8200].
|
| < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 | 1.0.0_schema.sql |
Modified src/include/init.php from [d8b3de9018] to [94cb9d23a4].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace Garradin; use KD2\ErrorManager; use KD2\Security; use KD2\Form; error_reporting(-1); /* * Version de Garradin */ function garradin_version() { | > | | | | | | | | | | | | | | | | | | | | | > > > > > | | | < < < < < < < < < < < < < < < < < < | < < < < < | | | | | | | | | | | | | | | < < < < < < | | < | < | | | | | < < | | | | | | | | | | | | > > | > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | < < < < < | | | | | | | | | > > > > | | | | | < | < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < | < < < < | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | <?php namespace Garradin; use KD2\ErrorManager; use KD2\Security; use KD2\Form; use KD2\DB\EntityManager; error_reporting(-1); /* * Version de Garradin */ function garradin_version() { if (defined('Garradin\VERSION')) { return VERSION; } $file = __DIR__ . '/../VERSION'; if (file_exists($file)) { $version = trim(file_get_contents($file)); } else { $version = 'unknown'; } define('Garradin\VERSION', $version); return $version; } function garradin_manifest() { $file = __DIR__ . '/../../manifest.uuid'; if (@file_exists($file)) { return substr(trim(file_get_contents($file)), 0, 10); } return false; } if (!defined('\SQLITE3_OPEN_READWRITE')) { echo 'Le module de base de données SQLite3 n\'est pas disponible.' . PHP_EOL; exit(1); } /* * Configuration globale */ // Configuration externalisée if (file_exists(__DIR__ . '/../config.local.php')) { require __DIR__ . '/../config.local.php'; } // Configuration par défaut, si les constantes ne sont pas définies dans config.local.php // (fallback) if (!defined('Garradin\ROOT')) { define('Garradin\ROOT', dirname(__DIR__)); } \spl_autoload_register(function (string $classname) { $classname = ltrim($classname, '\\'); // Plugins if (substr($classname, 0, 16) == 'Garradin\\Plugin\\') { $classname = substr($classname, 16); $plugin_name = substr($classname, 0, strpos($classname, '\\')); $filename = str_replace('\\', '/', substr($classname, strpos($classname, '\\')+1)); $path = Plugin::getPath(strtolower($plugin_name)) . '/lib/' . $filename . '.php'; } else { // PSR-0 autoload $filename = str_replace('\\', '/', $classname); $path = ROOT . '/include/lib/' . $filename . '.php'; } if (file_exists($path)) { require_once $path; } }, true); if (!defined('Garradin\DATA_ROOT')) { define('Garradin\DATA_ROOT', ROOT); } if (!defined('Garradin\WWW_URI')) { try { $uri = \KD2\HTTP::getRootURI(ROOT); } catch (\UnexpectedValueException $e) { $uri = null; } if ($uri == '/www/') { $uri = '/'; } elseif ($uri !== null) { readfile(ROOT . '/sous-domaine.html'); exit; } define('Garradin\WWW_URI', $uri); unset($uri); } if (!defined('Garradin\WWW_URL')) { $host = \KD2\HTTP::getHost(); } if (WWW_URI === null || (!empty($host) && $host == 'host.unknown')) { $title = 'Impossible de détecter automatiquement l\'URL du site web.'; $info = 'Consulter l\'aide pour configurer manuellement l\'URL avec la directive WWW_URL et WWW_URI.'; $url ='https://fossil.kd2.org/garradin/wiki?name=Installation'; if (PHP_SAPI == 'cli') { printf("\n/!\\ %s\n%s\n-> %s\n\n", $title, $info, $url); } else { printf('<h2 style="color: red">%s</h2><p><a href="%s">%s</a></p>', $title, $url, $info); } exit(1); } if (!defined('Garradin\WWW_URL')) { define('Garradin\WWW_URL', \KD2\HTTP::getScheme() . '://' . $host . WWW_URI); } static $default_config = [ 'CACHE_ROOT' => DATA_ROOT . '/cache', 'DB_FILE' => DATA_ROOT . '/association.sqlite', 'DB_SCHEMA' => ROOT . '/include/data/schema.sql', 'PLUGINS_ROOT' => DATA_ROOT . '/plugins', 'PREFER_HTTPS' => false, 'ALLOW_MODIFIED_IMPORT' => true, 'PLUGINS_SYSTEM' => '', 'SHOW_ERRORS' => true, 'MAIL_ERRORS' => false, 'ERRORS_REPORT_URL' => null, 'ERRORS_ENABLE_LOG_VIEW'=> true, 'USE_CRON' => false, 'ENABLE_XSENDFILE' => false, 'SMTP_HOST' => false, 'SMTP_USER' => null, 'SMTP_PASSWORD' => null, 'SMTP_PORT' => 587, 'SMTP_SECURITY' => 'STARTTLS', 'ADMIN_URL' => WWW_URL . 'admin/', 'NTP_SERVER' => 'fr.pool.ntp.org', 'ENABLE_AUTOMATIC_BACKUPS' => true, 'ADMIN_COLOR1' => '#9c4f15', 'ADMIN_COLOR2' => '#d98628', 'ADMIN_BACKGROUND_IMAGE' => WWW_URL . 'admin/static/gdin_bg.png' ]; foreach ($default_config as $const => $value) { $const = sprintf('Garradin\\%s', $const); if (!defined($const)) { define($const, $value); } } const WEBSITE = 'https://fossil.kd2.org/garradin/'; const PLUGINS_URL = 'https://garradin.eu/plugins/list.json'; // PHP devrait être assez intelligent pour chopper la TZ système mais nan // il sait pas faire (sauf sur Debian qui a le bon patch pour ça), donc pour // éviter le message d'erreur à la con on définit une timezone par défaut // Pour utiliser une autre timezone, il suffit de définir date.timezone dans // un .htaccess ou dans config.local.php if (!ini_get('date.timezone')) { if (($tz = @date_default_timezone_get()) && $tz != 'UTC') { ini_set('date.timezone', $tz); } else { ini_set('date.timezone', 'Europe/Paris'); } } /* * Gestion des erreurs et exceptions */ class UserException extends \LogicException { } class ValidationException extends UserException { } // activer le gestionnaire d'erreurs/exceptions ErrorManager::enable(SHOW_ERRORS ? ErrorManager::DEVELOPMENT : ErrorManager::PRODUCTION); ErrorManager::setLogFile(DATA_ROOT . '/error.log'); // activer l'envoi de mails si besoin est if (MAIL_ERRORS) { ErrorManager::setEmail(MAIL_ERRORS); } ErrorManager::setContext([ 'rootDirectory' => ROOT, 'garradin_data_root' => DATA_ROOT, 'garradin_version' => garradin_version(), ]); if (ERRORS_REPORT_URL) { ErrorManager::setRemoteReporting(ERRORS_REPORT_URL, true); } ErrorManager::setProductionErrorTemplate('<!DOCTYPE html><html><head><title>Erreur interne</title> <style type="text/css"> body {font-family: sans-serif; } code, p, h1 { max-width: 400px; margin: 1em auto; display: block; } code { text-align: right; color: #666; } a { color: blue; } form { text-align: center; } </style></head><body><h1>Erreur interne</h1><p>Désolé mais le serveur a rencontré une erreur interne et ne peut répondre à votre requête. Merci de ré-essayer plus tard.</p> <p>Si vous suspectez un bug dans Garradin, vous pouvez suivre <a href="http://dev.kd2.org/garradin/Rapporter+un+bug">ces instructions</a> pour le rapporter.</p> <if(sent)><p>Un-e responsable a été notifié-e et cette erreur sera corrigée dès que possible.</p></if> <if(logged)><code>L\'erreur a été enregistrée dans les journaux système (error.log) sous la référence : <b>{$ref}</b></code></if> <p><a href="' . WWW_URL . '">← Retour à la page d\'accueil</a></p> </body></html>'); ErrorManager::setHtmlHeader('<!DOCTYPE html><meta charset="utf-8" /><style type="text/css"> body { font-family: sans-serif; } * { margin: 0; padding: 0; } u, code b, i, h3 { font-style: normal; font-weight: normal; text-decoration: none; } #icn { color: #fff; font-size: 2em; float: right; margin: 1em; padding: 1em; background: #900; border-radius: 50%; } section header { background: #fdd; padding: 1em; } section article { margin: 1em; } section article h3, section article h4 { font-size: 1em; font-family: mono; } code { border: 1px dotted #ccc; display: block; } code b { margin-right: 1em; color: #999; } code u { background: #fcc; display: inline-block; width: 100%; } table { border-collapse: collapse; margin: 1em; } td, th { border: 1px solid #ccc; padding: .2em .5em; text-align: left; vertical-align: top; } input { padding: .3em; margin: .5em; font-size: 1.2em; cursor: pointer; } </style> <pre id="icn"> \__/<br /> (xx)<br />//||\\\\</pre> <section> <article> <h1>Une erreur s\'est produite</h1> <if(report)><form method="post" action="{$report_url}"><p><input type="hidden" name="report" value="{$report_json}" /><input type="submit" value="Rapporter l\'erreur aux développeur⋅euses de Garradin →" /></p></form></if> </article> </section> '); function user_error(\Exception $e) { if (PHP_SAPI == 'cli') { echo $e->getMessage(); } else { $tpl = Template::getInstance(); $tpl->assign('error', $e->getMessage()); $tpl->assign('admin_url', ADMIN_URL); $tpl->display('error.tpl'); } exit; } // Message d'erreur simple pour les erreurs de l'utilisateur ErrorManager::setCustomExceptionHandler('\Garradin\UserException', '\Garradin\user_error'); ErrorManager::setCustomExceptionHandler('\KD2\MiniSkelMarkupException', '\Garradin\user_error'); // Clé secrète utilisée pour chiffrer les tokens CSRF etc. if (!defined('Garradin\SECRET_KEY')) { $key = base64_encode(random_bytes(64)); Install::setLocalConfig('SECRET_KEY', $key); define('Garradin\SECRET_KEY', $key); } // Intégration du secret pour les tokens Form::tokenSetSecret(SECRET_KEY); EntityManager::setGlobalDB(DB::getInstance()); /* * Vérifications pour enclencher le processus d'installation ou de mise à jour */ if (!defined('Garradin\INSTALL_PROCESS') && !defined('Garradin\UPGRADE_PROCESS')) { if (!file_exists(DB_FILE)) { Utils::redirect(ADMIN_URL . 'install.php'); } $config = Config::getInstance(); if (version_compare($config->getVersion(), garradin_version(), '<')) { Utils::redirect(ADMIN_URL . 'upgrade.php'); } } |
Added src/include/lib/Garradin/Accounting/Accounts.php version [104aa964ca].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | <?php namespace Garradin\Accounting; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Line; use Garradin\Entities\Accounting\Transaction; use Garradin\Entities\Accounting\Year; use Garradin\CSV; use Garradin\DB; use Garradin\Utils; use KD2\DB\EntityManager; class Accounts { protected $chart_id; protected $em; const EXPECTED_CSV_COLUMNS = ['code', 'label', 'description', 'position', 'type']; public function __construct(int $chart_id) { $this->chart_id = $chart_id; $this->em = EntityManager::getInstance(Account::class); } static public function get(int $id) { return EntityManager::findOneById(Account::class, $id); } static public function getSelectorLabel(int $id) { return EntityManager::getInstance(Account::class)->col('SELECT code || \' — \' || label FROM @TABLE WHERE id = ?;', $id); } public function getIdFromCode(string $code): int { return $this->em->col('SELECT id FROM @TABLE WHERE code = ? AND id_chart = ?;', $code, $this->chart_id); } /** * Return common accounting accounts from current chart * (will not return analytical and volunteering accounts) */ public function listCommonTypes(): array { return $this->em->all('SELECT * FROM @TABLE WHERE id_chart = ? AND type != 0 AND type NOT IN (?, ?) ORDER BY code COLLATE NOCASE;', $this->chart_id, Account::TYPE_ANALYTICAL, Account::TYPE_VOLUNTEERING); } /** * Return all accounts from current chart */ public function listAll(): array { return $this->em->all('SELECT * FROM @TABLE WHERE id_chart = ? ORDER BY code COLLATE NOCASE;', $this->chart_id); } public function listForCodes(array $codes): array { return DB::getInstance()->getGrouped('SELECT code, id, label FROM acc_accounts WHERE id_chart = ?;', $this->chart_id); } /** * Return all accounts from current chart */ public function export(): \Generator { $res = $this->em->DB()->iterate($this->em->formatQuery('SELECT code, label, description, position, type FROM @TABLE WHERE id_chart = ? ORDER BY code COLLATE NOCASE;'), $this->chart_id); foreach ($res as $row) { $row->type = Account::TYPES_NAMES[$row->type]; $row->position = Account::POSITIONS_NAMES[$row->position]; yield $row; } } /** * Return only analytical accounts */ public function listAnalytical(): array { return $this->em->DB()->getAssoc($this->em->formatQuery('SELECT id, label FROM @TABLE WHERE id_chart = ? AND type = ? ORDER BY code COLLATE NOCASE;'), $this->chart_id, Account::TYPE_ANALYTICAL); } /** * Return only analytical accounts */ public function listVolunteering(): array { return $this->em->all('SELECT * FROM @TABLE WHERE id_chart = ? AND type = ? ORDER BY code COLLATE NOCASE;', $this->chart_id, Account::TYPE_VOLUNTEERING); } /** * List common accounts, grouped by type * @return array */ public function listCommonGrouped(array $types = null): array { if (null === $types) { $types = ''; } else { $types = array_map('intval', $types); $types = ' AND ' . $this->em->DB()->where('type', $types); } $out = []; $query = $this->em->iterate('SELECT * FROM @TABLE WHERE id_chart = ? AND type != 0 ' . $types . ' ORDER BY type, code COLLATE NOCASE;', $this->chart_id); foreach ($query as $row) { if (!isset($out[$row->type])) { $out[$row->type] = (object) [ 'label' => Account::TYPES_NAMES[$row->type], 'type' => $row->type, 'accounts' => [], ]; } $out[$row->type]->accounts[] = $row; } return $out; } public function getNextCodesForTypes(): array { $db = DB::getInstance(); $codes = $db->getAssoc(sprintf('SELECT type, MAX(code) FROM %s WHERE id_chart = ? AND type > 0 GROUP BY type;', Account::TABLE), $this->chart_id); foreach ($codes as &$code) { if (($letter = substr($code, -1)) && !is_numeric($letter)) { $code = substr($code, 0, -1); $letter = strtoupper($letter); $letter = ($letter == 'Z') ? 'AA' : chr(ord($letter)+1); } else { $letter = 'A'; } $code = $code . $letter; } unset($code); return $codes; } public function copyFrom(int $id) { $db = DB::getInstance(); return $db->exec(sprintf('INSERT INTO %s (id_chart, code, label, description, position, type, user) SELECT %d, code, label, description, position, type, user FROM %1$s WHERE id_chart = %d;', Account::TABLE, $this->chart_id, $id)); } public function importUpload(array $file) { if (empty($file['size']) || empty($file['tmp_name'])) { throw new UserException('Fichier invalide'); } self::importCSV($file['tmp_name']); } public function importCSV(string $file): void { $db = DB::getInstance(); $positions = array_flip(Account::POSITIONS_NAMES); $types = array_flip(Account::TYPES_NAMES); $db->begin(); try { foreach (CSV::import($file, self::EXPECTED_CSV_COLUMNS) as $line => $row) { $account = new Account; $account->id_chart = $this->chart_id; try { $row['position'] = $positions[$row['position']]; $row['type'] = $types[$row['type']]; $account->importForm($row); $account->save(); } catch (ValidationException $e) { throw new UserException(sprintf('Ligne %d : %s', $line, $e->getMessage())); } } $db->commit(); } catch (\Exception $e) { $db->rollback(); throw $e; } } public function countByType(int $type) { return DB::getInstance()->count(Account::TABLE, 'id_chart = ? AND type = ?', $this->chart_id, $type); } public function getSingleAccountForType(int $type) { return DB::getInstance()->first('SELECT * FROM acc_accounts WHERE type = ? AND id_chart = ? LIMIT 1;', $type, $this->chart_id); } /* FIXME: implement closing of accounts public function getClosingAccountId() { return DB::getInstance()->firstColumn('SELECT id FROM acc_accounts WHERE type = ? AND id_chart = ?;', Account::TYPE_CLOSING, $this->chart_id); } public function closeRevenueExpenseAccounts(Year $year, int $user_id) { $closing_id = $this->getClosingAccountId(); if (!$closing_id) { throw new UserException('Aucun compte n\'est indiqué comme compte de clôture dans le plan comptable'); } $transaction = new Transaction; $transaction->id_creator = $user_id; $transaction->id_year = $year->id(); $transaction->type = Transaction::TYPE_ADVANCED; $transaction->label = 'Clôture de l\'exercice'; $transaction->date = new \DateTime; $debit = 0; $credit = 0; $sql = 'SELECT a.id, SUM(l.credit - l.debit) AS sum, a.position, a.code FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction INNER JOIN acc_accounts a ON a.id = l.id_account WHERE t.id_year = ? AND a.position IN (?, ?) GROUP BY a.id ORDER BY a.code;'; $res = DB::getInstance()->iterate($sql, $year->id(), Account::REVENUE, Account::EXPENSE); foreach ($res as $row) { $reversed = $row->position == Account::ASSET; $line = new Line; $line->id_account = $row->id; $line->credit = $reversed ? abs($row->sum) : 0; $line->debit = !$reversed ? abs($row->sum) : 0; $transaction->addLine($line); if ($reversed) { $debit += abs($row->sum); } else { $credit += abs($row->sum); } } if ($debit) { $line = new Line; $line->id_account = $closing_id; $line->credit = 0; $line->debit = $debit; $transaction->addLine($line); } if ($credit) { $line = new Line; $line->id_account = $closing_id; $line->credit = $credit; $line->debit = 0; $transaction->addLine($line); } $transaction->save(); } */ } |
Added src/include/lib/Garradin/Accounting/Charts.php version [23502d0c8f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <?php namespace Garradin\Accounting; use Garradin\Entities\Accounting\Chart; use Garradin\Utils; use Garradin\DB; use KD2\DB\EntityManager; class Charts { static public function get(int $id) { return EntityManager::findOneById(Chart::class, $id); } static public function list() { $em = EntityManager::getInstance(Chart::class); return $em->all('SELECT * FROM @TABLE ORDER BY country, label;'); } static public function listAssoc() { return DB::getInstance()->getAssoc(sprintf('SELECT id, country || \' - \' || label FROM %s ORDER BY country, label;', Chart::TABLE)); } static public function listByCountry() { $sql = sprintf('SELECT id, country, label FROM %s ORDER BY country, label;', Chart::TABLE); $list = DB::getInstance()->getGrouped($sql); $out = []; foreach ($list as $row) { $country = Utils::getCountryName($row->country); if (!array_key_exists($country, $out)) { $out[$country] = []; } $out[$country][$row->id] = $row->label; } return $out; } } |
Added src/include/lib/Garradin/Accounting/Graph.php version [a1b33675d1].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | <?php namespace Garradin\Accounting; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Line; use Garradin\Entities\Accounting\Transaction; use Garradin\Utils; use Garradin\Config; use Garradin\DB; use const Garradin\ADMIN_COLOR1; use const Garradin\ADMIN_COLOR2; use const Garradin\ADMIN_URL; use KD2\DB\EntityManager; use KD2\Graphics\SVG\Plot; use KD2\Graphics\SVG\Plot_Data; use KD2\Graphics\SVG\Pie; use KD2\Graphics\SVG\Pie_Data; class Graph { const URL_LIST = [ ADMIN_URL . 'acc/reports/graph_plot.php?type=assets&%s' => 'Évolution banques et caisses', ADMIN_URL . 'acc/reports/graph_plot.php?type=result&%s' => 'Évolution dépenses et recettes', ADMIN_URL . 'acc/reports/graph_plot.php?type=debts&%s' => 'Évolution créances (positif) et dettes (négatif)', ADMIN_URL . 'acc/reports/graph_pie.php?type=revenue&%s' => 'Répartition recettes', ADMIN_URL . 'acc/reports/graph_pie.php?type=expense&%s' => 'Répartition dépenses', ADMIN_URL . 'acc/reports/graph_pie.php?type=assets&%s' => 'Répartition actif', ]; const PLOT_TYPES = [ 'assets' => [ 'Total' => ['type' => [Account::TYPE_BANK, Account::TYPE_CASH, Account::TYPE_OUTSTANDING]], 'Banques' => ['type' => Account::TYPE_BANK], 'Caisses' => ['type' => Account::TYPE_CASH], 'En attente' => ['type' => Account::TYPE_OUTSTANDING], ], 'result' => [ 'Recettes' => ['position' => Account::REVENUE], 'Dépenses' => ['position' => Account::EXPENSE], ], 'debts' => [ 'Comptes de tiers' => ['type' => Account::TYPE_THIRD_PARTY], ], ]; const PIE_TYPES = [ 'revenue' => ['position' => Account::REVENUE], 'expense' => ['position' => Account::EXPENSE], 'assets' => ['type' => [Account::TYPE_BANK, Account::TYPE_CASH, Account::TYPE_OUTSTANDING]], ]; const WEEKLY_INTERVAL = 604800; // 7 days const MONTHLY_INTERVAL = 2635200; // 1 month static public function plot(string $type, array $criterias, int $interval = self::WEEKLY_INTERVAL, int $width = 700) { if (!array_key_exists($type, self::PLOT_TYPES)) { throw new \InvalidArgumentException('Unknown type'); } $plot = new Plot($width, 300); $lines = self::PLOT_TYPES[$type]; $data = []; foreach ($lines as $label => $line_criterias) { $line_criterias = array_merge($criterias, $line_criterias); $sums = Reports::getSumsByInterval($line_criterias, $interval); if (count($sums) <= 1) { continue; } // Invert sums for banks, cash, etc. if ('assets' === $type || 'debts' === $type || ('result' === $type && $line_criterias['position'] == Account::EXPENSE)) { $sums = array_map(function ($v) { return $v * -1; }, $sums); } $sums = array_map(function ($v) { return (int)$v/100; }, $sums); $graph = new Plot_Data($sums); $graph->title = $label; $data[] = $graph; } if (count($data)) { $labels = []; foreach ($data[0]->get() as $k=>$v) { $date = new \DateTime('@' . ($k * $interval)); $labels[] = Utils::date_fr($date, 'M y'); } $plot->setLabels($labels); $i = 0; $colors = self::getColors(); foreach ($data as $line) { $line->color = $colors[$i++]; $line->width = 3; $plot->add($line); if ($i >= count($colors)) $i = 0; } } return $plot->output(); } static public function pie(string $type, array $criterias) { if (!array_key_exists($type, self::PIE_TYPES)) { throw new \InvalidArgumentException('Unknown type'); } $pie = new Pie(700, 300); $pie_criterias = self::PIE_TYPES[$type]; $data = Reports::getClosingSumsWithAccounts(array_merge($criterias, $pie_criterias), 'ABS(sum) DESC'); $others = 0; $colors = self::getColors(); $max = count($colors); $total = 0; $count = 0; $i = 0; foreach ($data as $row) { $row->sum = abs($row->sum); $total += $row->sum; } foreach ($data as $row) { if ($i++ >= $max || $count > $total*0.95) { $others += $row->sum; } else { $label = strlen($row->label) > 40 ? substr($row->label, 0, 38) . '…' : $row->label; $pie->add(new Pie_Data(abs($row->sum) / 100, $label, $colors[$i-1])); } $count += $row->sum; } if ($others != 0) { $pie->add(new Pie_Data(abs($others) / 100, 'Autres', '#ccc')); } $pie->togglePercentage(true); return $pie->output(); } static protected function getColors() { $config = Config::getInstance(); $c1 = $config->get('couleur1') ?: ADMIN_COLOR1; $c2 = $config->get('couleur2') ?: ADMIN_COLOR2; list($h, $s, $v) = Utils::rgbToHsv($c1); list($h1, $s, $v) = Utils::rgbToHsv($c2); $colors = []; for ($i = 0; $i < 6; $i++) { if ($i % 2 == 0) { $s = $v = 50; $h =& $h1; } else { $s = $v = 70; $h =& $h2; } $colors[] = sprintf('hsl(%d, %d%%, %d%%)', $h, $s, $v); $h += 30; if ($h > 360) { $h -= 360; } } return $colors; } } |
Added src/include/lib/Garradin/Accounting/Reports.php version [bd1f8f1a69].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | <?php namespace Garradin\Accounting; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Line; use Garradin\Entities\Accounting\Transaction; use Garradin\Utils; use Garradin\DB; use KD2\DB\EntityManager; class Reports { static public function getWhereClause(array $criterias): string { $where = []; if (!empty($criterias['year'])) { $where[] = sprintf('t.id_year = %d', $criterias['year']); } if (!empty($criterias['position'])) { $db = DB::getInstance(); $where[] = $db->where('position', $criterias['position']); } if (!empty($criterias['exclude_position'])) { $db = DB::getInstance(); $where[] = $db->where('position', 'NOT IN', $criterias['exclude_position']); } if (!empty($criterias['type'])) { $db = DB::getInstance(); $criterias['type'] = array_map('intval', (array)$criterias['type']); $where[] = sprintf('a.type IN (%s)', implode(',', $criterias['type'])); } if (!empty($criterias['user'])) { $where[] = sprintf('t.id IN (SELECT id_transaction FROM acc_transactions_users WHERE id_user = %d)', $criterias['user']); } if (!empty($criterias['creator'])) { $where[] = sprintf('t.id_creator = %d', $criterias['creator']); } if (!empty($criterias['service_user'])) { $where[] = sprintf('t.id IN (SELECT tu.id_transaction FROM acc_transactions_users tu WHERE id_service_user = %d)', $criterias['service_user']); } if (!empty($criterias['analytical'])) { $where[] = sprintf('l.id_analytical = %d', $criterias['analytical']); } if (!count($where)) { throw new \LogicException('Unknown criteria'); } return implode(' AND ', $where); } /** * Return account sums per year or per account * @param bool $order_year If true will return accounts grouped by year, if false it will return years grouped by account */ static public function getAnalyticalSums(bool $by_year = false): \Generator { $sql = 'SELECT a.label AS account_label, a.id AS id_account, y.id AS id_year, y.label AS year_label, y.start_date, y.end_date, SUM(l.credit - l.debit) AS sum, SUM(l.credit) AS credit, SUM(l.debit) AS debit FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction INNER JOIN acc_accounts a ON a.id = l.id_analytical INNER JOIN acc_years y ON y.id = t.id_year GROUP BY %s ORDER BY %s;'; if ($by_year) { $group = 'y.id, a.id'; $order = 'y.start_date DESC, a.label COLLATE NOCASE'; } else { $group = 'a.id, y.id'; $order = 'a.label COLLATE NOCASE, y.id'; } $sql = sprintf($sql, $group, $order); $current = null; foreach (DB::getInstance()->iterate($sql) as $row) { $id = $by_year ? $row->id_year : $row->id_account; if (null !== $current && $current->id !== $id) { $current->items[] = (object) [ 'label' => 'Total', 'credit' => $current->credit, 'debit' => $current->debit, 'sum' => $current->sum, 'id_account' => $by_year ? null : $current->id, 'id_year' => $by_year ? $current->id : null, ]; yield $current; $current = null; } if (null === $current) { $current = (object) [ 'id' => $by_year ? $row->id_year : $row->id_account, 'label' => $by_year ? $row->year_label : $row->account_label, 'credit' => 0, 'debit' => 0, 'sum' => 0, 'items' => [] ]; } $row->label = !$by_year ? $row->year_label : $row->account_label; $current->items[] = $row; $current->credit += $row->credit; $current->debit += $row->debit; $current->sum += $row->sum; } if ($current === null) { return; } $current->items[] = (object) [ 'label' => 'Total', 'credit' => $current->credit, 'debit' => $current->debit, 'sum' => $current->sum, 'id_account' => $by_year ? null : $row->id_account, 'id_year' => $by_year ? $row->id_year : null, ]; yield $current; } static public function getSumsByInterval(array $criterias, int $interval) { $where = self::getWhereClause($criterias); $where_interval = !empty($criterias['year']) ? sprintf(' WHERE id_year = %d', $criterias['year']) : ''; $db = DB::getInstance(); $sql = sprintf('SELECT strftime(\'%%s\', MIN(date)) / %d AS start_interval, strftime(\'%%s\', MAX(date)) / %1$d AS end_interval FROM acc_transactions %s;', $interval, $where_interval); extract((array)$db->first($sql)); $out = array_fill_keys(range($start_interval, $end_interval), 0); $sql = sprintf('SELECT strftime(\'%%s\', t.date) / %d AS interval, SUM(l.credit) - SUM(l.debit) AS sum, t.id_year FROM acc_transactions t INNER JOIN acc_transactions_lines l ON l.id_transaction = t.id INNER JOIN acc_accounts a ON a.id = l.id_account WHERE %s GROUP BY %s ORDER BY %3$s;', $interval, $where, isset($criterias['year']) ? 'interval' : 't.id_year, interval'); $data = $db->getGrouped($sql); $sum = 0; $year = null; foreach ($out as $k => &$v) { if (array_key_exists($k, $data)) { $row = $data[$k]; if ($row->id_year != $year) { $sum = 0; $year = $row->id_year; } $sum += $data[$k]->sum; } $v = $sum; } unset($v); return $out; } static public function getResult(array $criterias): int { $where = self::getWhereClause($criterias); $sql = sprintf('SELECT SUM(l.credit) - SUM(l.debit) FROM %s l INNER JOIN %s t ON t.id = l.id_transaction INNER JOIN %s a ON a.id = l.id_account WHERE %s AND a.position = ?;', Line::TABLE, Transaction::TABLE, Account::TABLE, $where); $db = DB::getInstance(); $a = $db->firstColumn($sql, Account::REVENUE); $b = $db->firstColumn($sql, Account::EXPENSE); return (int)$a - abs((int)$b); } static public function getClosingSumsWithAccounts(array $criterias, ?string $order = null, bool $reverse = false): array { $where = self::getWhereClause($criterias); $order = $order ?: 'a.code COLLATE NOCASE'; $reverse = $reverse ? '* - 1' : ''; // Find sums, link them to accounts $sql = sprintf('SELECT a.id, a.code, a.label, a.position, SUM(l.credit) AS credit, SUM(l.debit) AS debit, SUM(l.credit - l.debit) %s AS sum FROM %s l INNER JOIN %s t ON t.id = l.id_transaction INNER JOIN %s a ON a.id = l.id_account WHERE %s GROUP BY l.id_account HAVING sum != 0 ORDER BY %s;', $reverse, Line::TABLE, Transaction::TABLE, Account::TABLE, $where, $order); return DB::getInstance()->getGrouped($sql); } static public function getBalanceSheet(array $criterias): array { $out = [ Account::ASSET => [], Account::LIABILITY => [], 'sums' => [ Account::ASSET => 0, Account::LIABILITY => 0, ], ]; $position_criteria = ['position' => [Account::ASSET, Account::LIABILITY, Account::ASSET_OR_LIABILITY]]; $list = self::getClosingSumsWithAccounts($criterias + $position_criteria); foreach ($list as $row) { if ($row->sum == 0) { // Ignore empty accounts continue; } $position = $row->position; if ($position == Account::ASSET_OR_LIABILITY) { $position = $row->sum < 0 ? Account::ASSET : Account::LIABILITY; $row->sum = abs($row->sum); } elseif ($position == Account::ASSET) { // reverse number for assets $row->sum *= -1; } $out[$position][] = $row; } $result = self::getResult($criterias); $out[Account::LIABILITY][] = (object) [ 'id' => null, 'label' => $result > 0 ? 'Résultat de l\'exercice courant (excédent)' : 'Résultat de l\'exercice courant (perte)', 'sum' => $result, ]; // Calculate the total sum for assets and liabilities foreach ($out as $position => $rows) { if ($position == 'sums') { continue; } $sum = 0; foreach ($rows as $row) { $sum += $row->sum; } $out['sums'][$position] = $sum; } return $out; } /** * Return list of favorite accounts (accounts with a type), grouped by type, with their current sum * @return \Generator list of accounts grouped by type */ static public function getClosingSumsFavoriteAccounts(array $criterias): \Generator { $where = self::getWhereClause($criterias); $sql = sprintf('SELECT a.id, a.code, a.label, a.description, a.type, SUM(l.credit) - SUM(l.debit) AS sum FROM %s a INNER JOIN %s t ON t.id = l.id_transaction INNER JOIN %s l ON a.id = l.id_account WHERE a.type != 0 AND %s GROUP BY l.id_account ORDER BY a.type, a.code COLLATE NOCASE;', Account::TABLE, Transaction::TABLE, Line::TABLE, $where); $group = null; foreach (DB::getInstance()->iterate($sql) as $row) { if (null !== $group && $row->type !== $group->type) { yield $group; $group = null; } if (null === $group) { $group = (object) [ 'label' => Account::TYPES_NAMES[$row->type], 'type' => $row->type, 'accounts' => [] ]; } $reverse = Account::isReversed($row->type) ? -1 : 1; $row->sum *= $reverse; $group->accounts[] = $row; } if (null !== $group) { yield $group; } } /** * Grand livre */ static public function getGeneralLedger(array $criterias): \Generator { $where = self::getWhereClause($criterias); $db = DB::getInstance(); $sql = sprintf('SELECT t.id_year, l.id_account, l.debit, l.credit, t.id, t.date, t.reference, l.reference AS line_reference, t.label, l.label AS line_label FROM acc_transactions t INNER JOIN acc_transactions_lines l ON l.id_transaction = t.id INNER JOIN acc_accounts a ON a.id = l.id_account WHERE %s ORDER BY a.code COLLATE NOCASE, t.date, t.id;', $where); $account = null; $debit = $credit = 0; $accounts = null; foreach ($db->iterate($sql) as $row) { if (null === $accounts) { $accounts = $db->getGrouped('SELECT id, code, label FROM acc_accounts WHERE id_chart = (SELECT id_chart FROM acc_years WHERE id = ?);', $row->id_year); } if (null !== $account && $account->id != $row->id_account) { yield $account; $account = null; } if (null === $account) { $account = (object) [ 'code' => $accounts[$row->id_account]->code, 'label' => $accounts[$row->id_account]->label, 'id' => $row->id_account, 'id_year' => $row->id_year, 'sum' => 0, 'debit' => 0, 'credit'=> 0, 'lines' => [], ]; } $row->date = \DateTime::createFromFormat('Y-m-d', $row->date); $account->sum += ($row->credit - $row->debit); $account->debit += $row->debit; $account->credit += $row->credit; $debit += $row->debit; $credit += $row->credit; $row->running_sum = $account->sum; $account->lines[] = $row; } if (null === $account) { return; } $account->all_debit = $debit; $account->all_credit = $credit; yield $account; } static public function getJournal(array $criterias): \Generator { $where = self::getWhereClause($criterias); $sql = sprintf('SELECT t.id_year, l.id_account, l.debit, l.credit, t.id, t.date, t.reference, l.reference AS line_reference, t.label, l.label AS line_label FROM acc_transactions t INNER JOIN acc_transactions_lines l ON l.id_transaction = t.id WHERE %s ORDER BY t.date, t.id;', $where); $transaction = null; $accounts = null; $db = DB::getInstance(); foreach ($db->iterate($sql) as $row) { if (null === $accounts) { $accounts = $db->getGrouped('SELECT id, code, label FROM acc_accounts WHERE id_chart = (SELECT id_chart FROM acc_years WHERE id = ?);', $row->id_year); } if (null !== $transaction && $transaction->id != $row->id) { yield $transaction; $transaction = null; } if (null === $transaction) { $transaction = (object) [ 'id' => $row->id, 'label' => $row->label, 'date' => \DateTime::createFromFormat('Y-m-d', $row->date), 'reference' => $row->reference, 'lines' => [], ]; } if (!isset($accounts[$row->id_account])) { throw new \LogicException(sprintf('Account #%s not found', $row->id_account)); } $transaction->lines[] = (object) [ 'account_label' => $accounts[$row->id_account]->label, 'account_code' => $accounts[$row->id_account]->code, 'label' => $row->line_label, 'reference' => $row->line_reference, 'id_account' => $row->id_account, 'credit' => $row->credit, 'debit' => $row->debit, 'id_year' => $row->id_year, ]; } if (null === $transaction) { return; } yield $transaction; } } |
Added src/include/lib/Garradin/Accounting/Transactions.php version [04872dade5].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | <?php namespace Garradin\Accounting; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Line; use Garradin\Entities\Accounting\Transaction; use Garradin\Entities\Accounting\Year; use KD2\DB\EntityManager; use Garradin\CSV; use Garradin\CSV_Custom; use Garradin\DB; use Garradin\DynamicList; use Garradin\Utils; use Garradin\UserException; class Transactions { const EXPECTED_CSV_COLUMNS_SELF = ['id', 'type', 'status', 'label', 'date', 'notes', 'reference', 'line_id', 'account', 'credit', 'debit', 'line_reference', 'line_label', 'reconciled']; const POSSIBLE_CSV_COLUMNS = [ 'id' => 'Numéro d\'écriture', 'label' => 'Libellé', 'date' => 'Date', 'notes' => 'Notes', 'reference' => 'Numéro pièce comptable', 'p_reference' => 'Référence paiement', 'debit_account' => 'Compte de débit', 'credit_account' => 'Compte de crédit', 'amount' => 'Montant', ]; const MANDATORY_CSV_COLUMNS = ['id', 'label', 'date', 'credit_account', 'debit_account', 'amount']; static public function get(int $id) { return EntityManager::findOneById(Transaction::class, $id); } static public function saveReconciled(\Generator $journal, ?array $checked) { if (null === $checked) { $checked = []; } $db = DB::getInstance(); $db->begin(); // Synchro des trucs cochés $st = $db->prepare('UPDATE acc_transactions_lines SET reconciled = :r WHERE id = :id;'); foreach ($journal as $row) { if (!isset($row->id_line)) { continue; } $st->bindValue(':id', (int)$row->id_line, \SQLITE3_INTEGER); $st->bindValue(':r', !empty($checked[$row->id_line]) ? 1 : 0, \SQLITE3_INTEGER); $st->execute(); } $db->commit(); } static public function saveDeposit(Transaction $transaction, \Generator $journal, array $checked) { $db = DB::getInstance(); $db->begin(); try { $ids = []; foreach ($journal as $row) { if (!array_key_exists($row->id, $checked)) { continue; } $ids[] = (int)$row->id; $line = new Line; $line->importForm([ 'reference' => $row->line_reference, 'id_account' => $row->id_account, ]); $line->credit = $row->debit; $transaction->addLine($line); } $transaction->save(); $ids = implode(',', $ids); $db->exec(sprintf('UPDATE acc_transactions SET status = (status | %d) WHERE id IN (%s);', Transaction::STATUS_DEPOSIT, $ids)); $db->commit(); } catch (\Exception $e) { $db->rollback(); throw $e; } } static public function countForUser(int $user_id): int { return DB::getInstance()->count('acc_transactions_users', 'id_user = ?', $user_id); } static public function countForCreator(int $user_id): int { return DB::getInstance()->count('acc_transactions', 'id_creator = ?', $user_id); } /** * Return all transactions from year */ static public function export(int $year_id): \Generator { $sql = 'SELECT t.id, t.type, t.status, t.label, t.date, t.notes, t.reference, l.id AS line_id, a.code AS account, l.debit AS debit, l.credit AS credit, l.reference AS line_reference, l.label AS line_label, l.reconciled, a2.code AS analytical FROM acc_transactions t INNER JOIN acc_transactions_lines l ON l.id_transaction = t.id INNER JOIN acc_accounts a ON a.id = l.id_account LEFT JOIN acc_accounts a2 ON a2.id = l.id_analytical WHERE t.id_year = ? ORDER BY t.date, t.id, l.id;'; $res = DB::getInstance()->iterate($sql, $year_id); $previous_id = null; foreach ($res as $row) { if ($previous_id === $row->id) { $row->id = $row->type = $row->status = $row->label = $row->date = $row->notes = $row->reference = null; } else { $row->type = Transaction::TYPES_NAMES[$row->type]; $status = []; foreach (Transaction::STATUS_NAMES as $k => $v) { if ($row->status & $k) { $status[] = $v; } } $row->status = implode(', ', $status); $row->date = \DateTime::createFromFormat('Y-m-d', $row->date); $row->date = $row->date->format('d/m/Y'); } $row->credit = Utils::money_format($row->credit, ',', ''); $row->debit = Utils::money_format($row->debit, ',', ''); $previous_id = $row->id; yield $row; } } static public function importCSV(Year $year, array $file, int $user_id) { if ($year->closed) { throw new \InvalidArgumentException('Closed year'); } $db = DB::getInstance(); $db->begin(); $accounts = $year->accounts(); $transaction = null; $types = array_flip(Transaction::TYPES_NAMES); $l = 0; try { foreach (CSV::importUpload($file, self::EXPECTED_CSV_COLUMNS_SELF) as $l => $row) { $row = (object) $row; $has_transaction = !empty($row->id) || !empty($row->type) || !empty($row->status) || !empty($row->label) || !empty($row->date) || !empty($row->notes) || !empty($row->reference); if (null !== $transaction && $has_transaction) { $transaction->save(); $transaction = null; } if (null === $transaction) { if (!$has_transaction) { throw new UserException('cette ligne n\'est reliée à aucune écriture'); } if ($row->id) { $transaction = self::get((int)$row->id); if (!$transaction) { throw new UserException(sprintf('l\'écriture n°%d est introuvable', $row->id)); } if ($transaction->validated) { throw new UserException(sprintf('l\'écriture n°%d est validée et ne peut être modifiée', $row->id)); } } else { $transaction = new Transaction; $transaction->id_creator = $user_id; $transaction->id_year = $year->id(); } if (!isset($types[$row->type])) { throw new UserException(sprintf('le type "%s" est inconnu', $row->type)); } $transaction->type = $types[$row->type]; $fields = array_intersect_key((array)$row, array_flip(['label', 'date', 'notes', 'reference'])); $transaction->importForm($fields); } $id_account = $accounts->getIdFromCode($row->account); if (!$id_account) { throw new UserException(sprintf('le compte "%s" n\'existe pas dans le plan comptable', $row->account)); } $row->line_id = trim($row->line_id); $id_analytical = null; $data = [ 'credit' => $row->credit ?: 0, 'debit' => $row->debit ?: 0, 'id_account' => $id_account, 'reference' => $row->line_reference, 'label' => $row->line_label, 'reconciled' => $row->reconciled, ]; if (!empty($row->analytical)) { $id_analytical = $accounts->getIdFromCode($row->analytical); if (!$id_analytical) { throw new UserException(sprintf('le compte analytique "%s" n\'existe pas dans le plan comptable', $row->analytical)); } $data['id_analytical'] = $id_analytical; } elseif (property_exists($row, 'analytical')) { $data['id_analytical'] = null; } if ($row->line_id) { $line = $transaction->getLine((int)$row->line_id); if (!$line) { throw new UserException(sprintf('le numéro de ligne "%s" n\'existe pas dans l\'écriture "%s"', $row->line_id, $transaction->id ?: 'à créer')); } } else { $line = new Line; } $line->importForm($data); if (!$row->line_id) { $transaction->addLine($line); } } if (null !== $transaction) { $transaction->save(); } } catch (UserException $e) { $db->rollback(); throw new UserException(sprintf('Erreur sur la ligne %d : %s', $l, $e->getMessage())); } $db->commit(); } static public function importCustom(Year $year, CSV_Custom $csv, int $user_id) { if ($year->closed) { throw new \InvalidArgumentException('Closed year'); } $db = DB::getInstance(); $db->begin(); $accounts = $year->accounts(); $l = 0; try { foreach ($csv->iterate() as $l => $row) { if (!isset($row->credit_account, $row->debit_account, $row->amount)) { throw new UserException('Une des colonnes compte de crédit, compte de débit ou montant est manquante.'); } if (!empty($row->id)) { $transaction = self::get((int)$row->id); if (!$transaction) { throw new UserException(sprintf('Ligne %d : l\'écriture n°%d est introuvable', $l, $row->id)); } if ($transaction->validated) { throw new UserException(sprintf('Ligne %d : l\'écriture n°%d est validée et ne peut être modifiée', $l, $row->id)); } $transaction->resetLines(); } else { $transaction = new Transaction; $transaction->type = Transaction::TYPE_ADVANCED; $transaction->id_creator = $user_id; $transaction->id_year = $year->id(); } $fields = array_intersect_key((array)$row, array_flip(['label', 'date', 'notes', 'reference'])); $transaction->importForm($fields); $credit_account = $accounts->getIdFromCode($row->credit_account); $debit_account = $accounts->getIdFromCode($row->debit_account); if (!$credit_account) { throw new UserException(sprintf('Compte de crédit "%s" inconnu dans le plan comptable', $row->credit_account)); } if (!$debit_account) { throw new UserException(sprintf('Compte de débit "%s" inconnu dans le plan comptable', $row->debit_account)); } $line = new Line; $line->importForm([ 'credit' => $row->amount, 'debit' => 0, 'id_account' => $credit_account, 'reference' => isset($row->p_reference) ? $row->p_reference : null, ]); $transaction->addLine($line); $line = new Line; $line->importForm([ 'credit' => 0, 'debit' => $row->amount, 'id_account' => $debit_account, 'reference' => isset($row->p_reference) ? $row->p_reference : null, ]); $transaction->addLine($line); $transaction->save(); } } catch (UserException $e) { $db->rollback(); throw new UserException(sprintf('Erreur sur la ligne %d : %s', $l, $e->getMessage())); } $db->commit(); } static public function setAnalytical(?int $id_analytical, array $lines) { $db = DB::getInstance(); if (null !== $id_analytical && !$db->test(Account::TABLE, 'type = 7 AND id = ?', $id_analytical)) { throw new \InvalidArgumentException('Chosen account ID is not analytical'); } $lines = array_map('intval', $lines); return $db->exec(sprintf('UPDATE acc_transactions_lines SET id_analytical = %s WHERE id IN (%s);', (int)$id_analytical ?: 'NULL', implode(', ', $lines))); } static public function listByType(int $year_id, int $type) { $reverse = 1; $columns = Account::LIST_COLUMNS; unset($columns['line_label'], $columns['sum'], $columns['debit'], $columns['credit']); $columns['line_reference']['label'] = 'Réf. paiement'; $columns['change']['select'] = sprintf($columns['change']['select'], $reverse); $columns['change']['label'] = 'Montant'; $tables = 'acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction INNER JOIN acc_accounts a ON a.id = l.id_account LEFT JOIN acc_accounts b ON b.id = l.id_analytical'; $conditions = sprintf('t.type = %s AND t.id_year = %d', $type, $year_id); $sum = 0; $list = new DynamicList($columns, $tables, $conditions); $list->orderBy('date', true); $list->setCount('COUNT(*)'); $list->groupBy('t.id'); $list->setModifier(function (&$row) use (&$sum, $reverse) { $row->date = \DateTime::createFromFormat('!Y-m-d', $row->date); }); $list->setExportCallback(function (&$row) { $row->change = Utils::money_format($row->change, '.', '', false); }); return $list; } } |
Added src/include/lib/Garradin/Accounting/Years.php version [6f97d0273b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | <?php namespace Garradin\Accounting; use Garradin\Entities\Accounting\Year; use Garradin\Utils; use Garradin\DB; use KD2\DB\EntityManager; class Years { static public function get(int $year_id) { return EntityManager::findOneById(Year::class, $year_id); } static public function getCurrentOpenYear() { return EntityManager::findOne(Year::class, 'SELECT * FROM @TABLE WHERE closed = 0 ORDER BY start_date LIMIT 1;'); } static public function listOpen() { $db = EntityManager::getInstance(Year::class)->DB(); return $db->get('SELECT *, (SELECT 1 FROM acc_transactions WHERE id_year = acc_years.id LIMIT 1) AS has_transactions FROM acc_years WHERE closed = 0 ORDER BY end_date;'); } static public function listAssoc() { return DB::getInstance()->getAssoc('SELECT id, label FROM acc_years ORDER BY end_date;'); } static public function listClosed() { $em = EntityManager::getInstance(Year::class); return $em->all('SELECT * FROM @TABLE WHERE closed = 1 ORDER BY end_date;'); } static public function countClosed() { return DB::getInstance()->count(Year::TABLE, 'closed = 1'); } static public function list(bool $reverse = false) { $desc = $reverse ? 'DESC' : ''; $em = EntityManager::getInstance(Year::class); return $em->all(sprintf('SELECT * FROM @TABLE ORDER BY end_date %s;', $desc)); } static public function getNewYearDates(): array { $last_year = EntityManager::findOne(Year::class, 'SELECT * FROM @TABLE ORDER BY end_date DESC LIMIT 1;'); if ($last_year) { $start_date = clone $last_year->start_date; $start_date->modify('+1 year'); $end_date = clone $last_year->end_date; $end_date->modify('+1 year'); } else { $start_date = new \DateTime; $end_date = clone $start_date; $end_date->modify('+1 year'); } return [$start_date, $end_date]; } } |
Added src/include/lib/Garradin/CSV.php version [0895323879].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | <?php namespace Garradin; use KD2\Office\Calc\Writer as ODSWriter; class CSV { static public function readAsArray(string $path) { if (!file_exists($path) || !is_readable($path)) { throw new \RuntimeException('Fichier inconnu : '.$path); } $fp = self::open($path); if (!$fp) { return false; } $delim = self::findDelimiter($fp); self::skipBOM($fp); $line = 0; $out = []; $nb_columns = null; while (!feof($fp)) { $row = fgetcsv($fp, 4096, $delim); $line++; if (empty($row)) { continue; } if (null === $nb_columns) { $nb_columns = count($row); } if (count($row) != $nb_columns) { throw new UserException('Erreur sur la ligne ' . $line . ' : incohérence dans le nombre de colonnes avec la première ligne.'); } $out[$line] = $row; } fclose($fp); return $out; } static public function open(string $file) { ini_set('auto_detect_line_endings', true); return fopen($file, 'r'); } static public function findDelimiter(&$fp) { $line = ''; while ($line === '' && !feof($fp)) { $line = fgets($fp, 4096); } if (strlen($line) >= 4095) { throw new UserException('Fichier CSV illisible : la première ligne est trop longue.'); } // Delete the columns content $line = preg_replace('/".*?"/', '', $line); $delims = [ ';' => substr_count($line, ';'), ',' => substr_count($line, ','), "\t"=> substr_count($line, "\t") ]; arsort($delims); reset($delims); rewind($fp); return key($delims); } static public function skipBOM(&$fp) { // Skip BOM if (fgets($fp, 4) !== chr(0xEF) . chr(0xBB) . chr(0xBF)) { fseek($fp, 0); } } static public function row($row): string { $row = (array) $row; array_walk($row, function (&$field) { $field = strtr($field, ['"' => '""', "\r\n" => "\n"]); }); return sprintf("\"%s\"\r\n", implode('","', $row)); } static public function export(string $format, string $name, iterable $iterator, ?array $header = null, ?callable $row_map_callback = null): void { if ('csv' == $format) { self::toCSV(... array_slice(func_get_args(), 1)); } else { self::toODS(... array_slice(func_get_args(), 1)); } } static protected function rowToArray($row, ?callable $row_map_callback) { if (null !== $row_map_callback) { call_user_func_array($row_map_callback, [&$row]); } if (is_object($row) && $row instanceof Entity) { $row = $row->asArray(); } elseif (is_object($row)) { $row = (array) $row; } foreach ($row as $key => &$v) { if ((is_object($v) && !($v instanceof \DateTimeInterface)) || is_array($v)) { throw new \UnexpectedValueException(sprintf('Unexpected value for "%s": %s', $key, gettype($v))); } } return $row; } static public function toCSV(string $name, iterable $iterator, ?array $header = null, ?callable $row_map_callback = null): void { header('Content-type: application/csv'); header(sprintf('Content-Disposition: attachment; filename="%s.csv"', $name)); $fp = fopen('php://output', 'w'); if ($header) { fputs($fp, self::row($header)); } foreach ($iterator as $row) { foreach ($row as $key => &$v) { if (is_object($v)&& $v instanceof \DateTimeInterface) { $v = $v->format('d/m/Y'); } } $row = self::rowToArray($row, $row_map_callback); if (!$header) { fputs($fp, self::row(array_keys($row))); $header = true; } fputs($fp, self::row($row)); } fclose($fp); } static public function toODS(string $name, iterable $iterator, ?array $header = null, ?callable $row_map_callback = null): void { header('Content-type: application/vnd.oasis.opendocument.spreadsheet'); header(sprintf('Content-Disposition: attachment; filename="%s.ods"', $name)); $ods = new ODSWriter; $ods->table_name = $name; if ($header) { $ods->add((array) $header); } foreach ($iterator as $row) { $row = self::rowToArray($row, $row_map_callback); if (!$header) { $ods->add(array_keys($row)); $header = true; } $ods->add((array) $row); } $ods->output(); } static public function importUpload(array $file, array $expected_columns): \Generator { if (empty($file['size']) || empty($file['tmp_name'])) { throw new UserException('Fichier invalide'); } return self::import($file['tmp_name'], $expected_columns); } static public function import(string $file, array $expected_columns): \Generator { $fp = fopen($file, 'r'); if (!$fp) { throw new UserException('Le fichier ne peut être ouvert'); } // Find the delimiter $delim = self::findDelimiter($fp); self::skipBOM($fp); $line = 1; $columns = fgetcsv($fp, 4096, $delim); $columns = array_map('trim', $columns); // Check for required columns foreach ($expected_columns as $column) { if (!in_array($column, $columns, true)) { throw new UserException(sprintf('La colonne "%s" est absente du fichier importé', $column)); } } while (!feof($fp)) { $row = fgetcsv($fp, 4096, $delim); $line++; // Empty line, skip if (empty($row)) { continue; } if (count($row) != count($columns)) { throw new UserException('Erreur sur la ligne ' . $line . ' : le nombre de colonnes est incorrect.'); } $row = array_combine($columns, $row); yield $line => $row; } fclose($fp); } } |
Added src/include/lib/Garradin/CSV_Custom.php version [12dd8c64a5].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | <?php namespace Garradin; use KD2\UserSession; class CSV_Custom { protected $session; protected $key; protected $csv; protected $translation; protected $columns; protected $mandatory_columns = []; protected $skip = 1; public function __construct(UserSession $session, string $key) { $this->session = $session; $this->key = $key; $this->csv = $this->session->get($this->key); $this->translation = $this->session->get($this->key . '_translation') ?: []; $this->skip = $this->session->get($this->key . '_skip') ?: 1; } public function load(array $file) { if (empty($file['size']) || empty($file['tmp_name'])) { throw new UserException('Fichier invalide'); } $csv = CSV::readAsArray($file['tmp_name']); if (!count($csv)) { throw new UserException('Ce fichier est vide (aucune ligne trouvée).'); } $this->session->set($this->key, $csv); } public function iterate(): \Generator { if (empty($this->csv)) { throw new \LogicException('No file has been loaded'); } if (!$this->columns || !$this->translation) { throw new \LogicException('Missing columns or translation table'); } $default = array_map(function ($a) { return null; }, $this->columns); $i = 0; foreach ($this->csv as $k => $line) { if ($i++ < $this->skip) { continue; } $row = $default; foreach ($line as $col => $value) { if (!isset($this->translation[$col])) { continue; } $row[$this->translation[$col]] = $value; } $row = (object) $row; yield $k => $row; } } public function getFirstLine(): array { if (empty($this->csv)) { throw new \LogicException('No file has been loaded'); } return reset($this->csv); } public function getSelectedTable(?array $source = null): array { if (null === $source && isset($_POST['translation_table'])) { $source = $_POST['translation_table']; } elseif (null === $source) { $source = []; } $selected = $this->getFirstLine(); foreach ($selected as $k => &$v) { if (isset($source[$k])) { $v = $source[$k]; } elseif (isset($this->translation[$k])) { $v = $this->translation[$k]; } elseif (false !== ($pos = array_search($v, $this->columns, true))) { $v = $pos; } else { $v = null; } } return $selected; } public function getTranslationTable(): array { return $this->translation; } public function setTranslationTable(array $table): void { $translation = []; foreach ($table as $csv => $target) { if (empty($target)) { continue; } if (!array_key_exists($target, $this->columns)) { throw new UserException('Colonne inconnue'); } $translation[(int)$csv] = $target; } foreach ($this->mandatory_columns as $key) { if (!in_array($key, $translation, true)) { throw new UserException(sprintf('La colonne "%s" est obligatoire mais n\'a pas été sélectionnée ou n\'existe pas.', $this->columns[$key])); } } $this->translation = $translation; $this->session->set($this->key . '_translation', $this->translation); } public function clear(): void { $this->session->set($this->key, null); $this->session->set($this->key . '_translation', null); $this->session->set($this->key . '_skip', null); } public function loaded(): bool { return null !== $this->csv; } public function ready(): bool { return $this->loaded() && !empty($this->translation); } public function count(): ?int { return null !== $this->csv ? count($this->csv) : null; } public function skip(int $count): void { $this->skip = $count; $this->session->set($this->key . '_skip', $count); } public function setColumns(array $columns): void { $this->columns = $columns; } public function setMandatoryColumns(array $columns): void { $this->mandatory_columns = $columns; } public function getColumnsString(): string { return implode(', ', $this->getColumns()); } public function getMandatoryColumnsString(): string { return implode(', ', $this->getMandatoryColumns()); } public function getColumns(): array { return $this->columns; } public function getMandatoryColumns(): array { return array_intersect_key($this->columns, $this->mandatory_columns); } } |
Deleted src/include/lib/Garradin/Compta/Categories.php version [aacf281b4b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Compta/Comptes.php version [9bf36bdeef].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Compta/Comptes_Bancaires.php version [c2ddfadd03].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Compta/Exercices.php version [3bc6667d2a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Compta/Import.php version [f437eb905d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Compta/Journal.php version [88e9a2c624].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Compta/Projets.php version [e557763ba3].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Compta/Rapports.php version [9726d24a12].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Compta/Rapprochement.php version [21098b9dae].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Compta/Stats.php version [5104b17973].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/include/lib/Garradin/Config.php from [c889a0eda3] to [06d32e37da].
︙ | ︙ | |||
45 46 47 48 49 50 51 | $object = new \stdClass; $this->fields_types = [ 'nom_asso' => $string, 'adresse_asso' => $string, 'email_asso' => $string, 'site_asso' => $string, | | | | | < < < | | | > | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | $object = new \stdClass; $this->fields_types = [ 'nom_asso' => $string, 'adresse_asso' => $string, 'email_asso' => $string, 'site_asso' => $string, 'monnaie' => $string, 'pays' => $string, 'champs_membres' => $object, 'categorie_membres' => $int, 'accueil_wiki' => $string, 'accueil_connexion' => $string, 'frequence_sauvegardes' => $int, 'nombre_sauvegardes' => $int, 'champ_identifiant' => $string, 'champ_identite' => $string, 'version' => $string, 'last_chart_change' => $int, 'couleur1' => $string, 'couleur2' => $string, 'image_fond' => $string, 'desactiver_site' => $bool, ]; $db = DB::getInstance(); $this->config = $db->getAssoc('SELECT cle, valeur FROM config ORDER BY cle;'); foreach ($this->config as $key=>&$value) |
︙ | ︙ | |||
118 119 120 121 122 123 124 | { if (empty($this->modified)) return true; $values = []; $db = DB::getInstance(); | > | > > | | | > > | | > > | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | { if (empty($this->modified)) return true; $values = []; $db = DB::getInstance(); // Image files if (isset($this->modified['image_fond'])) { $key = 'image_fond'; $value =& $this->config[$key]; if ($current = $db->firstColumn('SELECT valeur FROM config WHERE cle = ?;', $key)) { try { $f = new Fichiers($current); $f->remove(); } catch (\InvalidArgumentException $e) { // Ignore: the file has already been deleted } } if (strlen($value) > 0) { $content = $value; $value = null; $f = Fichiers::storeFromBase64($key . '.png', $content); $value = $f->id; unset($f); } } unset($value, $key); $db->begin(); foreach ($this->modified as $key=>$modified) { $value = $this->config[$key]; |
︙ | ︙ | |||
161 162 163 164 165 166 167 | $db->preparedQuery('INSERT OR REPLACE INTO config (cle, valeur) VALUES (?, ?);', [$key, $value]); } if (!empty($this->modified['champ_identifiant'])) { // Mettre les champs identifiant vides à NULL pour pouvoir créer un index unique | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | $db->preparedQuery('INSERT OR REPLACE INTO config (cle, valeur) VALUES (?, ?);', [$key, $value]); } if (!empty($this->modified['champ_identifiant'])) { // Mettre les champs identifiant vides à NULL pour pouvoir créer un index unique $db->exec('UPDATE membres SET '.$this->get('champ_identifiant').' = NULL WHERE '.$this->get('champ_identifiant').' = "";'); // Création de l'index unique $db->exec('DROP INDEX IF EXISTS membres_identifiant;'); $db->exec('CREATE UNIQUE INDEX membres_identifiant ON membres ('.$this->get('champ_identifiant').');'); } |
︙ | ︙ | |||
187 188 189 190 191 192 193 | throw new \OutOfBoundsException('Ce champ est inconnu.'); } if (!array_key_exists($key, $this->config)) { return null; } | | | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | throw new \OutOfBoundsException('Ce champ est inconnu.'); } if (!array_key_exists($key, $this->config)) { return null; } return $this->config[$key]; } public function getVersion() { if (!array_key_exists('version', $this->config)) { |
︙ | ︙ | |||
297 298 299 300 301 302 303 | // Vérification que le champ existe bien if (!$champs->get($value)) { throw new UserException('Le champ '.$value.' n\'existe pas pour la configuration de '.$key); } // Vérification que le champ est unique pour l'identifiant | | | < < < < < < < < < < < | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | // Vérification que le champ existe bien if (!$champs->get($value)) { throw new UserException('Le champ '.$value.' n\'existe pas pour la configuration de '.$key); } // Vérification que le champ est unique pour l'identifiant if ($key == 'champ_identifiant' && !$db->firstColumn('SELECT (COUNT(DISTINCT lower('.$value.')) = COUNT(*)) FROM membres WHERE '.$value.' IS NOT NULL AND '.$value.' != \'\';')) { throw new UserException('Le champ '.$value.' comporte des doublons et ne peut donc pas servir comme identifiant pour la connexion.'); } break; } case 'categorie_membres': { $db = DB::getInstance(); if (!$db->firstColumn('SELECT 1 FROM membres_categories WHERE id = ?;', $value)) { |
︙ | ︙ |
Deleted src/include/lib/Garradin/Cotisations.php version [895e912baf].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/include/lib/Garradin/DB.php from [b5f765f6ec] to [dad60ad267].
1 2 3 4 | <?php namespace Garradin; | | | | > > > > | | < < < < | < | < < < < < < < < < < | | | | | | | > > > > | | | < | < < < < < < | < > > | < | < < | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | <?php namespace Garradin; use KD2\DB\SQLite3; class DB extends SQLite3 { /** * Application ID pour SQLite * @link https://www.sqlite.org/pragma.html#pragma_application_id */ const APPID = 0x5da2d811; static protected $_instance = null; static public function getInstance($create = false, $readonly = false) { if (null === self::$_instance) { self::$_instance = new DB('sqlite', ['file' => DB_FILE]); } return self::$_instance; } private function __clone() { // Désactiver le clonage, car on ne veut qu'une seule instance } public function connect(): void { if (null !== $this->db) { return; } parent::connect(); // Activer les contraintes des foreign keys $this->db->exec('PRAGMA foreign_keys = ON;'); // 10 secondes $this->db->busyTimeout(10 * 1000); // Performance enhancement // see https://www.cs.utexas.edu/~jaya/slides/apsys17-sqlite-slides.pdf // https://ericdraken.com/sqlite-performance-testing/ $this->exec(sprintf('PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA journal_size_limit = %d;', 32 * 1024 * 1024)); $this->db->createFunction('transliterate_to_ascii', ['Garradin\Utils', 'transliterateToAscii']); } public function close(): void { parent::close(); self::$_instance = null; } public function beginSchemaUpdate() { $this->toggleForeignKeys(false); $this->begin(); } public function commitSchemaUpdate() { $this->commit(); $this->toggleForeignKeys(true); } /** * @see https://www.sqlite.org/lang_altertable.html */ public function toggleForeignKeys($enable) { |
︙ | ︙ |
Added src/include/lib/Garradin/DynamicList.php version [f85cc3737c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | <?php namespace Garradin; class DynamicList { protected $columns; protected $tables; protected $conditions; protected $group; protected $order; protected $modifier; protected $export_callback; protected $title = 'Liste'; protected $count = 'COUNT(*)'; protected $desc = true; protected $per_page = 100; protected $page = 1; private $count_result; public function __construct(array $columns, string $tables, string $conditions) { $this->columns = $columns; $this->tables = $tables; $this->conditions = $conditions; $this->order = key($columns); } public function __get($key) { return $this->$key; } public function setTitle(string $title) { $this->title = $title; } public function setModifier(callable $fn) { $this->modifier = $fn; } public function setExportCallback(callable $fn) { $this->export_callback = $fn; } public function setPageSize(?int $size) { $this->per_page = $size; } public function setConditions(string $conditions) { $this->conditions = $conditions; } public function orderBy(string $key, bool $desc) { if (!array_key_exists($key, $this->columns)) { throw new UserException('Invalid order: ' . $key); } $this->order = $key; $this->desc = $desc; } public function groupBy(string $value) { $this->group = $value; } public function count() { if (null === $this->count_result) { $sql = sprintf('SELECT %s FROM %s WHERE %s;', $this->count, $this->tables, $this->conditions); $this->count_result = DB::getInstance()->firstColumn($sql); } return $this->count_result; } public function export(string $name, string $format = 'csv') { $this->setPageSize(null); $columns = []; foreach ($this->columns as $key => $column) { if (empty($column['label'])) { $columns[] = $key; continue; } $columns[] = $column['label']; } if ('csv' == $format) { CSV::toCSV($name, $this->iterate(false), $this->getHeaderColumns(true), $this->export_callback); } else if ('ods' == $format) { CSV::toODS($name, $this->iterate(false), $this->getHeaderColumns(true), $this->export_callback); } else { throw new UserException('Invalid export format'); } } public function paginationURL() { return Utils::getModifiedURL('?p=[ID]'); } public function orderURL(string $order, bool $desc) { $query = array_merge($_GET, ['o' => $order, 'd' => (int) $desc]); $url = Utils::getSelfURL($query); return $url; } public function setCount(string $count) { $this->count = $count; } public function getHeaderColumns(bool $label_only = false) { $columns = []; foreach ($this->columns as $alias => $properties) { if (isset($properties['only_with_order']) && !($properties['only_with_order'] == $this->order && !$this->desc)) { continue; } // Skip columns that require a certain order AND paginated result if (isset($properties['only_with_order']) && $this->page > 1) { continue; } if (!isset($properties['label'])) { continue; } $columns[$alias] = $label_only ? $properties['label'] : $properties; } return $columns; } public function iterate(bool $include_hidden = true) { $start = ($this->page - 1) * $this->per_page; $columns = []; foreach ($this->columns as $alias => $properties) { // Skip columns that require a certain order (eg. calculating a running sum) if (isset($properties['only_with_order']) && !($properties['only_with_order'] == $this->order && !$this->desc)) { continue; } // Skip columns that require a certain order AND paginated result if (isset($properties['only_with_order']) && $this->page > 1) { continue; } if (!isset($properties['label']) && !$include_hidden) { continue; } $select = array_key_exists('select', $properties) ? $properties['select'] : $alias; if (null === $select) { $select = 'NULL'; } $columns[] = sprintf('%s AS %s', $select, $alias); } $columns = implode(', ', $columns); if (isset($this->columns[$this->order]['order'])) { $order = sprintf($this->columns[$this->order]['order'], $this->desc ? 'DESC' : 'ASC'); } else { $order = $this->order; if (true === $this->desc) { $order .= ' DESC'; } } $group = $this->group ? 'GROUP BY ' . $this->group : ''; $sql = sprintf('SELECT %s FROM %s WHERE %s %s ORDER BY %s', $columns, $this->tables, $this->conditions, $group, $order); if (null !== $this->per_page) { $sql .= sprintf(' LIMIT %d,%d', $start, $this->per_page); } foreach (DB::getInstance()->iterate($sql) as $row) { if ($this->modifier) { call_user_func_array($this->modifier, [&$row]); } yield $row; } } public function loadFromQueryString() { if (!empty($_GET['export'])) { $this->export($this->title, $_GET['export']); exit; } if (!empty($_GET['o'])) { $this->orderBy($_GET['o'], !empty($_GET['d'])); } if (!empty($_GET['p'])) { $this->page = (int)$_GET['p']; } } } |
Added src/include/lib/Garradin/Entities/Accounting/Account.php version [bfec22341c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | <?php namespace Garradin\Entities\Accounting; use DateTimeInterface; use Garradin\Config; use Garradin\CSV_Custom; use Garradin\DB; use Garradin\DynamicList; use Garradin\Entity; use Garradin\Utils; use Garradin\UserException; use Garradin\ValidationException; use Garradin\Accounting\Charts; class Account extends Entity { const TABLE = 'acc_accounts'; // Actif const ASSET = 1; // Passif const LIABILITY = 2; // Passif ou actif const ASSET_OR_LIABILITY = 3; // Charge const EXPENSE = 4; // Produit const REVENUE = 5; const POSITIONS_NAMES = [ '', 'Actif', 'Passif', 'Actif ou passif', 'Charge', 'Produit', ]; const TYPE_NONE = 0; const TYPE_BANK = 1; const TYPE_CASH = 2; /** * Outstanding transaction accounts (like cheque or card payments) */ const TYPE_OUTSTANDING = 3; const TYPE_THIRD_PARTY = 4; const TYPE_EXPENSE = 5; const TYPE_REVENUE = 6; const TYPE_ANALYTICAL = 7; const TYPE_VOLUNTEERING = 8; const TYPE_OPENING = 9; const TYPE_CLOSING = 10; const TYPE_POSITIVE_RESULT = 11; const TYPE_NEGATIVE_RESULT = 12; const TYPES_NAMES = [ '', 'Banque', 'Caisse', 'Attente d\'encaissement', 'Tiers', 'Dépenses', 'Recettes', 'Analytique', 'Bénévolat', 'Ouverture', 'Clôture', 'Résultat excédentaire', 'Résultat déficitaire', ]; const LIST_COLUMNS = [ 'id' => [ 'select' => 't.id', 'label' => 'N°', ], 'id_line' => [ 'select' => 'l.id', ], 'date' => [ 'label' => 'Date', 'select' => 't.date', 'order' => 'date %s, id %1$s', ], 'debit' => [ 'select' => 'l.debit', 'label' => 'Débit', ], 'credit' => [ 'select' => 'l.credit', 'label' => 'Crédit', ], 'change' => [ 'select' => '(l.credit - l.debit) * %d', 'label' => 'Mouvement', ], 'sum' => [ 'select' => NULL, 'label' => 'Solde cumulé', 'only_with_order' => 'date', ], 'reference' => [ 'label' => 'Pièce comptable', 'select' => 't.reference', ], 'type' => [ 'select' => 't.type', ], 'label' => [ 'select' => 't.label', 'label' => 'Libellé', ], 'line_label' => [ 'select' => 'l.label', 'label' => 'Libellé ligne' ], 'line_reference' => [ 'label' => 'Réf. ligne', 'select' => 'l.reference', ], 'id_analytical' => [ 'select' => 'l.id_analytical', ], 'code_analytical' => [ 'label' => 'Projet', 'select' => 'b.code', ], 'status' => [ 'select' => 't.status', ], ]; protected $id; protected $id_chart; protected $code; protected $label; protected $description; protected $position; protected $type; protected $user = 0; protected $_types = [ 'id' => 'int', 'id_chart' => 'int', 'code' => 'string', 'label' => 'string', 'description' => '?string', 'position' => 'int', 'type' => 'int', 'user' => 'int', ]; protected $_form_rules = [ 'code' => 'required|string|alpha_num|max:10', 'label' => 'required|string|max:200', 'description' => 'string|max:2000', 'position' => 'required|numeric|min:0', 'type' => 'required|numeric|min:0', ]; public function selfCheck(): void { $db = DB::getInstance(); $this->assert(!empty($this->id_chart), 'Aucun plan comptable lié'); $where = 'code = ? AND id_chart = ?'; $where .= $this->exists() ? sprintf(' AND id != %d', $this->id()) : ''; if ($db->test(self::TABLE, $where, $this->code, $this->id_chart)) { throw new ValidationException(sprintf('Le code "%s" est déjà utilisé par un autre compte.', $this->code)); } $this->assert(array_key_exists($this->type, self::TYPES_NAMES), 'Type invalide'); $this->assert(array_key_exists($this->position, self::POSITIONS_NAMES), 'Position invalide'); $this->assert($this->user === 0 || $this->user === 1); parent::selfCheck(); } public function listJournal(int $year_id, bool $simple = false) { $columns = self::LIST_COLUMNS; $tables = 'acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction LEFT JOIN acc_accounts b ON b.id = l.id_analytical'; $conditions = sprintf('l.id_account = %d AND t.id_year = %d', $this->id(), $year_id); $sum = 0; $reverse = $simple && self::isReversed($this->type) ? -1 : 1; if ($simple) { unset($columns['debit']['label'], $columns['credit']['label'], $columns['line_label']); $columns['line_reference']['label'] = 'Réf. paiement'; $columns['change']['select'] = sprintf($columns['change']['select'], $reverse); } else { unset($columns['change']); } $list = new DynamicList($columns, $tables, $conditions); $list->orderBy('date', false); $list->setCount('COUNT(*)'); $list->setPageSize(null); $list->setModifier(function (&$row) use (&$sum, $reverse) { if (property_exists($row, 'sum')) { $sum += isset($row->change) ? $row->change : ($row->credit - $row->debit); $row->sum = $sum; } $row->date = \DateTime::createFromFormat('!Y-m-d', $row->date); }); $list->setExportCallback(function (&$row) { static $columns = ['change', 'sum', 'credit', 'debit']; foreach ($columns as $key) { if (isset($row->$key)) { $row->$key = Utils::money_format($row->$key, '.', '', false); } } }); return $list; } static public function isReversed(int $type): bool { return in_array($type, [self::TYPE_BANK, self::TYPE_CASH, self::TYPE_OUTSTANDING, self::TYPE_EXPENSE, self::TYPE_THIRD_PARTY]); } public function getReconcileJournal(int $year_id, DateTimeInterface $start_date, DateTimeInterface $end_date, bool $only_non_reconciled = false) { if ($end_date < $start_date) { throw new ValidationException('La date de début ne peut être avant la date de fin.'); } $condition = $only_non_reconciled ? ' AND l.reconciled = 0' : ''; $db = DB::getInstance(); $sql = 'SELECT l.debit, l.credit, t.id, t.date, t.reference, l.reference AS line_reference, t.label, l.label AS line_label, l.reconciled, l.id AS id_line FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction WHERE l.id_account = ? AND t.id_year = ? AND t.date >= ? AND t.date <= ? %s ORDER BY t.date, t.id;'; $rows = $db->iterate(sprintf($sql, $condition), $this->id(), $year_id, $start_date->format('Y-m-d'), $end_date->format('Y-m-d')); $sum = $this->getSumAtDate($year_id, $start_date); $reconciled_sum = $this->getSumAtDate($year_id, $start_date, true); $start_sum = false; foreach ($rows as $row) { if (!$start_sum) { yield (object) ['sum' => $sum, 'date' => $start_date]; $start_sum = true; } $row->date = \DateTime::createFromFormat('Y-m-d', $row->date); $sum += ($row->credit - $row->debit); $row->running_sum = $sum; if ($row->reconciled) { $reconciled_sum += ($row->credit - $row->debit); } $row->reconciled_sum = $reconciled_sum; yield $row; } if (!$only_non_reconciled) { yield (object) ['sum' => $sum, 'reconciled_sum' => $reconciled_sum, 'date' => $end_date]; } } public function mergeReconcileJournalAndCSV(\Generator $journal, CSV_Custom $csv) { $lines = []; $csv = iterator_to_array($csv->iterate()); $journal = iterator_to_array($journal); $i = 0; $sum = 0; foreach ($csv as $k => &$line) { try { $date = \DateTime::createFromFormat('!d/m/Y', $line->date); $line->amount = ($line->amount < 0 ? -1 : 1) * Utils::moneyToInteger($line->amount); if (!$date) { throw new UserException('Date invalide : ' . $line->date); } $line->date = $date; } catch (UserException $e) { throw new UserException(sprintf('Ligne %d : %s', $k, $e->getMessage())); } } unset($line); foreach ($journal as $j) { $id = $j->date->format('Ymd') . '.' . $i++; $row = (object) ['csv' => null, 'journal' => $j]; if (isset($j->debit)) { foreach ($csv as &$line) { if (!isset($line->date)) { continue; } if ($j->date->format('Ymd') == $line->date->format('Ymd') && ($j->credit == abs($line->amount) || $j->debit == abs($line->amount))) { $row->csv = $line; $line = null; break; } } } $lines[$id] = $row; } unset($j); foreach ($csv as $line) { if (null == $line) { continue; } $id = $line->date->format('Ymd') . '.' . ($i++); $lines[$id] = (object) ['csv' => $line, 'journal' => null]; } ksort($lines); $prev = null; foreach ($lines as &$line) { $line->add = false; if (isset($line->csv)) { $sum += $line->csv->amount; $line->csv->running_sum = $sum; if ($prev && ($prev->date->format('Ymd') != $line->csv->date->format('Ymd') || $prev->label != $line->csv->label)) { $prev = null; } } if (isset($line->csv) && isset($line->journal)) { $prev = null; } if (isset($line->csv) && !isset($line->journal) && !$prev) { $line->add = true; $prev = $line->csv; } } return $lines; } public function getDepositJournal(int $year_id, array $checked = []): \Generator { $res = DB::getInstance()->iterate('SELECT l.debit, l.credit, t.id, t.date, t.reference, l.reference AS line_reference, t.label, l.label AS line_label, l.reconciled, l.id AS id_line, l.id_account FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction WHERE t.id_year = ? AND l.id_account = ? AND l.credit = 0 AND NOT (t.status & ?) ORDER BY t.date, t.id;', $year_id, $this->id(), Transaction::STATUS_DEPOSIT); $sum = 0; foreach ($res as $row) { $row->date = \DateTime::createFromFormat('Y-m-d', $row->date); $sum += ($row->credit - $row->debit); $row->running_sum = $sum; $row->checked = array_key_exists($row->id, $checked); yield $row; } } public function getSum(int $year_id, bool $simple = false): int { $sum = (int) DB::getInstance()->firstColumn('SELECT SUM(l.credit) - SUM(l.debit) FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction wHERE l.id_account = ? AND t.id_year = ?;', $this->id(), $year_id); if ($simple && self::isReversed($this->type)) { $sum *= -1; } return $sum; } public function getSumAtDate(int $year_id, DateTimeInterface $date, bool $reconciled_only = false): int { $sql = sprintf('SELECT SUM(l.credit) - SUM(l.debit) FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction wHERE l.id_account = ? AND t.id_year = ? AND t.date < ? %s;', $reconciled_only ? 'AND l.reconciled = 1' : ''); return (int) DB::getInstance()->firstColumn($sql, $this->id(), $year_id, $date->format('Y-m-d')); } public function importSimpleForm(array $translate_type_position, array $translate_type_codes, ?array $source = null) { if (null === $source) { $source = $_POST; } if (empty($source['type'])) { throw new UserException('Le type est obligatoire dans ce formulaire'); } $type = (int) $source['type']; if (array_key_exists($type, $translate_type_position)) { $source['position'] = $translate_type_position[$type]; } else { $source['position'] = self::ASSET_OR_LIABILITY; } if (array_key_exists($type, $translate_type_codes)) { $source['code'] = $translate_type_codes[$type]; } $this->importForm($source); } public function importLimitedForm(?array $source = null) { if (null === $source) { $source = $_POST; } $data = array_intersect_key($source, array_flip(['type', 'description'])); parent::import($data); } public function canDelete(): bool { return !DB::getInstance()->firstColumn(sprintf('SELECT 1 FROM %s WHERE id_account = ? LIMIT 1;', Line::TABLE), $this->id()); } /** * An account properties (position, label and code) can only be changed if: * * it's either a user-created account or an account part of a user-created chart * * has no transactions in a closed year * @return bool */ public function canEdit(): bool { $db = DB::getInstance(); $sql = sprintf('SELECT 1 FROM %s l INNER JOIN %s t ON t.id = l.id_transaction INNER JOIN %s y ON y.id = t.id_year WHERE l.id_account = ? AND y.closed = 1 LIMIT 1;', Line::TABLE, Transaction::TABLE, Year::TABLE); $has_transactions_in_closed_year = $db->firstColumn($sql, $this->id()); if ($has_transactions_in_closed_year) { return false; } if ($this->user) { return true; } return $db->test(Chart::TABLE, 'id = ? AND code IS NULL', $this->id_chart); } public function chart(): Chart { return Charts::get($this->id_chart); } public function save(): bool { Config::getInstance()->set('last_chart_change', time()); return parent::save(); } } |
Added src/include/lib/Garradin/Entities/Accounting/Chart.php version [297b8e2f31].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php namespace Garradin\Entities\Accounting; use Garradin\DB; use Garradin\Entity; use Garradin\Utils; use Garradin\ValidationException; use Garradin\UserException; use Garradin\Accounting\Accounts; class Chart extends Entity { const TABLE = 'acc_charts'; protected $id; protected $label; protected $country; protected $code; protected $archived = 0; protected $_types = [ 'id' => 'int', 'label' => 'string', 'country' => 'string', 'code' => '?string', 'archived' => 'int', ]; protected $_form_rules = [ 'label' => 'required|string|max:200', 'country' => 'required|string|size:2', 'archived' => 'numeric|min:0|max:1' ]; public function selfCheck(): void { parent::selfCheck(); $this->assert(Utils::getCountryName($this->country), 'Le code pays doit être un code ISO valide'); $this->assert($this->archived === 0 || $this->archived === 1); } public function accounts() { return new Accounts($this->id()); } public function canDelete() { return !DB::getInstance()->firstColumn(sprintf('SELECT 1 FROM %s WHERE id_chart = ? LIMIT 1;', Year::TABLE), $this->id()); } } |
Added src/include/lib/Garradin/Entities/Accounting/Line.php version [0fde672e4f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <?php namespace Garradin\Entities\Accounting; use Garradin\Entity; use Garradin\ValidationException; use Garradin\Utils; class Line extends Entity { const TABLE = 'acc_transactions_lines'; protected $id; protected $id_transaction; protected $id_account; protected $credit = 0; protected $debit = 0; protected $reference; protected $label; protected $reconciled = 0; protected $id_analytical; protected $_types = [ 'id' => 'int', 'id_transaction' => 'int', 'id_account' => 'int', 'credit' => 'int', 'debit' => 'int', 'reference' => '?string', 'label' => '?string', 'reconciled' => 'int', 'id_analytical' => '?int', ]; protected $_form_rules = [ 'id_account' => 'required|numeric|in_table:acc_accounts,id', 'id_analytical' => 'numeric|in_table:acc_accounts,id', 'credit' => 'money|min:0', 'debit' => 'money|min:0', 'reference' => 'string|max:200', 'label' => 'string|max:200', ]; public function filterUserValue(string $type, $value, string $key) { if ($key == 'credit' || $key == 'debit') { $value = Utils::moneyToInteger($value); } elseif ($key == 'id_analytical' && $value == 0) { $value = null; } $value = parent::filterUserValue($type, $value, $key); return $value; } public function selfCheck(): void { parent::selfCheck(); $this->assert($this->credit || $this->debit, 'Aucun montant au débit ou au crédit'); $this->assert(($this->credit * $this->debit) === 0 && ($this->credit + $this->debit) > 0, 'Ligne non équilibrée : crédit ou débit doit valoir zéro.'); $this->assert($this->id_transaction, 'Aucun mouvement n\'a été indiqué pour cette ligne.'); $this->assert($this->reconciled === 0 || $this->reconciled === 1); } } |
Added src/include/lib/Garradin/Entities/Accounting/Transaction.php version [7f6416e57a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 | <?php namespace Garradin\Entities\Accounting; use KD2\DB\EntityManager; use Garradin\Entity; use Garradin\Fichiers; use Garradin\Accounting\Accounts; use Garradin\ValidationException; use Garradin\DB; use Garradin\Config; use Garradin\Utils; use Garradin\UserException; class Transaction extends Entity { const TABLE = 'acc_transactions'; const TYPE_ADVANCED = 0; const TYPE_REVENUE = 1; const TYPE_EXPENSE = 2; const TYPE_TRANSFER = 3; const TYPE_DEBT = 4; const TYPE_CREDIT = 5; const STATUS_WAITING = 1; const STATUS_PAID = 2; const STATUS_DEPOSIT = 4; const STATUS_NAMES = [ 1 => 'En attente de règlement', 2 => 'Réglé', 4 => 'Déposé en banque', ]; const TYPES_NAMES = [ 'Avancé', 'Recette', 'Dépense', 'Virement', 'Dette', 'Créance', ]; protected $id; protected $type; protected $status = 0; protected $label; protected $notes; protected $reference; protected $date; protected $validated = 0; protected $hash; protected $prev_hash; protected $id_year; protected $id_creator; protected $id_related; protected $_types = [ 'id' => 'int', 'type' => 'int', 'status' => 'int', 'label' => 'string', 'notes' => '?string', 'reference' => '?string', 'date' => 'date', 'validated' => 'bool', 'hash' => '?string', 'prev_hash' => '?string', 'id_year' => 'int', 'id_creator' => '?int', 'id_related' => '?int', ]; protected $_form_rules = [ 'label' => 'required|string|max:200', 'notes' => 'string|max:20000', 'reference' => 'string|max:200', 'date' => 'required|date_format:d/m/Y', ]; protected $_lines; protected $_old_lines = []; protected $_related; static public function getTypeFromAccountType(int $account_type) { switch ($account_type) { case Account::TYPE_REVENUE: return self::TYPE_REVENUE; case Account::TYPE_EXPENSE: return self::TYPE_EXPENSE; case Account::TYPE_THIRD_PARTY: return self::TYPE_DEBT; default: return self::TYPE_TRANSFER; } } public function getLinesWithAccounts() { $em = EntityManager::getInstance(Line::class); return $em->DB()->get('SELECT l.*, a.label AS account_name, a.code AS account_code, b.label AS analytical_name FROM acc_transactions_lines l INNER JOIN acc_accounts a ON a.id = l.id_account LEFT JOIN acc_accounts b ON b.id = l.id_analytical WHERE l.id_transaction = ? ORDER BY l.id;', $this->id); } public function getLines($with_accounts = false) { if (null === $this->_lines && $this->exists()) { $em = EntityManager::getInstance(Line::class); $this->_lines = $em->all('SELECT * FROM @TABLE WHERE id_transaction = ? ORDER BY id;', $this->id); } elseif (null === $this->_lines) { $this->_lines = []; } return $this->_lines; } public function removeLine(Line $remove) { $new = []; foreach ($this->getLines() as $line) { if ($line->id === $remove->id) { $this->_old_lines[] = $remove; } else { $new[] = $line; } } $this->_lines = $new; } public function resetLines() { $this->_old_lines = $this->getLines(); $this->_lines = []; } public function getLine(int $id) { foreach ($this->getLines() as $line) { if ($line->id === $id) { return $line; } } return null; } public function getLinesCreditSum() { $sum = 0; foreach ($this->getLines() as $line) { $sum += $line->credit; } return $sum; } public function getTypesAccounts() { if ($this->type == self::TYPE_ADVANCED) { return []; } $debit = null; $credit = null; $lines = $this->getLinesWithAccounts(); foreach ($lines as $line) { $account = [$line->id_account => sprintf('%s — %s', $line->account_code, $line->account_name)]; if ($line->debit) { $debit = $account; } else { $credit = $account; } } $type = $this->getTypesDetails()[$this->type]; return [ $type->accounts[0]->position == 'credit' ? $credit : $debit, $type->accounts[1]->position == 'credit' ? $credit : $debit, ]; } /* public function getHash() { if (!$this->id_year) { throw new \LogicException('Il n\'est pas possible de hasher un mouvement qui n\'est pas associé à un exercice'); } static $keep_keys = [ 'label', 'notes', 'reference', 'date', 'validated', 'prev_hash', ]; $hash = hash_init('sha256'); $values = $this->asArray(); $values = array_intersect_key($values, $keep_keys); hash_update($hash, implode(',', array_keys($values))); hash_update($hash, implode(',', $values)); foreach ($this->getLines() as $line) { hash_update($hash, implode(',', [$line->compte, $line->debit, $line->credit])); } return hash_final($hash, false); } public function checkHash() { return hash_equals($this->getHash(), $this->hash); } */ public function addLine(Line $line) { $this->_lines[] = $line; } public function sum(): int { $sum = 0; foreach ($this->getLines() as $line) { $sum += $line->credit; // Because credit == debit, we only use credit } return $sum; } public function save(): bool { if ($this->validated && !isset($this->_modified['validated'])) { throw new ValidationException('Il n\'est pas possible de modifier une écriture qui a été validé'); } $db = DB::getInstance(); if ($db->test(Year::TABLE, 'id = ? AND closed = 1', $this->id_year)) { throw new ValidationException('Il n\'est pas possible de modifier une écriture qui fait partie d\'un exercice clôturé'); } if (!parent::save()) { return false; } foreach ($this->getLines() as $line) { $line->id_transaction = $this->id(); $line->save(); } foreach ($this->_old_lines as $line) { $line->delete(); } // Remove flag if ((self::TYPE_DEBT == $this->type || self::TYPE_CREDIT == $this->type) && $this->_related) { $this->_related->removeStatus(self::STATUS_WAITING); $this->_related->addStatus(self::STATUS_PAID); $this->_related->save(); } return true; } public function removeStatus(int $property) { $this->set('status', $this->status & ~$property); } public function addStatus(int $property) { $this->set('status', $this->status | $property); } public function delete(): bool { if ($this->validated) { throw new ValidationException('Il n\'est pas possible de supprimer une écriture qui a été validée'); } $db = DB::getInstance(); if ($db->test(Year::TABLE, 'id = ? AND closed = 1', $this->id_year)) { throw new ValidationException('Il n\'est pas possible de supprimer une écriture qui fait partie d\'un exercice clôturé'); } Fichiers::deleteLinkedFiles(Fichiers::LIEN_COMPTA, $this->id()); return parent::delete(); } public function selfCheck(): void { parent::selfCheck(); $db = DB::getInstance(); $config = Config::getInstance(); // ID d'exercice obligatoire if (null === $this->id_year) { throw new \LogicException('Aucun exercice spécifié.'); } if (!$db->test(Year::TABLE, 'id = ? AND start_date <= ? AND end_date >= ?;', $this->id_year, $this->date->format('Y-m-d'), $this->date->format('Y-m-d'))) { throw new ValidationException('La date ne correspond pas à l\'exercice sélectionné : ' . $this->date->format('d/m/Y')); } $total = 0; $lines = $this->getLines(); foreach ($lines as $line) { $total += $line->credit; $total -= $line->debit; } if (0 !== $total) { throw new ValidationException(sprintf('Écriture non équilibrée : déséquilibre (%s) entre débits et crédits', Utils::money_format($total))); } if (!array_key_exists($this->type, self::TYPES_NAMES)) { throw new ValidationException('Type d\'écriture inconnu : ' . $this->type); } } public function importFromDepositForm(?array $source = null): void { if (null === $source) { $source = $_POST; } if (empty($source['amount'])) { throw new UserException('Montant non précisé'); } $this->type = self::TYPE_TRANSFER; $amount = $source['amount']; $key = 'account_transfer'; $account = isset($source[$key]) && @count($source[$key]) ? key($source[$key]) : null; $line = new Line; $line->importForm([ 'debit' => $amount, 'credit' => 0, 'id_account' => $account, ]); $this->addLine($line); $this->importForm($source); } public function importFromNewForm(?array $source = null): void { if (null === $source) { $source = $_POST; } if (!isset($source['type'])) { throw new ValidationException('Type d\'écriture inconnu'); } $type = $source['type']; $this->importForm($source); if (self::TYPE_ADVANCED == $type) { $lines = Utils::array_transpose($source['lines']); foreach ($lines as $i => $line) { $line['id_account'] = @count($line['account']) ? key($line['account']) : null; if (!$line['id_account']) { throw new ValidationException('Numéro de compte invalide sur la ligne ' . ($i+1)); } $line = (new Line)->import($line); $this->addLine($line); } } else { $details = self::getTypesDetails(); if (!array_key_exists($type, $details)) { throw new ValidationException('Type d\'écriture inconnu'); } if (empty($this->_related) && ($type == self::TYPE_DEBT || $type == self::TYPE_CREDIT)) { $this->status = self::STATUS_WAITING; } if (empty($source['amount'])) { throw new UserException('Montant non précisé'); } $amount = $source['amount']; // Fill lines using a pre-defined setup obtained from getTypesDetails foreach ($details[$type]->accounts as $k => $account) { $credit = $account->position == 'credit' ? $amount : 0; $debit = $account->position == 'debit' ? $amount : 0; $key = sprintf('account_%d_%d', $type, $k); $account = isset($source[$key]) && @count($source[$key]) ? key($source[$key]) : null; $line = new Line; $line->importForm([ 'reference' => $source['payment_reference'], 'credit' => $credit, 'debit' => $debit, 'id_account' => $account, 'id_analytical' => !empty($source['id_analytical']) ? $source['id_analytical'] : null, ]); $this->addLine($line); } } } public function importFromEditForm(?array $source = null): void { if (null === $source) { $source = $_POST; } $this->resetLines(); $this->importFromNewForm($source); } public function importFromBalanceForm(Year $year, ?array $source = null): void { if (null === $source) { $source = $_POST; } if (!isset($source['lines']) || !is_array($source['lines'])) { throw new ValidationException('Aucun contenu trouvé dans le formulaire.'); } $this->label = 'Balance d\'ouverture'; $this->date = $year->start_date; $this->id_year = $year->id(); $this->type = self::TYPE_ADVANCED; try { $lines = Utils::array_transpose($source['lines']); } catch (\LogicException $e) { throw new ValidationException('Aucun compte sélectionné pour certaines lignes.'); } $debit = $credit = 0; foreach ($lines as $line) { $line['id_account'] = @count($line['account']) ? key($line['account']) : null; $line = (new Line)->importForm($line); $this->addLine($line); $debit += $line->debit; $credit += $line->credit; } if ($debit != $credit) { // Add final balance line $line = new Line; if ($debit > $credit) { $line->debit = $debit - $credit; } else { $line->credit = $credit - $debit; } $open_account = EntityManager::findOne(Account::class, 'SELECT * FROM @TABLE WHERE id_chart = ? AND type = ? LIMIT 1;', $year->id_chart, Account::TYPE_OPENING); if (!$open_account) { throw new ValidationException('Aucun compte favori de bilan d\'ouverture n\'existe dans le plan comptable'); } $line->id_account = $open_account->id(); $this->addLine($line); } } public function year() { return EntityManager::findOneById(Year::class, $this->id_year); } public function listFiles() { return Fichiers::listLinkedFiles(Fichiers::LIEN_COMPTA, $this->id()); } public function linkToUser(int $user_id, ?int $service_id = null) { $db = EntityManager::getInstance(self::class)->DB(); return $db->preparedQuery('INSERT OR IGNORE INTO acc_transactions_users (id_transaction, id_user, id_service_user) VALUES (?, ?, ?);', $this->id(), $user_id, $service_id); } public function updateLinkedUsers(array $users) { $db = EntityManager::getInstance(self::class)->DB(); $db->begin(); $sql = sprintf('DELETE FROM acc_transactions_users WHERE id_transaction = ? AND id_service_user IS NULL AND %s;', $db->where('id_user', 'NOT IN', $users)); $db->preparedQuery($sql, $this->id()); foreach ($users as $id) { $db->preparedQuery('INSERT OR IGNORE INTO acc_transactions_users (id_transaction, id_user) VALUES (?, ?);', $this->id(), $id); } $db->commit(); } public function listLinkedUsers() { $db = EntityManager::getInstance(self::class)->DB(); $identity_column = Config::getInstance()->get('champ_identite'); $sql = sprintf('SELECT m.id, m.%s AS identity, l.id_service_user FROM membres m INNER JOIN acc_transactions_users l ON l.id_user = m.id WHERE l.id_transaction = ?;', $identity_column); return $db->get($sql, $this->id()); } public function listLinkedUsersAssoc() { $db = EntityManager::getInstance(self::class)->DB(); $identity_column = Config::getInstance()->get('champ_identite'); $sql = sprintf('SELECT m.id, m.%s AS identity FROM membres m INNER JOIN acc_transactions_users l ON l.id_user = m.id WHERE l.id_transaction = ?;', $identity_column); return $db->getAssoc($sql, $this->id()); } static public function getTypesDetails() { $details = [ self::TYPE_REVENUE => [ 'accounts' => [ [ 'label' => 'Type de recette', 'targets' => [Account::TYPE_REVENUE], 'position' => 'credit', ], [ 'label' => 'Compte d\'encaissement', 'targets' => [Account::TYPE_BANK, Account::TYPE_CASH, Account::TYPE_OUTSTANDING], 'position' => 'debit', ], ], 'label' => self::TYPES_NAMES[self::TYPE_REVENUE], ], self::TYPE_EXPENSE => [ 'accounts' => [ [ 'label' => 'Type de dépense', 'targets' => [Account::TYPE_EXPENSE], 'position' => 'debit', ], [ 'label' => 'Compte de décaissement', 'targets' => [Account::TYPE_BANK, Account::TYPE_CASH, Account::TYPE_OUTSTANDING], 'position' => 'credit', ], ], 'label' => self::TYPES_NAMES[self::TYPE_EXPENSE], 'help' => null, ], self::TYPE_TRANSFER => [ 'accounts' => [ [ 'label' => 'De', 'targets' => [Account::TYPE_BANK, Account::TYPE_CASH, Account::TYPE_OUTSTANDING], 'position' => 'debit', ], [ 'label' => 'Vers', 'targets' => [Account::TYPE_BANK, Account::TYPE_CASH, Account::TYPE_OUTSTANDING], 'position' => 'credit', ], ], 'label' => self::TYPES_NAMES[self::TYPE_TRANSFER], 'help' => 'Dépôt en banque, virement interne, etc.', ], self::TYPE_DEBT => [ 'accounts' => [ [ 'label' => 'Compte de tiers', 'targets' => [Account::TYPE_THIRD_PARTY], 'position' => 'credit', ], [ 'label' => 'Type de dette (dépense)', 'targets' => [Account::TYPE_EXPENSE], 'position' => 'debit', ], ], 'label' => self::TYPES_NAMES[self::TYPE_DEBT], 'help' => 'Quand l\'association doit de l\'argent à un membre ou un fournisseur', ], self::TYPE_CREDIT => [ 'accounts' => [ [ 'label' => 'Compte de tiers', 'targets' => [Account::TYPE_THIRD_PARTY], 'position' => 'debit', ], [ 'label' => 'Type de créance (recette)', 'targets' => [Account::TYPE_REVENUE], 'position' => 'credit', ], ], 'label' => self::TYPES_NAMES[self::TYPE_CREDIT], 'help' => 'Quand un membre ou un fournisseur doit de l\'argent à l\'association', ], self::TYPE_ADVANCED => [ 'accounts' => [], 'label' => self::TYPES_NAMES[self::TYPE_ADVANCED], 'help' => 'Choisir les comptes du plan comptable, ventiler une écriture sur plusieurs comptes, etc.', ], ]; foreach ($details as $key => &$type) { $type = (object) $type; $type->id = $key; foreach ($type->accounts as &$account) { $account = (object) $account; $account->targets_string = implode(':', $account->targets); } } return $details; } public function payOffFrom(int $id): \stdClass { $this->_related = EntityManager::findOneById(self::class, $id); if (!$this->_related) { throw new \LogicException('Écriture d\'origine invalide'); } $this->id_related = $this->_related->id(); $this->label = ($this->_related->type == Transaction::TYPE_DEBT ? 'Règlement de dette : ' : 'Règlement de créance : ') . $this->_related->label; $this->type = $this->_related->type; $out = (object) [ 'id' => $this->_related->id, 'sum' => $this->_related->sum(), 'id_account' => null, 'form_account_name' => sprintf('account_%d_%d', $this->type, $this->_related->type == self::TYPE_DEBT ? 1 : 0), 'form_target_name' => sprintf('account_%d_%d', $this->type, $this->_related->type == self::TYPE_DEBT ? 0 : 1), ]; foreach ($this->_related->getLines() as $line) { if (($this->_related->type == self::TYPE_DEBT && $line->debit) || ($this->_related->type == self::TYPE_CREDIT && $line->credit)) { // Skip the type of debt/credit, just keep the thirdparty account continue; } $out->id_account = $line->id_account; break; } return $out; } } |
Added src/include/lib/Garradin/Entities/Accounting/Year.php version [efb670bde0].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | <?php namespace Garradin\Entities\Accounting; use KD2\DB\EntityManager; use Garradin\DB; use Garradin\Entity; use Garradin\Fichiers; use Garradin\UserException; use Garradin\Accounting\Accounts; class Year extends Entity { const TABLE = 'acc_years'; protected $id; protected $label; protected $start_date; protected $end_date; protected $closed = 0; protected $id_chart; protected $_types = [ 'id' => 'int', 'label' => 'string', 'start_date' => 'date', 'end_date' => 'date', 'closed' => 'int', 'id_chart' => 'int', ]; protected $_form_rules = [ 'label' => 'required|string|max:200', 'start_date' => 'required|date_format:d/m/Y', 'end_date' => 'required|date_format:d/m/Y', ]; public function selfCheck(): void { parent::selfCheck(); $this->assert($this->start_date < $this->end_date, 'La date de fin doit être postérieure à la date de début'); $this->assert($this->closed === 0 || $this->closed === 1); $this->assert($this->closed == 1 || !isset($this->_modified['closed']), 'Il est interdit de réouvrir un exercice clôturé'); $db = DB::getInstance(); $this->assert($this->id_chart !== null); if ($this->exists()) { $this->assert( !$db->test(Transaction::TABLE, 'id_year = ? AND date < ?', $this->id(), $this->start_date->format('Y-m-d')), 'Des mouvements de cet exercice ont une date antérieure à la date de début de l\'exercice.' ); $this->assert( !$db->test(Transaction::TABLE, 'id_year = ? AND date > ?', $this->id(), $this->end_date->format('Y-m-d')), 'Des mouvements de cet exercice ont une date postérieure à la date de fin de l\'exercice.' ); } } public function close(int $user_id): void { if ($this->closed) { throw new \LogicException('Cet exercice est déjà clôturé'); } $this->set('closed', 1); $this->save(); } public function delete(): bool { // Manual delete of transactions, as there is a voluntary safeguard in SQL: no cascade DB::getInstance()->preparedQuery('DELETE FROM acc_transactions WHERE id_year = ?;', $this->id()); // Clean up files Fichiers::deleteUnlinkedFiles(); return parent::delete(); } public function countTransactions(): int { $db = DB::getInstance(); return $db->count(Transaction::TABLE, $db->where('id_year', $this->id())); } public function chart() { return EntityManager::findOneById(Chart::class, $this->id_chart); } public function accounts() { return new Accounts($this->id_chart); } } |
Added src/include/lib/Garradin/Entities/Services/Fee.php version [6f825919cc].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | <?php namespace Garradin\Entities\Services; use Garradin\Config; use Garradin\DB; use Garradin\DynamicList; use Garradin\Entity; use Garradin\ValidationException; use Garradin\Utils; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Year; use KD2\DB\EntityManager; class Fee extends Entity { const TABLE = 'services_fees'; protected $id; protected $label; protected $description; protected $amount; protected $formula; protected $id_service; protected $id_account; protected $id_year; protected $_types = [ 'id' => 'int', 'label' => 'string', 'description' => '?string', 'amount' => '?int', 'formula' => '?string', 'id_service' => 'int', 'id_account' => '?int', 'id_year' => '?int', ]; public function filterUserValue(string $type, $value, string $key) { if ($key == 'amount' && $value !== null) { $value = Utils::moneyToInteger($value); } return $value; } public function importForm(array $source = null) { if (null === $source) { $source = $_POST; } if (isset($source['account']) && is_array($source['account'])) { $source['id_account'] = (int)key($source['account']); } if (isset($source['amount_type'])) { if ($source['amount_type'] == 2) { $source['amount'] = null; } elseif ($source['amount_type'] == 1) { $source['formula'] = null; } else { $source['amount'] = $source['formula'] = null; } } if (empty($source['accounting'])) { $source['id_account'] = $source['id_year'] = null; } return parent::importForm($source); } public function selfCheck(): void { $db = DB::getInstance(); parent::selfCheck(); $this->assert(trim($this->label) !== '', 'Le libellé doit être renseigné'); $this->assert(strlen($this->label) <= 200, 'Le libellé doit faire moins de 200 caractères'); $this->assert(strlen($this->description) <= 2000, 'La description doit faire moins de 2000 caractères'); $this->assert(null === $this->amount || $this->amount > 0, 'Le montant est invalide : ' . $this->amount); $this->assert($this->id_service, 'Aucun service n\'a été indiqué pour ce tarif.'); $this->assert((null === $this->id_account && null === $this->id_year) || (null !== $this->id_account && null !== $this->id_year), 'Le compte doit être indiqué avec l\'exercice'); $this->assert(null === $this->id_account || $db->test(Account::TABLE, 'id = ?', $this->id_account), 'Le compte indiqué n\'existe pas'); $this->assert(null === $this->id_year || $db->test(Year::TABLE, 'id = ?', $this->id_year), 'L\'exercice indiqué n\'existe pas'); $this->assert(null === $this->formula || $this->checkFormula(), 'Formule de calcul invalide'); $this->assert(null === $this->amount || null === $this->formula, 'Il n\'est pas possible de spécifier à la fois une formule et un montant'); } public function getAmountForUser(int $user_id): ?int { if ($this->amount) { return $this->amount; } elseif ($this->formula) { $db = DB::getInstance(); return (int) $db->firstColumn($this->getFormulaSQL(), $user_id); } return null; } protected function getFormulaSQL() { return sprintf('SELECT %s FROM membres WHERE id = ?;', $this->formula); } protected function checkFormula() { try { $db = DB::getInstance(); $sql = $this->getFormulaSQL(); $db->protectSelect(['membres' => null], $sql); return true; } catch (\Exception $e) { throw $e; return false; } } public function service() { return EntityManager::findOneById(Service::class, $this->id_service); } public function paidUsersList(): DynamicList { $identity = Config::getInstance()->get('champ_identite'); $columns = [ 'id_user' => [ 'select' => 'su.id_user', ], 'identity' => [ 'label' => 'Membre', 'select' => 'm.' . $identity, 'order' => sprintf('transliterate_to_ascii(m.%s) COLLATE NOCASE', $identity), ], 'paid' => [ 'label' => 'Payé ?', 'select' => 'su.paid', ], 'paid_amount' => [ 'label' => 'Montant payé', 'select' => 'SUM(l.credit)', ], 'date' => [ 'label' => 'Date', 'select' => 'su.date', ], ]; $tables = 'services_users su INNER JOIN membres m ON m.id = su.id_user INNER JOIN services_fees sf ON sf.id = su.id_fee LEFT JOIN acc_transactions_users tu ON tu.id_service_user = su.id LEFT JOIN acc_transactions_lines l ON l.id_transaction = tu.id_transaction'; $conditions = sprintf('su.id_fee = %d AND su.paid = 1 AND su.expiry_date >= date()', $this->id()); $list = new DynamicList($columns, $tables, $conditions); $list->groupBy('su.id_user'); $list->orderBy('date', true); $list->setCount('COUNT(DISTINCT su.id_user)'); return $list; } public function unpaidUsersList(): DynamicList { $list = $this->paidUsersList(); $conditions = sprintf('su.id_fee = %d AND su.paid = 0', $this->id()); $list->setConditions($conditions); return $list; } public function expiredUsersList(): DynamicList { $list = $this->paidUsersList(); $conditions = sprintf('su.id_fee = %d AND su.expiry_date < date()', $this->id()); $list->setConditions($conditions); return $list; } } |
Added src/include/lib/Garradin/Entities/Services/Reminder.php version [308065935f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | <?php namespace Garradin\Entities\Services; use Garradin\DynamicList; use Garradin\Entity; use Garradin\ValidationException; use Garradin\Config; use KD2\DB\EntityManager; class Reminder extends Entity { const TABLE = 'services_reminders'; protected $id; protected $id_service; protected $delay; protected $subject; protected $body; protected $_types = [ 'id' => 'int', 'id_service' => 'int', 'delay' => 'int', 'subject' => 'string', 'body' => 'string', ]; public function selfCheck(): void { parent::selfCheck(); $this->assert($this->id_service, 'Aucun service n\'a été indiqué pour ce tarif.'); $this->assert(trim($this->subject) !== '', 'Le sujet doit être renseigné'); $this->assert(strlen($this->subject) <= 200, 'Le sujet doit faire moins de 200 caractères'); $this->assert(trim($this->body) !== '', 'Le corps du message doit être renseigné'); $this->assert(strlen($this->body) <= 64000, 'Le corps du message doit faire moins de 64.000 caractères'); $this->assert($this->delay !== null, 'Le délai de rappel doit être renseigné'); } public function service() { return EntityManager::findOneById(Service::class, $this->id_service); } public function importForm(array $source = null) { if (null === $source) { $source = $_POST; } if (isset($source['delay_type'])) { if (1 == $source['delay_type'] && !empty($source['delay_before'])) { $source['delay'] = (int)$source['delay_before'] * -1; } elseif (2 == $source['delay_type'] && !empty($source['delay_after'])) { $source['delay'] = (int)$source['delay_after']; } else { $source['delay'] = 0; } } parent::importForm($source); } public function sentList(): DynamicList { $identity = Config::getInstance()->get('champ_identite'); $columns = [ 'id_user' => [ 'select' => 'srs.id_user', ], 'identity' => [ 'label' => 'Membre', 'select' => 'm.' . $identity, 'order' => sprintf('transliterate_to_ascii(m.%s) COLLATE NOCASE', $identity), ], 'email' => [ 'label' => 'Adresse e-mail', 'select' => 'm.email', ], 'date' => [ 'label' => 'Date', 'select' => 'srs.date', ], ]; $tables = 'services_reminders_sent srs INNER JOIN membres m ON m.id = srs.id_user'; $conditions = sprintf('srs.id_reminder = %d', $this->id()); $list = new DynamicList($columns, $tables, $conditions); $list->orderBy('date', true); return $list; } } |
Added src/include/lib/Garradin/Entities/Services/Service.php version [5fa29d7db5].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | <?php namespace Garradin\Entities\Services; use Garradin\Config; use Garradin\DynamicList; use Garradin\Entity; use Garradin\ValidationException; use Garradin\Utils; use Garradin\Services\Fees; class Service extends Entity { const TABLE = 'services'; protected $id; protected $label; protected $description; protected $duration; protected $start_date; protected $end_date; protected $_types = [ 'id' => 'int', 'label' => 'string', 'description' => '?string', 'duration' => '?int', 'start_date' => '?date', 'end_date' => '?date', ]; public function selfCheck(): void { parent::selfCheck(); $this->assert(trim($this->label) !== '', 'Le libellé doit être renseigné'); $this->assert(strlen($this->label) <= 200, 'Le libellé doit faire moins de 200 caractères'); $this->assert(strlen($this->description) <= 2000, 'La description doit faire moins de 2000 caractères'); $this->assert(!isset($this->duration, $this->start_date, $this->end_date) || $this->duration || ($this->start_date && $this->end_date), 'Seulement une option doit être choisie : durée ou dates de début et de fin de validité'); $this->assert(null === $this->start_date || $this->start_date instanceof \DateTimeInterface); $this->assert(null === $this->end_date || $this->end_date instanceof \DateTimeInterface); $this->assert(null === $this->duration || (is_int($this->duration) && $this->duration > 0), 'La durée n\'est pas valide'); $this->assert(null === $this->start_date || $this->end_date > $this->start_date, 'La date de fin de validité doit être après la date de début'); } public function importForm(?array $source = null) { if (null === $source) { $source = $_POST; } if (isset($source['period'])) { if (1 == $source['period']) { $source['start_date'] = $source['end_date'] = null; } elseif (2 == $source['period']) { $source['duration'] = null; } else { $source['duration'] = $source['start_date'] = $source['end_date'] = null; } } parent::importForm($source); } public function fees() { return new Fees($this->id()); } public function paidUsersList(): DynamicList { $identity = Config::getInstance()->get('champ_identite'); $columns = [ 'id_user' => [ ], 'end_date' => [ ], 'identity' => [ 'label' => 'Membre', 'select' => 'm.' . $identity, 'order' => sprintf('transliterate_to_ascii(m.%s) COLLATE NOCASE', $identity), ], 'status' => [ 'label' => 'Statut', 'select' => 'CASE WHEN su.expiry_date < date() THEN -1 WHEN su.expiry_date >= date() THEN 1 ELSE 0 END', ], 'paid' => [ 'label' => 'Payé ?', 'select' => 'su.paid', ], 'expiry' => [ 'label' => 'Date d\'expiration', 'select' => 'MAX(su.expiry_date)', ], 'fee' => [ 'label' => 'Tarif', 'select' => 'sf.label', ], 'date' => [ 'label' => 'Date d\'inscription', 'select' => 'su.date', ], ]; $tables = 'services_users su INNER JOIN membres m ON m.id = su.id_user INNER JOIN services s ON s.id = su.id_service INNER JOIN services_fees sf ON sf.id = su.id_fee'; $conditions = sprintf('su.id_service = %d AND su.paid = 1 AND su.expiry_date >= date()', $this->id()); $list = new DynamicList($columns, $tables, $conditions); $list->groupBy('su.id_user'); $list->orderBy('date', true); $list->setCount('COUNT(DISTINCT su.id_user)'); return $list; } public function unpaidUsersList(): DynamicList { $list = $this->paidUsersList(); $conditions = sprintf('su.id_service = %d AND su.paid = 0', $this->id()); $list->setConditions($conditions); return $list; } public function expiredUsersList(): DynamicList { $list = $this->paidUsersList(); $conditions = sprintf('su.id_service = %d AND su.expiry_date < date()', $this->id()); $list->setConditions($conditions); return $list; } } |
Added src/include/lib/Garradin/Entities/Services/Service_User.php version [6dbdf76a1e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | <?php namespace Garradin\Entities\Services; use Garradin\DB; use Garradin\Entity; use Garradin\ValidationException; use Garradin\Services\Fees; use Garradin\Services\Services; use Garradin\Entities\Accounting\Transaction; class Service_User extends Entity { const TABLE = 'services_users'; protected $id; protected $id_user; protected $id_service; protected $id_fee; protected $paid; protected $expected_amount; protected $date; protected $expiry_date; protected $_types = [ 'id' => 'int', 'id_user' => 'int', 'id_service' => 'int', 'id_fee' => '?int', 'paid' => 'bool', 'expected_amount' => '?int', 'date' => 'date', 'expiry_date' => '?date', ]; protected $_service, $_fee; public function selfCheck(): void { $this->paid = (bool) $this->paid; $this->assert(!DB::getInstance()->test(self::TABLE, 'id_user = ? AND id_service = ? AND date = ? AND id != ?', $this->id_user, $this->id_service, $this->date->format('Y-m-d'), $this->id), 'Cette activité a déjà été enregistrée pour ce membre et ce jour'); } public function importForm(?array $source = null) { if (null === $source) { $source = $_POST; } if (!empty($source['id_service']) && empty($source['expiry_date'])) { $service = $this->_service = Services::get((int) $source['id_service']); if (!$service) { throw new \LogicException('The requested service is not found'); } if ($service->duration) { $dt = new \DateTime; $dt->modify(sprintf('+%d days', $service->duration)); $this->expiry_date = $dt; } elseif ($service->end_date) { $this->expiry_date = $service->end_date; } else { $this->expiry_date = null; } } return parent::importForm($source); } public function service() { if (null === $this->_service) { $this->_service = Services::get($this->id_service); } return $this->_service; } public function fee() { if (null === $this->_fee) { $this->_fee = Fees::get($this->id_fee); } return $this->_fee; } public function addPayment(int $user_id, ?array $source = null) { if (null === $source) { $source = $_POST; } $transaction = new Transaction; $transaction->id_creator = $user_id; $transaction->id_year = $this->fee()->id_year; $source['type'] = Transaction::TYPE_REVENUE; $key = sprintf('account_%d_', $source['type']); $source[$key . '0'] = [$this->fee()->id_account => '']; $source[$key . '1'] = isset($source['account']) ? $source['account'] : null; $source['label'] = 'Règlement activité - ' . $this->service()->label . ' - ' . $this->fee()->label; $source['date'] = $this->date->format('d/m/Y'); $transaction->importFromNewForm($source); $transaction->save(); $transaction->linkToUser($this->id_user, $this->id()); return $transaction; } static public function saveFromForm(int $user_id, ?array $source = null) { if (null === $source) { $source = $_POST; } $db = DB::getInstance(); $db->begin(); $su = new self; $su->date = new \DateTime; $su->importForm($source); if ($su->id_fee && $su->fee()->id_account && $su->id_user) { $su->expected_amount = $su->fee()->getAmountForUser($su->id_user); } $su->save(); if ($su->id_fee && $su->fee()->id_account && !empty($source['amount'])) { $su->addPayment($user_id, $source); } $db->commit(); return $su; } } |
Added src/include/lib/Garradin/Entity.php version [de03b9076a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | <?php namespace Garradin; use Garradin\Form; use KD2\DB\AbstractEntity; class Entity extends AbstractEntity { protected $_form_rules = []; /** * Valider les champs avant enregistrement * @throws ValidationException Si une erreur de validation survient */ public function importForm(array $source = null) { if (null === $source) { $source = $_POST; } $form = new Form; if (!$form->validate($this->_form_rules, $source)) { $messages = $form->getErrorMessages(); throw new ValidationException(implode("\n", $messages)); } return $this->import($source); } protected function filterUserValue(string $type, $value, string $key) { if ($type == 'date') { if (!trim($value)) { return null; } if (preg_match('!^\d{2}/\d{2}/\d{2}$!', $value)) { return \DateTime::createFromFormat('d/m/y', $value); } elseif (preg_match('!^\d{2}/\d{2}/\d{4}$!', $value)) { return \DateTime::createFromFormat('d/m/Y', $value); } elseif (null !== $value) { throw new ValidationException('Format de date invalide (merci d\'utiliser le format JJ/MM/AAAA) : ' . $value); } } else { return parent::filterUserValue($type, $value, $key); } } protected function assert(bool $test, string $message = null): void { if ($test) { return; } if (null === $message) { $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); $caller_class = array_pop($backtrace); $caller = array_pop($backtrace); $message = sprintf('Entity assertion fail from class %s on line %d', $caller_class['class'], $caller['line']); throw new \UnexpectedValueException($message); } else { throw new ValidationException($message); } } } |
Modified src/include/lib/Garradin/Fichiers.php from [b62209a8ff] to [04d7bcf61a].
1 2 3 4 | <?php namespace Garradin; | | | | | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php namespace Garradin; use KD2\Graphics\Image; use Garradin\Membres\Session; class Fichiers { public $id; public $nom; public $type; public $image; public $datetime; public $hash; public $taille; public $id_contenu; /** * Tailles de miniatures autorisées, pour ne pas avoir 500 fichiers générés avec 500 tailles différentes * @var array */ protected static $allowed_thumb_sizes = [200, 500]; const LIEN_COMPTA = 'acc_transactions'; const LIEN_WIKI = 'wiki_pages'; const LIEN_MEMBRES = 'membres'; /** * Renvoie l'URL vers un fichier * @param integer $id Numéro du fichier * @param string $nom Nom de fichier avec extension * @param integer $size Taille de la miniature désirée (pour les images) * @return string URL du fichier */ static public function _getURL(int $id, string $nom, string $hash, $size = false): string { $url = sprintf('%sf/%s/%s?', WWW_URL, base_convert((int)$id, 10, 36), $nom); if ($size) { $url .= self::_findThumbSize($size) . 'px&'; } $url .= substr($hash, 0, 10); return $url; } /** * Renvoie la taille de miniature la plus proche de la taille demandée * @param integer $size Taille demandée |
︙ | ︙ | |||
70 71 72 73 74 75 76 | return max(self::$allowed_thumb_sizes); } /** * Constructeur de l'objet pour un fichier * @param integer $id Numéro unique du fichier */ | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | return max(self::$allowed_thumb_sizes); } /** * Constructeur de l'objet pour un fichier * @param integer $id Numéro unique du fichier */ public function __construct(int $id, ?iterable $data = null) { if (is_null($data)) { $data = DB::getInstance()->first('SELECT fichiers.*, fc.hash, fc.taille, strftime(\'%s\', datetime) AS datetime FROM fichiers INNER JOIN fichiers_contenu AS fc ON fc.id = fichiers.id_contenu WHERE fichiers.id = ?;', (int)$id); |
︙ | ︙ | |||
98 99 100 101 102 103 104 | /** * Renvoie l'adresse d'accès au fichier * @param boolean $size Taille éventuelle de la miniature demandée * @return string URL d'accès au fichier */ public function getURL($size = false) { | | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | /** * Renvoie l'adresse d'accès au fichier * @param boolean $size Taille éventuelle de la miniature demandée * @return string URL d'accès au fichier */ public function getURL($size = false) { return self::_getURL($this->id, $this->nom, $this->hash, $size); } /** * Lier un fichier à un contenu * @param string $type Type de contenu (constantes LIEN_*) * @param integer $foreign_id ID du contenu lié * @return boolean TRUE en cas de succès |
︙ | ︙ | |||
142 143 144 145 146 147 148 | throw new \LogicException('Ce fichier est déjà lié à un autre contenu : ' . $check_type); } return $db->preparedQuery('INSERT OR IGNORE INTO fichiers_' . $type . ' (fichier, id) VALUES (?, ?);', [(int)$this->id, (int)$foreign_id]); } | > > > | > > | > | | > > | | < < | | > > > > > > > > > > > > > > > > > > | > | > | | > > > > | | | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | throw new \LogicException('Ce fichier est déjà lié à un autre contenu : ' . $check_type); } return $db->preparedQuery('INSERT OR IGNORE INTO fichiers_' . $type . ' (fichier, id) VALUES (?, ?);', [(int)$this->id, (int)$foreign_id]); } public function getLinkedId(string $type) { $check = [self::LIEN_MEMBRES, self::LIEN_WIKI, self::LIEN_COMPTA]; if (!in_array($type, $check)) { throw new \LogicException('Type de lien de fichier inconnu.'); } return DB::getInstance()->firstColumn(sprintf('SELECT id FROM fichiers_%s WHERE fichier = %d;', $type, $this->id)); } public function isPublic(&$wiki = null): bool { $config = Config::getInstance(); if ($config->get('image_fond') == $this->id) { return true; } // On regarde déjà si le fichier n'est pas lié au wiki $query = sprintf('SELECT wp.droit_lecture FROM fichiers_%s AS link INNER JOIN wiki_pages AS wp ON wp.id = link.id WHERE link.fichier = ? LIMIT 1;', self::LIEN_WIKI); $wiki = DB::getInstance()->firstColumn($query, (int)$this->id); // Page wiki publique, aucune vérification à faire, seul cas d'accès à un fichier en dehors de l'espace admin if ($wiki !== false && $wiki == Wiki::LECTURE_PUBLIC) { return true; } return false; } /** * Vérifie que l'utilisateur a bien le droit d'accéder à ce fichier * @param mixed $user Tableau contenant les infos sur l'utilisateur connecté, provenant de Session::getUser, ou false * @return boolean TRUE si l'utilisateur a le droit d'accéder au fichier, sinon FALSE */ public function checkAccess(Session $session, bool $require_admin = false) { $wiki = null; if ($this->isPublic($wiki) && !$require_admin) { return true; } // Pas d'utilisateur connecté, pas d'accès aux fichiers de l'espace admin if (!$session->isLogged()) { return false; } $user = $session->getUser(); if ($wiki !== false) { // S'il n'a même pas droit à accéder au wiki c'est mort if (!$session->canAccess('wiki', Membres::DROIT_ACCES)) { return false; } // On renvoie à l'objet Wiki pour savoir si l'utilisateur a le droit de lire ce fichier $_w = new Wiki; $_w->setRestrictionCategorie($user->id_categorie, $user->droit_wiki); return $require_admin ? $_w->canWritePage($wiki) : $_w->canReadPage($wiki); } $level = $require_admin ? Membres::DROIT_ADMIN : Membres::DROIT_ACCES; $db = DB::getInstance(); // On regarde maintenant si le fichier est lié à la compta $query = sprintf('SELECT 1 FROM fichiers_%s WHERE fichier = ? LIMIT 1;', self::LIEN_COMPTA); $compta = $db->firstColumn($query, (int)$this->id); if ($compta) { // OK si accès à la compta return $session->canAccess('compta', $level); } // Enfin, si le fichier est lié à un membre $query = sprintf('SELECT id FROM fichiers_%s WHERE fichier = ? LIMIT 1;', self::LIEN_MEMBRES); $membre = $db->firstColumn($query, (int)$this->id); if ($membre !== false) { // De manière évidente, l'utilisateur a le droit d'accéder aux fichiers liés à son profil if ((int)$membre == $user->id) { return true; } // Pour voir les fichiers des membres il faut pouvoir les gérer if ($level == Membres::DROIT_ACCES) { $level = Membres::DROIT_ECRITURE; } if ($session->canAccess('membres', $level)) { return true; } } return false; } /** * Supprime le fichier * @return boolean TRUE en cas de succès */ public function remove() { $db = DB::getInstance(); $db->begin(); $db->delete('fichiers_' . self::LIEN_COMPTA, 'fichier = ?', (int)$this->id); $db->delete('fichiers_' . self::LIEN_WIKI, 'fichier = ?', (int)$this->id); $db->delete('fichiers_' . self::LIEN_MEMBRES, 'fichier = ?', (int)$this->id); $db->delete('fichiers', 'id = ?', (int)$this->id); // Suppression du contenu s'il n'est pas utilisé par un autre fichier if (!$db->firstColumn('SELECT 1 FROM fichiers WHERE id_contenu = ? AND id != ? LIMIT 1;', (int)$this->id_contenu, (int)$this->id)) { |
︙ | ︙ | |||
283 284 285 286 287 288 289 | /** * Envoie le fichier au client HTTP * @return void */ public function serve() { | | | > > > > > | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | /** * Envoie le fichier au client HTTP * @return void */ public function serve() { return $this->_serve($this->getFilePathFromCache(), $this->type, ($this->image ? false : $this->nom), $this->taille, $this->isPublic()); } /** * Envoie une miniature à la taille indiquée au client HTTP * @return void */ public function serveThumbnail($width = null) { if (!$this->image) { throw new UserException('Il n\'est pas possible de fournir une miniature pour un fichier qui n\'est pas une image.'); } if (!$width) { $width = reset(self::$allowed_thumb_sizes); } if (!in_array($width, self::$allowed_thumb_sizes)) { throw new UserException('Cette taille de miniature n\'est pas autorisée.'); } $cache_id = 'fichiers.' . $this->id_contenu . '.thumb.' . (int)$width; |
︙ | ︙ | |||
329 330 331 332 333 334 335 | * Servir un fichier local en HTTP * @param string $path Chemin vers le fichier local * @param string $type Type MIME du fichier * @param string $name Nom du fichier avec extension * @param integer $size Taille du fichier en octets (facultatif) * @return boolean TRUE en cas de succès */ | | > > > > | | | | > | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | * Servir un fichier local en HTTP * @param string $path Chemin vers le fichier local * @param string $type Type MIME du fichier * @param string $name Nom du fichier avec extension * @param integer $size Taille du fichier en octets (facultatif) * @return boolean TRUE en cas de succès */ protected function _serve($path, $type, $name = false, $size = null, bool $public = false) { if ($public) { Utils::HTTPCache($this->hash, $this->datetime); } else { // Désactiver le cache header('Pragma: public'); header('Expires: -1'); header('Cache-Control: public, must-revalidate, post-check=0, pre-check=0'); } header('Content-Type: '.$type); if ($name) { header('Content-Disposition: attachment; filename="' . $name . '"'); } // Utilisation de XSendFile si disponible if (ENABLE_XSENDFILE && isset($_SERVER['SERVER_SOFTWARE'])) { if (stristr($_SERVER['SERVER_SOFTWARE'], 'apache') && function_exists('apache_get_modules') && in_array('mod_xsendfile', apache_get_modules())) { |
︙ | ︙ | |||
373 374 375 376 377 378 379 | @ini_set('zlib.output_compression', 'Off'); if ($size) { header('Content-Length: '. (int)$size); } | > | > > | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | @ini_set('zlib.output_compression', 'Off'); if ($size) { header('Content-Length: '. (int)$size); } if (@ob_get_length()) { @ob_clean(); } flush(); // Sinon on envoie le fichier à la mano return readfile($path); } /** |
︙ | ︙ | |||
462 463 464 465 466 467 468 | } if (!is_uploaded_file($file['tmp_name'])) { throw new \RuntimeException('Le fichier n\'a pas été envoyé de manière conventionnelle.'); } | < < < < < < < < < < < < < < < < < < < < < < < | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 | } if (!is_uploaded_file($file['tmp_name'])) { throw new \RuntimeException('Le fichier n\'a pas été envoyé de manière conventionnelle.'); } $name = preg_replace('/\s+/', '_', $file['name']); $name = preg_replace('/[^\d\w._-]/ui', '', $name); return self::storeFile($name, $file['tmp_name']); } /** * Upload de fichier à partir d'une chaîne en base64 * @param string $name * @param string $content * @return Fichiers */ static public function storeFromBase64($name, $content) |
︙ | ︙ | |||
547 548 549 550 551 552 553 | // Check that it's a real image if ($is_image) { try { if ($path && !$content) { $i = new Image($path); } else { | | > > > > > > > > > > > > | > > > | > | | < | | | < < > > | | > | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | // Check that it's a real image if ($is_image) { try { if ($path && !$content) { $i = new Image($path); } else { $i = Image::createFromBlob($content); } // Recompress PNG files from base64, assuming they are coming // from JS canvas which doesn't know how to gzip (d'oh!) if ($i->format() == 'png' && null !== $content) { $content = $i->output('png', true); $hash = sha1($content); $size = strlen($content); } unset($i); } catch (\RuntimeException $e) { if (strstr($e->getMessage(), 'No suitable image library found')) { throw new UserException('Le serveur n\'a aucune bibliothèque de gestion d\'image installée, et ne peut donc pas accepter les images. Installez Imagick ou GD.'); } throw new UserException('Fichier image invalide'); } } $db = DB::getInstance(); $db->begin(); // Il peut arriver que l'on renvoie ici un fichier déjà stocké, auquel cas, ne pas le re-stocker if (!($id_contenu = $db->firstColumn('SELECT id FROM fichiers_contenu WHERE hash = ?;', $hash))) { $db->preparedQuery('INSERT INTO fichiers_contenu (hash, taille, contenu) VALUES (?, ?, zeroblob(?));', [$hash, (int)$size, (int)$size]); $id_contenu = $db->lastInsertRowID(); // Écrire le contenu $blob = $db->openBlob('fichiers_contenu', 'contenu', $id_contenu, 'main', SQLITE3_OPEN_READWRITE); if (null !== $content) { fwrite($blob, $content); } else{ fwrite($blob, file_get_contents($path)); } fclose($blob); } $db->insert('fichiers', [ 'id_contenu' => (int)$id_contenu, 'nom' => $name, 'type' => $type, 'image' => (int)$is_image, |
︙ | ︙ | |||
623 624 625 626 627 628 629 | } /** * Récupère la liste des fichiers liés à une ressource * * @param string $type Type de ressource * @param integer $id Numéro de ressource | | | | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 | } /** * Récupère la liste des fichiers liés à une ressource * * @param string $type Type de ressource * @param integer $id Numéro de ressource * @param boolean|null $images TRUE pour retourner seulement les images, * FALSE pour retourner les fichiers sans images, NULL pour tout retourner * @return array Liste des fichiers */ static public function listLinkedFiles($type, $id, $images = null) { $check = [self::LIEN_MEMBRES, self::LIEN_WIKI, self::LIEN_COMPTA]; if (!in_array($type, $check)) { throw new \LogicException('Type de lien de fichier inconnu.'); } |
︙ | ︙ | |||
649 650 651 652 653 654 655 | WHERE fwp.id = ? %s ORDER BY fichiers.nom COLLATE NOCASE;', $type, $images); $files = DB::getInstance()->get($query, (int)$id); foreach ($files as &$file) { | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | WHERE fwp.id = ? %s ORDER BY fichiers.nom COLLATE NOCASE;', $type, $images); $files = DB::getInstance()->get($query, (int)$id); foreach ($files as &$file) { $file->url = self::_getURL($file->id, $file->nom, $file->hash); $file->thumb = $file->image ? self::_getURL($file->id, $file->nom, $file->hash, 200) : false; } return $files; } static public function deleteLinkedFiles($type, int $id) { static $check = [self::LIEN_MEMBRES, self::LIEN_WIKI, self::LIEN_COMPTA]; if (!in_array($type, $check)) { throw new \LogicException('Type de lien de fichier inconnu.'); } $files = DB::getInstance()->delete('fichiers_' . $type, 'id = ?', $id); return self::deleteUnlinkedFiles(); } static public function deleteUnlinkedFiles() { static $all = [self::LIEN_MEMBRES, self::LIEN_WIKI, self::LIEN_COMPTA]; $id_background = Config::getInstance()->get('image_fond'); $list = DB::getInstance()->iterate(sprintf('SELECT f.id, f.id_contenu FROM fichiers f LEFT JOIN fichiers_%s a ON a.fichier = f.id LEFT JOIN fichiers_%s b ON b.fichier = f.id LEFT JOIN fichiers_%s c ON c.fichier = f.id WHERE a.id IS NULL AND b.id IS NULL AND c.id IS NULL;', self::LIEN_MEMBRES, self::LIEN_WIKI, self::LIEN_COMPTA)); foreach ($list as $file) { if ($file->id == $id_background) { // FIXME: want to use something cleaner here! continue; } $f = new Fichiers($file->id, (array) $file); $f->remove(); } } /** * Enlève d'une liste de fichiers ceux qui sont mentionnés dans un texte wiki * @param array $files Liste de fichiers * @param string $text texte wiki * @return array Un tableau qui ne contient pas les fichiers mentionnés dans $text */ |
︙ | ︙ | |||
680 681 682 683 684 685 686 | * @param string $text Texte wiki * @return array Liste des IDs de fichiers mentionnés */ static public function listFilesUsedInText($text) { preg_match_all('/<<?(?:fichier|image)\s*(?:\|\s*)?(\d+)/', $text, $match, PREG_PATTERN_ORDER); preg_match_all('/(?:fichier|image):\/\/(\d+)/', $text, $match2, PREG_PATTERN_ORDER); | | | 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 | * @param string $text Texte wiki * @return array Liste des IDs de fichiers mentionnés */ static public function listFilesUsedInText($text) { preg_match_all('/<<?(?:fichier|image)\s*(?:\|\s*)?(\d+)/', $text, $match, PREG_PATTERN_ORDER); preg_match_all('/(?:fichier|image):\/\/(\d+)/', $text, $match2, PREG_PATTERN_ORDER); return array_merge($match[1], $match2[1]); } /** * Callback utilisé pour l'extension <<fichier>> dans le wiki-texte * @param array $args Arguments passés à l'extension * @param string $content Contenu éventuel (en mode bloc) |
︙ | ︙ |
Modified src/include/lib/Garradin/Form.php from [4384bc9995] to [024879329f].
1 2 3 4 5 6 7 8 9 10 11 12 | <?php namespace Garradin; class Form { protected $errors = []; public function __construct() { // Valide un montant de monnaie valide (deux décimales, ne peut être négatif) \KD2\Form::registerValidationRule('money', function ($name, $params, $value) { | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | <?php namespace Garradin; class Form { protected $errors = []; public function __construct() { // Valide un montant de monnaie valide (deux décimales, ne peut être négatif) \KD2\Form::registerValidationRule('money', function ($name, $params, $value) { return preg_match('/^\d+(?:[.,]\d{1,2})?$/', $value) && $value >= 0; }); // Test si la valeur existe dans cette table // in_table:compta_categories,id \KD2\Form::registerValidationRule('in_table', function ($name, $params, $value) { $db = DB::getInstance(); return $db->test($params[0], $db->where($params[1], $value)); }); } public function run(callable $fn, ?string $csrf_key = null, ?string $redirect = null): bool { if (null !== $csrf_key && !$this->check($csrf_key)) { return false; } try { call_user_func($fn); if (null !== $redirect) { Utils::redirect($redirect); } return true; } catch (UserException $e) { $this->addError($e->getMessage()); return false; } } public function runIf($condition, callable $fn, ?string $csrf_key = null, ?string $redirect = null): ?bool { if (is_string($condition) && empty($_POST[$condition])) { return null; } elseif (is_bool($condition) && !$condition) { return null; } return $this->run($fn, $csrf_key, $redirect); } public function check($token_action = '', Array $rules = null) { if (!\KD2\Form::tokenCheck($token_action)) { $this->errors[] = 'Une erreur est survenue, merci de bien vouloir renvoyer le formulaire.'; return false; } if (!is_null($rules) && !$this->validate($rules)) { return false; } return true; } public function validate(Array $rules, array $source = null) { return \KD2\Form::validate($rules, $this->errors, $source); } public function hasErrors() { return (count($this->errors) > 0); } |
︙ | ︙ | |||
92 93 94 95 96 97 98 99 100 101 102 103 104 105 | { case '_id': return 'identifiant'; case 'passe': return 'mot de passe'; case 'debut': return 'date de début'; case 'fin': return 'date de fin'; case 'duree': return 'durée'; case 'passe_check': return 'vérification de mot de passe'; default: return $name; } } protected function getErrorMessage($rule, $element, Array $params) { $element = $this->getFieldName($element); | > > | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | { case '_id': return 'identifiant'; case 'passe': return 'mot de passe'; case 'debut': return 'date de début'; case 'fin': return 'date de fin'; case 'duree': return 'durée'; case 'passe_check': return 'vérification de mot de passe'; case 'id_account': return 'compte'; case 'label': return 'libellé'; default: return $name; } } protected function getErrorMessage($rule, $element, Array $params) { $element = $this->getFieldName($element); |
︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | case 'date_format': return sprintf('Format de date invalide dans le champ %s.', $element); case 'numeric': return sprintf('Le champ %s doit être un nombre.', $element); case 'money': return sprintf('Le champ %s n\'est pas un nombre valide.', $element); case 'in': return sprintf('Valeur invalide dans le champ \'%s\'.', $element); default: return sprintf('Erreur "%s" dans le champ "%s"', $rule, $element); } } public function __invoke($key) { return \KD2\Form::get($key); } } | > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | case 'date_format': return sprintf('Format de date invalide dans le champ %s.', $element); case 'numeric': return sprintf('Le champ %s doit être un nombre.', $element); case 'money': return sprintf('Le champ %s n\'est pas un nombre valide.', $element); case 'in': case 'in_table': return sprintf('Valeur invalide dans le champ \'%s\'.', $element); default: return sprintf('Erreur "%s" dans le champ "%s"', $rule, $element); } } public function __invoke($key) { return \KD2\Form::get($key); } } |
Modified src/include/lib/Garradin/Install.php from [3140a79786] to [f40229806d].
1 2 3 4 5 6 7 8 9 10 11 | <?php namespace Garradin; /** * Pour procéder à l'installation de l'instance Garradin * Utile pour automatiser l'installation sans passer par la page d'installation */ class Install { static public function reset(Membres\Session $session, $password, array $options = []) | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php namespace Garradin; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Chart; use Garradin\Entities\Accounting\Year; /** * Pour procéder à l'installation de l'instance Garradin * Utile pour automatiser l'installation sans passer par la page d'installation */ class Install { static public function reset(Membres\Session $session, $password, array $options = []) |
︙ | ︙ | |||
21 22 23 24 25 26 27 | (new Sauvegarde)->create(date('Y-m-d-His-') . 'avant-remise-a-zero'); DB::getInstance()->close(); Config::deleteInstance(); unlink(DB_FILE); | > > | > > | < | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | (new Sauvegarde)->create(date('Y-m-d-His-') . 'avant-remise-a-zero'); DB::getInstance()->close(); Config::deleteInstance(); unlink(DB_FILE); // We can't use the real password, as it might not be valid (too short or compromised) $ok = self::install($config->nom_asso, $user->identite, $user->email, md5($password . SECRET_KEY)); // Restore password DB::getInstance()->preparedQuery('UPDATE membres SET passe = ? WHERE id = 1;', [$session::hashPassword($password)]); if ($ok) { // Force l'installation de plugin système Plugin::checkAndInstallSystemPlugins(); } return $ok; } static public function install($nom_asso, $nom_membre, $email_membre, $passe_membre) { $db = DB::getInstance(true); // Taille de la page de DB, on force à 4096 (défaut dans les dernières // versions de SQLite mais pas les vieilles) $db->exec('PRAGMA page_size = 4096;'); $db->exec('VACUUM;'); // Création de la base de données $db->begin(); $db->exec('PRAGMA application_id = ' . DB::APPID . ';'); $db->exec(file_get_contents(DB_SCHEMA)); $db->commit(); // Configuration de base // c'est dans Config::set que sont vérifiées les données utilisateur (renvoie UserException) $config = Config::getInstance(); $config->set('nom_asso', $nom_asso); $config->set('email_asso', $email_membre); $config->set('site_asso', WWW_URL); $config->set('monnaie', '€'); $config->set('pays', 'FR'); $config->setVersion(garradin_version()); $champs = Membres\Champs::importInstall(); $champs->save(false); // Pas de copie car pas de table membres existante |
︙ | ︙ | |||
83 84 85 86 87 88 89 | 'droit_compta' => Membres::DROIT_AUCUN, 'droit_config' => Membres::DROIT_AUCUN, 'droit_connexion' => Membres::DROIT_AUCUN, 'cacher' => 1, ]); $id = $cats->add([ | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | 'droit_compta' => Membres::DROIT_AUCUN, 'droit_config' => Membres::DROIT_AUCUN, 'droit_connexion' => Membres::DROIT_AUCUN, 'cacher' => 1, ]); $id = $cats->add([ 'nom' => 'Administrateurs', 'droit_inscription' => Membres::DROIT_AUCUN, 'droit_wiki' => Membres::DROIT_ADMIN, 'droit_membres' => Membres::DROIT_ADMIN, 'droit_compta' => Membres::DROIT_ADMIN, 'droit_config' => Membres::DROIT_ADMIN, ]); |
︙ | ︙ | |||
129 130 131 132 133 134 135 | $wiki->editRevision($id_page, 0, [ 'id_auteur' => $id_membre, 'contenu' => "Bienvenue dans l'administration de ".$nom_asso." !\n\n" . "Utilisez le menu à gauche pour accéder aux différentes rubriques.", ]); $config->set('accueil_connexion', $page); | | | > > > > | > | > > > | > > | | | | > > > | | > | | > > > > > > > > > > > > > > > > > > > > | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | $wiki->editRevision($id_page, 0, [ 'id_auteur' => $id_membre, 'contenu' => "Bienvenue dans l'administration de ".$nom_asso." !\n\n" . "Utilisez le menu à gauche pour accéder aux différentes rubriques.", ]); $config->set('accueil_connexion', $page); // Import plan comptable $chart = new Chart; $chart->label = 'Plan comptable associatif 2018'; $chart->country = 'FR'; $chart->code = 'PCA2018'; $chart->save(); $chart->accounts()->importCSV(ROOT . '/include/data/charts/fr_2018.csv'); // Premier exercice $year = new Year; $year->label = sprintf('Exercice %d', date('Y')); $year->start_date = new \DateTime('January 1st'); $year->end_date = new \DateTime('December 31'); $year->id_chart = $chart->id(); $year->save(); // Compte bancaire $account = new Account; $account->import([ 'label' => 'Compte courant', 'code' => '512A', 'type' => Account::TYPE_BANK, 'position' => Account::ASSET_OR_LIABILITY, 'id_chart' => $chart->id(), 'user' => 1, ]); $account->save(); // Ajout d'une recherche avancée en exemple (membres) $query = (object) [ 'query' => [[ 'operator' => 'AND', 'conditions' => [ [ 'column' => 'lettre_infos', 'operator' => '= 1', 'values' => [], ], ], ]], 'order' => 'numero', 'desc' => true, 'limit' => '10000', ]; $recherche = new Recherche; $recherche->add('Membres inscrits à la lettre d\'information', null, $recherche::TYPE_JSON, 'membres', $query); // Ajout d'une recherche avancée en exemple (compta) $query = (object) [ 'query' => [[ 'operator' => 'AND', 'conditions' => [ [ 'column' => 'a2.code', 'operator' => 'IS NULL', 'values' => [], ], ], ]], 'order' => 't.id', 'desc' => false, 'limit' => '100', ]; $recherche = new Recherche; $recherche->add('Écritures sans projet', null, $recherche::TYPE_JSON, 'compta', $query); return $config->save(); } static public function checkAndCreateDirectories() { // Vérifier que les répertoires vides existent, sinon les créer $paths = [DATA_ROOT, PLUGINS_ROOT, CACHE_ROOT, CACHE_ROOT . '/static', CACHE_ROOT . '/compiled']; |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres.php from [1c694ab262] to [312c7859a9].
︙ | ︙ | |||
288 289 290 291 292 293 294 | } public function getIDWithNumero($numero) { return DB::getInstance()->firstColumn('SELECT id FROM membres WHERE numero = ?;', (int) $numero); } | | > > | > | > > | < | | < > | > | > > | | | | | | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | } public function getIDWithNumero($numero) { return DB::getInstance()->firstColumn('SELECT id FROM membres WHERE numero = ?;', (int) $numero); } public function quickSearch(string $query) { $identity = Config::getInstance()->get('champ_identite'); $operator = 'LIKE'; if (is_numeric(trim($query))) { $column = 'numero'; $operator = '= ?'; } elseif (strpos($query, '@') !== false) { $column = 'email'; } else { $column = $identity; } if ($operator == 'LIKE') { $query = '%' . str_replace(['%', '_'], '\\', $query) . '%'; $operator = 'LIKE ? ESCAPE \'\\\''; } $sql = sprintf('SELECT id, numero, %s AS identite FROM membres WHERE %s %s ORDER BY %1$s LIMIT 50;', $identity, $column, $operator); return DB::getInstance()->get($sql, $query); } public function sendMessage(array $recipients, $subject, $message, $send_copy) { $config = Config::getInstance(); foreach ($recipients as $key => $recipient) |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres/Categories.php from [cfad189ba8] to [2ef27a72a7].
︙ | ︙ | |||
15 16 17 18 19 20 21 | 'connexion' => Membres::DROIT_ACCES, 'membres' => Membres::DROIT_AUCUN, 'compta' => Membres::DROIT_AUCUN, 'wiki' => Membres::DROIT_ACCES, 'config' => Membres::DROIT_AUCUN, ]; | < < < < < < < < < < < < < < < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 'connexion' => Membres::DROIT_ACCES, 'membres' => Membres::DROIT_AUCUN, 'compta' => Membres::DROIT_AUCUN, 'wiki' => Membres::DROIT_ACCES, 'config' => Membres::DROIT_AUCUN, ]; protected function _checkData(&$data) { $db = DB::getInstance(); if (!isset($data['nom']) || !trim($data['nom'])) { throw new UserException('Le nom de catégorie ne peut rester vide.'); } } public function add($data) { $this->_checkData($data); foreach ($this->droits as $key=>$value) |
︙ | ︙ |
Deleted src/include/lib/Garradin/Membres/Cotisations.php version [f8b5327ae2].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/include/lib/Garradin/Membres/Import.php from [5800dd1bd4] to [0c863b55dc].
1 2 3 4 5 6 7 8 9 10 11 12 | <?php namespace Garradin\Membres; use Garradin\Membres; use Garradin\Config; use Garradin\DB; use Garradin\Utils; use Garradin\UserException; class Import { | > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <?php namespace Garradin\Membres; use Garradin\Membres; use Garradin\Config; use Garradin\DB; use Garradin\Utils; use Garradin\CSV; use Garradin\CSV_Custom; use Garradin\UserException; class Import { /** * Importer un CSV générique * @return boolean TRUE en cas de succès */ public function fromCustomCSV(CSV_Custom $csv, int $current_user_id) { $db = DB::getInstance(); $db->begin(); $membres = new Membres; foreach ($csv->iterate() as $line => $row) { if (!empty($row->numero) && $row->numero > 0) { $numero = (int)$row->numero; } else { unset($row->numero); $numero = false; } try { if ($numero && ($id = $membres->getIDWithNumero($numero))) { if ($id === $current_user_id) { // Ne pas modifier le membre courant, on risque de se tirer une balle dans le pied continue; } $membres->edit($id, (array)$row); } else { $membres->add((array)$row, false); } } catch (UserException $e) { $db->rollback(); throw new UserException('Erreur sur la ligne ' . $line . ' : ' . $e->getMessage()); } |
︙ | ︙ | |||
175 176 177 178 179 180 181 | public function fromGarradinCSV($path, $current_user_id) { if (!file_exists($path) || !is_readable($path)) { throw new \RuntimeException('Fichier inconnu : '.$path); } | | | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | public function fromGarradinCSV($path, $current_user_id) { if (!file_exists($path) || !is_readable($path)) { throw new \RuntimeException('Fichier inconnu : '.$path); } $fp = CSV::open($path); if (!$fp) { return false; } $db = DB::getInstance(); $db->begin(); $membres = new Membres; // On récupère les champs qu'on peut importer $champs_membres = Config::getInstance()->get('champs_membres'); $champs_multiples = $champs_membres->getMultiples(); $champs = $champs_membres->getKeys(); $champs[] = 'date_inscription'; //$champs[] = 'date_connexion'; //$champs[] = 'id'; //$champs[] = 'id_categorie'; $line = 0; $delim = CSV::findDelimiter($fp); CSV::skipBOM($fp); while (!feof($fp)) { $row = fgetcsv($fp, 4096, $delim); $line++; |
︙ | ︙ | |||
324 325 326 327 328 329 330 | sprintf('Export membres - %s - %s', Config::getInstance()->get('nom_asso'), date('Y-m-d')), ]; } public function toCSV(array $list = null) { list($champs, $result, $name) = $this->export($list); | | | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | sprintf('Export membres - %s - %s', Config::getInstance()->get('nom_asso'), date('Y-m-d')), ]; } public function toCSV(array $list = null) { list($champs, $result, $name) = $this->export($list); return CSV::toCSV($name, $result, $champs, [$this, 'exportRow']); } public function toODS(array $list = null) { list($champs, $result, $name) = $this->export($list); return CSV::toODS($name, $result, $champs, [$this, 'exportRow']); } public function exportRow(\stdClass $row) { // Pas hyper efficace, il faudrait ne pas récupérer la liste pour chaque ligne... FIXME $champs_multiples = Config::getInstance()->get('champs_membres')->getMultiples(); // convertir les champs à choix multiple de binaire vers liste séparée par des points virgules |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres/Session.php from [fa679095c9] to [db8cb5f1d1].
︙ | ︙ | |||
11 12 13 14 15 16 17 | use const Garradin\SECRET_KEY; use const Garradin\WWW_URL; use const Garradin\ADMIN_URL; use KD2\Security; use KD2\Security_OTP; | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | use const Garradin\SECRET_KEY; use const Garradin\WWW_URL; use const Garradin\ADMIN_URL; use KD2\Security; use KD2\Security_OTP; use KD2\Graphics\QRCode; use KD2\HTTP; class Session extends \KD2\UserSession { // Personalisation de la config de UserSession protected $cookie_name = 'gdin'; protected $remember_me_cookie_name = 'gdinp'; |
︙ | ︙ | |||
57 58 59 60 61 62 63 | } // Extension des méthodes de UserSession public function __construct() { $url = parse_url(ADMIN_URL); | < < < < < < < < < < < < < | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | } // Extension des méthodes de UserSession public function __construct() { $url = parse_url(ADMIN_URL); parent::__construct(DB::getInstance(), [ 'cookie_domain' => $url['host'], 'cookie_path' => preg_replace('!/admin/$!', '/', $url['path']), 'cookie_secure' => (\Garradin\PREFER_HTTPS >= 2) ? true : false, ]); } protected function getUserForLogin($login) { $champ_id = Config::getInstance()->get('champ_identifiant'); // Ne renvoie un membre que si celui-ci a le droit de se connecter $query = 'SELECT m.id, m.%1$s AS login, m.passe AS password, m.secret_otp AS otp_secret FROM membres AS m |
︙ | ︙ | |||
150 151 152 153 154 155 156 | { $logged = parent::isLogged(); if (!$disable_local_login && defined('\Garradin\LOCAL_LOGIN')) { $login_id = \Garradin\LOCAL_LOGIN; | | | | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | { $logged = parent::isLogged(); if (!$disable_local_login && defined('\Garradin\LOCAL_LOGIN')) { $login_id = \Garradin\LOCAL_LOGIN; // On va chercher le premier membre avec le droit de gérer la config if (-1 === $login_id) { $login_id = $this->db->firstColumn('SELECT id FROM membres WHERE id_categorie IN (SELECT id FROM membres_categories WHERE droit_config = ?) LIMIT 1', Membres::DROIT_ADMIN); } if ($login_id > 0 && (!$logged || ($logged && $this->user->id != $login_id))) { $logged = $this->create($login_id); } |
︙ | ︙ |
Modified src/include/lib/Garradin/Plugin.php from [de7f4cd5b0] to [7d2a1289d6].
︙ | ︙ | |||
183 184 185 186 187 188 189 | /** * Inclure un fichier depuis le plugin (dynamique ou statique) * @param string $file Chemin du fichier à aller chercher : si c'est un .php il sera inclus, * sinon il sera juste affiché * @return void * @throws UserException Si le fichier n'existe pas ou fait partie des fichiers qui ne peuvent * être appelés que par des méthodes de Plugin. | | | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | /** * Inclure un fichier depuis le plugin (dynamique ou statique) * @param string $file Chemin du fichier à aller chercher : si c'est un .php il sera inclus, * sinon il sera juste affiché * @return void * @throws UserException Si le fichier n'existe pas ou fait partie des fichiers qui ne peuvent * être appelés que par des méthodes de Plugin. * @throws \RuntimeException Si le chemin indiqué tente de sortir du contexte du PHAR */ public function call($file) { $file = preg_replace('!^[./]*!', '', $file); if (preg_match('!(?:\.\.|[/\\\\]\.|\.[/\\\\])!', $file)) { |
︙ | ︙ | |||
439 440 441 442 443 444 445 | '{Membres::DROIT_ECRITURE}' => Membres::DROIT_ECRITURE, '{Membres::DROIT_ADMIN}' => Membres::DROIT_ADMIN, ]); $condition = preg_replace_callback('/\{\$user\.(\w+)\}/', function ($m) use ($user) { return $user->{$m[1]}; }, $condition); $query = 'SELECT 1 WHERE ' . $condition . ';'; | < | | | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 | '{Membres::DROIT_ECRITURE}' => Membres::DROIT_ECRITURE, '{Membres::DROIT_ADMIN}' => Membres::DROIT_ADMIN, ]); $condition = preg_replace_callback('/\{\$user\.(\w+)\}/', function ($m) use ($user) { return $user->{$m[1]}; }, $condition); $query = 'SELECT 1 WHERE ' . $condition . ';'; $res = $db->protectSelect(['membres' => []], $query); if (!$db->firstColumn($query)) { unset($list[$id]); continue; } $row = $row->nom; } |
︙ | ︙ | |||
528 529 530 531 532 533 534 | 'disable_compression' => true, ] ]; $context = stream_context_create($context_options); try { | | > > > > > | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | 'disable_compression' => true, ] ]; $context = stream_context_create($context_options); try { $result = file_get_contents(PLUGINS_URL, false, $context); } catch (\Exception $e) { throw new UserException('Le téléchargement de la liste des plugins a échoué : ' . $e->getMessage()); } Static_Cache::store('plugins_list', $result); } else { $result = Static_Cache::get('plugins_list'); } $list = json_decode($result, true); return $list; } static public function fetchOfficialList() { return []; // FIXME } /** * Vérifier le hash du plugin $id pour voir s'il correspond au hash du fichier téléchargés * @param string $id Identifiant du plugin * @return boolean TRUE si le hash correspond (intégrité OK), sinon FALSE */ static public function checkHash($id) |
︙ | ︙ | |||
578 579 580 581 582 583 584 | return array_key_exists($id, $list); } /** * Télécharge un plugin depuis le repository officiel, et l'installe * @param string $id Identifiant du plugin * @return boolean TRUE si ça marche | | | | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | return array_key_exists($id, $list); } /** * Télécharge un plugin depuis le repository officiel, et l'installe * @param string $id Identifiant du plugin * @return boolean TRUE si ça marche * @throws \LogicException Si le plugin n'est pas dans la liste des plugins officiels * @throws UserException Si le plugin est déjà installé ou que le téléchargement a échoué * @throws \RuntimeException Si l'archive téléchargée est corrompue (intégrité du hash ne correspond pas) */ static public function download($id) { $list = self::fetchOfficialList(); if (!array_key_exists($id, $list)) { |
︙ | ︙ |
Deleted src/include/lib/Garradin/Rappels.php version [ac12c6b477].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/include/lib/Garradin/Rappels_Envoyes.php version [fcaa354186].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/include/lib/Garradin/Recherche.php from [98002e1aea] to [c748f37f3f].
1 2 3 4 5 6 7 8 9 10 11 | <?php namespace Garradin; class Recherche { const TYPE_JSON = 'json'; const TYPE_SQL = 'sql'; const TARGETS = [ 'membres', | > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php namespace Garradin; use Garradin\Entities\Accounting\Transaction; class Recherche { const TYPE_JSON = 'json'; const TYPE_SQL = 'sql'; const TARGETS = [ 'membres', 'compta', ]; protected function _checkFields($data) { $db = DB::getInstance(); if (array_key_exists('intitule', $data) && trim($data['intitule']) === '') |
︙ | ︙ | |||
55 56 57 58 59 60 61 | throw new \InvalidArgumentException('Recherche invalide pour le type SQL'); } $query = $data['contenu']; if ($data['type'] == self::TYPE_JSON) { | | > > > > > > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | throw new \InvalidArgumentException('Recherche invalide pour le type SQL'); } $query = $data['contenu']; if ($data['type'] == self::TYPE_JSON) { if (!is_object($query)) { throw new \InvalidArgumentException('Recherche invalide pour le type JSON'); } $query = json_encode($query); if (!json_decode($query)) { throw new \InvalidArgumentException('JSON invalide pour le type JSON'); } } } return $query; } public function duplicate(int $id) { DB::getInstance()->preparedQuery('INSERT INTO recherches (id_membre, intitule, cible, type, contenu) SELECT id_membre, \'Copie de : \' || intitule, cible, type, contenu FROM recherches WHERE id = ?;', [$id]); } public function edit($id, $data) { $allowed = ['intitule', 'id_membre', 'type', 'cible', 'contenu']; // Supprimer les champs qui ne sont pas ceux de la BDD $data = array_intersect_key($data, array_flip($allowed)); |
︙ | ︙ | |||
110 111 112 113 114 115 116 | return DB::getInstance()->delete('recherches', 'id = ?', (int) $id); } public function get($id) { $r = DB::getInstance()->first('SELECT * FROM recherches WHERE id = ?;', (int) $id); | | < | < < < < < < < | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | return DB::getInstance()->delete('recherches', 'id = ?', (int) $id); } public function get($id) { $r = DB::getInstance()->first('SELECT * FROM recherches WHERE id = ?;', (int) $id); if ($r && $r->type == self::TYPE_JSON) { $r->query = (object) json_decode($r->contenu, true); } return $r; } public function getList($id_membre, $cible) { |
︙ | ︙ | |||
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | if ($search->type == self::TYPE_JSON) { $search->contenu = $this->buildQuery($search->cible, $search->query, $search->order, $search->desc, $no_limit ? 10000 : $search->limit); } return $this->searchSQL($search->cible, $search->contenu, $force_select, $no_limit); } /** * Renvoie la liste des colonnes d'une cible */ public function getColumns($target) { $columns = []; $db = DB::getInstance(); if ($target == 'membres') { $champs = Config::getInstance()->get('champs_membres'); $columns['id_categorie'] = (object) [ | > > > > > > > > > > > > > > > > > > > > > > > < < | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | if ($search->type == self::TYPE_JSON) { $search->contenu = $this->buildQuery($search->cible, $search->query, $search->order, $search->desc, $no_limit ? 10000 : $search->limit); } return $this->searchSQL($search->cible, $search->contenu, $force_select, $no_limit); } public function getResultHeader(string $target, array $result) { if (!count($result)) { return []; } $out = []; $columns = $this->getColumns($target); foreach (reset($result) as $key => $v) { foreach ($columns as $ckey => $config) { if ($ckey == $key) { $out[$key] = $config->label; } elseif (isset($config->alias) && $config->alias == $key) { $out[$config->alias] = $config->label; } } } return $out; } /** * Renvoie la liste des colonnes d'une cible */ public function getColumns($target) { $columns = []; $db = DB::getInstance(); if ($target == 'membres') { $champs = Config::getInstance()->get('champs_membres'); $columns['id_categorie'] = (object) [ 'textMatch'=> false, 'label' => 'Catégorie', 'type' => 'enum', 'null' => false, 'values' => $db->getAssoc('SELECT id, nom FROM membres_categories ORDER BY nom;'), ]; foreach ($champs->getList() as $champ => $config) { $column = (object) [ 'textMatch'=> $champs->isText($champ), 'label' => $config->title, 'type' => 'text', 'null' => true, ]; if ($config->type == 'checkbox') |
︙ | ︙ | |||
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | { $column->type = $config->type; } elseif ($config->type == 'number' || $champ == 'numero') { $column->type = 'integer'; } $columns[$champ] = $column; } } return $columns; } /** * Construire une recherche SQL à partir d'un objet généré par QueryBuilder * @param string $target Cible de la requête : membres, compta_journal, etc. * @param array $groups Groupes de critères * @param string $order Ordre de tri * @param boolean $desc Inverser le tri * @param integer $limit Limite * @return string Chaîne SQL */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | { $column->type = $config->type; } elseif ($config->type == 'number' || $champ == 'numero') { $column->type = 'integer'; } if ($config->type == 'tel') { $column->originalType = 'tel'; } $columns[$champ] = $column; } } elseif ($target === 'compta') { $columns['t.id'] = (object) [ 'textMatch'=> false, 'label' => 'Numéro écriture', 'type' => 'integer', 'null' => false, 'alias' => 'id', ]; $columns['t.date'] = (object) [ 'textMatch'=> false, 'label' => 'Date', 'type' => 'date', 'null' => false, 'alias' => 'date', ]; $columns['t.label'] = (object) [ 'textMatch'=> true, 'label' => 'Libellé écriture', 'type' => 'text', 'null' => false, 'alias' => 'label', ]; $columns['t.reference'] = (object) [ 'textMatch'=> true, 'label' => 'Numéro pièce comptable', 'type' => 'text', 'null' => true, 'alias' => 'reference', ]; $columns['t.notes'] = (object) [ 'textMatch'=> true, 'label' => 'Notes', 'type' => 'text', 'null' => true, 'alias' => 'notes', ]; $columns['l.label'] = (object) [ 'textMatch'=> true, 'label' => 'Libellé ligne', 'type' => 'text', 'null' => true, 'alias' => 'line_label', ]; $columns['l.debit'] = (object) [ 'textMatch'=> false, 'label' => 'Débit', 'type' => 'integer', 'null' => false, 'alias' => 'debit', 'originalType' => 'money', ]; $columns['l.credit'] = (object) [ 'textMatch'=> false, 'label' => 'Crédit', 'type' => 'integer', 'null' => false, 'alias' => 'credit', 'originalType' => 'money', ]; $columns['l.reference'] = (object) [ 'textMatch'=> true, 'label' => 'Référence ligne écriture', 'type' => 'text', 'null' => true, 'alias' => 'line_reference', ]; $columns['t.type'] = (object) [ 'textMatch'=> false, 'label' => 'Type d\'écriture', 'type' => 'enum', 'null' => false, 'values' => Transaction::TYPES_NAMES, 'alias' => 'type', ]; $columns['a.code'] = (object) [ 'textMatch'=> true, 'label' => 'Numéro de compte', 'type' => 'text', 'null' => false, 'alias' => 'code', ]; $columns['t.id_year'] = (object) [ 'textMatch'=> false, 'label' => 'Exercice', 'type' => 'enum', 'null' => false, 'values' => $db->getAssoc('SELECT id, label FROM acc_years ORDER BY end_date;'), 'alias' => 'id_year', ]; $columns['a2.code'] = (object) [ 'textMatch'=> true, 'label' => 'N° de compte projet', 'type' => 'text', 'null' => true, 'alias' => 'id_analytical', ]; } return $columns; } /** * Construire une recherche SQL à partir d'un objet généré par QueryBuilder * @param string $target Cible de la requête : membres, compta_journal, etc. * @param array $groups Groupes de critères * @param string $order Ordre de tri * @param boolean $desc Inverser le tri * @param integer $limit Limite * @return string Chaîne SQL */ public function buildQuery(string $target, array $groups, string $order, bool $desc = false, int $limit = 100) { if (!in_array($target, self::TARGETS, true)) { throw new \InvalidArgumentException('Cible inconnue : ' . $target); } if ($target == 'membres') { $config = Config::getInstance(); $champs = $config->get('champs_membres'); } $db = DB::getInstance(); $target_columns = $this->getColumns($target); if (!isset($target_columns[$order])) { throw new UserException('Colonne de tri inconnue : ' . $order); } $query_columns = []; $query_groups = []; static $no_transform_operators = ['IS NULL', 'IS NOT NULL', '= 0', '= 1', '&']; foreach ($groups as $group) |
︙ | ︙ | |||
269 270 271 272 273 274 275 | } if (!array_key_exists($condition['column'], $target_columns)) { // Ignorer une condition qui se rapporte à une colonne // qui n'existe pas, cas possible si on reprend une recherche // après avoir modifié les fiches de membres | | > | < | | > > > > | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | } if (!array_key_exists($condition['column'], $target_columns)) { // Ignorer une condition qui se rapporte à une colonne // qui n'existe pas, cas possible si on reprend une recherche // après avoir modifié les fiches de membres throw new UserException('Cette recherche fait référence à une colonne qui n\'existe pas : ' . $condition['column']); } $query_columns[] = $condition['column']; $column = $target_columns[$condition['column']]; if ($column->textMatch == 'text' && !in_array($condition['operator'], $no_transform_operators)) { $query = sprintf('transliterate_to_ascii(%s) COLLATE NOCASE %s', $db->quoteIdentifier($condition['column']), $condition['operator']); } else { $query = sprintf('%s %s', $db->quoteIdentifier($condition['column']), $condition['operator']); } $values = isset($condition['values']) ? $condition['values'] : []; $values = array_map(['Garradin\Utils', 'transliterateToAscii'], $values); if (!empty($column->originalType)) { if ($column->originalType == 'tel') { // Normaliser le numéro de téléphone $values = array_map(['Garradin\Utils', 'normalizePhoneNumber'], $values); } elseif ($column->originalType == 'money') { $values = array_map(['Garradin\Utils', 'moneyToInteger'], $values); } } // L'opérateur binaire est un peu spécial if ($condition['operator'] == '&') { $new_query = []; |
︙ | ︙ | |||
315 316 317 318 319 320 321 | { $values = array_map([$db, 'quote'], $values); $query = str_replace('??', implode(', ', $values), $query); } // Remplacement de recherche LIKE elseif (preg_match('/%\?%|%\?|\?%/', $query, $match)) { | | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | { $values = array_map([$db, 'quote'], $values); $query = str_replace('??', implode(', ', $values), $query); } // Remplacement de recherche LIKE elseif (preg_match('/%\?%|%\?|\?%/', $query, $match)) { $value = str_replace(['%', '_'], ['\\%', '\\_'], reset($values)); $value = str_replace('?', $value, $match[0]); $query = str_replace($match[0], sprintf('%s ESCAPE \'\\\'', $db->quote($value)), $query); } // Remplacement de paramètre elseif (strpos($query, '?') !== false) { $expected = substr_count($query, '?'); |
︙ | ︙ | |||
352 353 354 355 356 357 358 | if (!count($query_groups)) { throw new UserException('Aucune clause trouvée dans la recherche.'); } // Ajout du champ identité si pas présent | | | > > > > > | > > | > > | | | | | | > > > > > > > > | > > > > > > | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 | if (!count($query_groups)) { throw new UserException('Aucune clause trouvée dans la recherche.'); } // Ajout du champ identité si pas présent if ($target == 'membres') { $query_columns = array_merge(['id', $config->get('champ_identite')], $query_columns); } // Ajout de champs compta si pas présents elseif ($target == 'compta') { $query_columns = array_merge(['t.id', 't.date', 't.label', 'l.debit', 'l.credit', 'a.code'], $query_columns); } $query_columns[] = $order; if ($target_columns[$order]->textMatch) { $order = sprintf('transliterate_to_ascii(%s) COLLATE NOCASE', $db->quoteIdentifier($order)); } else { $order = $db->quoteIdentifier($order); } $query_columns = array_unique($query_columns); $query_columns = array_map(function ($column) use ($target_columns, $db) { if (isset($target_columns[$column]->alias)) { return sprintf('%s AS %s', $db->quoteIdentifier($column), $db->quote($target_columns[$column]->alias)); } return $db->quoteIdentifier($column); }, $query_columns); $query_columns = implode(', ', $query_columns); $query_groups = '(' . implode(') AND (', $query_groups) . ')'; $desc = $desc ? 'DESC' : 'ASC'; if ('compta' === $target) { $sql_query = sprintf('SELECT %s FROM acc_transactions AS t INNER JOIN acc_transactions_lines AS l ON l.id_transaction = t.id INNER JOIN acc_accounts AS a ON l.id_account = a.id LEFT JOIN acc_accounts AS a2 ON l.id_analytical = a2.id WHERE %s GROUP BY t.id ORDER BY %s %s LIMIT %d;', $query_columns, $query_groups, $order, $desc, (int) $limit); $sql_query = preg_replace('/"(a|a2|l|t)\./', '"$1"."', $sql_query); } else { $sql_query = sprintf('SELECT id, %s FROM %s WHERE %s ORDER BY %s %s LIMIT %d;', $query_columns, $target, $query_groups, $order, $desc, (int) $limit); } return $sql_query; } /** * Lancer une recherche SQL */ |
︙ | ︙ | |||
404 405 406 407 408 409 410 | if (!$no_limit && !preg_match('/LIMIT\s+\d+/i', $query)) { $query = preg_replace('/;?\s*$/', '', $query); $query .= ' LIMIT 100'; } try { | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | > > > > > > | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 | if (!$no_limit && !preg_match('/LIMIT\s+\d+/i', $query)) { $query = preg_replace('/;?\s*$/', '', $query); $query .= ' LIMIT 100'; } try { $db = DB::getInstance(); static $allowed = [ 'compta' => ['acc_transactions' => null, 'acc_transactions_lines' => null, 'acc_accounts' => null], 'membres' => ['membres' => null], ]; $db->protectSelect($allowed[$target], $query); return $db->get($query); } catch (\Exception $e) { $message = 'Erreur dans la requête : ' . $e->getMessage(); if (null !== $force_select) { $message .= "\nVérifiez que votre requête sélectionne bien les colonnes suivantes : " . implode(', ', $force_select); } throw new UserException($message); } } public function searchQuery(string $table, $query, $order, $desc = false, $limit = 100) { $sql_query = $this->buildQuery($table, $query, $order, $desc, $limit); return $this->searchSQL($table, $sql_query); } public function buildSimpleMemberQuery(string $query) { $operator = 'LIKE %?%'; if (is_numeric(trim($query))) { $column = 'numero'; $operator = '= ?'; } elseif (strpos($query, '@') !== false) { $column = 'email'; } else { $column = Config::getInstance()->get('champ_identite'); } $query = [[ 'operator' => 'AND', 'conditions' => [ [ 'column' => $column, 'operator' => $operator, 'values' => [$query], ], ], ]]; return (object) [ 'query' => $query, 'order' => $column, 'desc' => false, 'limit' => 50, ]; } public function schema($target) { $db = DB::getInstance(); if ($target == 'membres') { $tables = [ 'membres' => $db->firstColumn('SELECT sql FROM sqlite_master WHERE type = \'table\' AND name = \'membres\';'), 'categories' => $db->firstColumn('SELECT sql FROM sqlite_master WHERE type = \'table\' AND name = \'membres_categories\';'), ]; } elseif ($target == 'compta') { $tables = [ 'acc_transactions' => $db->firstColumn('SELECT sql FROM sqlite_master WHERE type = \'table\' AND name = \'acc_transactions\';'), 'acc_transactions_lines' => $db->firstColumn('SELECT sql FROM sqlite_master WHERE type = \'table\' AND name = \'acc_transactions_lines\';'), ]; } return $tables; } } |
Modified src/include/lib/Garradin/Sauvegarde.php from [adf221aa11] to [7f664d6dd4].
︙ | ︙ | |||
179 180 181 182 183 184 185 | } /** * Restaure une sauvegarde locale * @param string $file Le nom de fichier à utiliser comme point de restauration * @return boolean true si la restauration a fonctionné, false sinon */ | | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | } /** * Restaure une sauvegarde locale * @param string $file Le nom de fichier à utiliser comme point de restauration * @return boolean true si la restauration a fonctionné, false sinon */ public function restoreFromLocal($file, bool $do_backup = true) { if (preg_match('!\.\.+!', $file) || !preg_match('!^[\w\d._ -]+$!iu', $file)) { throw new UserException('Nom de fichier non valide.'); } if (!file_exists(DATA_ROOT . '/' . $file)) { throw new UserException('Le fichier fourni n\'existe pas.'); } return $this->restoreDB(DATA_ROOT . '/' . $file, false, false, false); } /** * Restaure une copie distante (fichier envoyé) * @param array $file Tableau provenant de $_FILES * @param integer $user_id ID du membre actuellement connecté, utilisé pour * vérifier qu'il est toujours administrateur dans la sauvegarde |
︙ | ︙ | |||
223 224 225 226 227 228 229 | } elseif ($integrity === false) { throw new UserException('Le fichier fourni a été modifié par un programme externe.', self::INTEGRITY_FAIL); } } | | | | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | } elseif ($integrity === false) { throw new UserException('Le fichier fourni a été modifié par un programme externe.', self::INTEGRITY_FAIL); } } $r = $this->restoreDB($file['tmp_name'], $user_id, true); if ($r) { Utils::safe_unlink($file['tmp_name']); } return $r; } /** * Vérifie l'intégrité d'une sauvegarde Garradin * @param string $file_path Chemin absolu vers la base de donnée * @return boolean|null */ protected function checkIntegrity($file_path, $remove_hash = true) { $size = filesize($file_path); $fp = fopen($file_path, 'r+'); $header = fread($fp, 16); |
︙ | ︙ | |||
285 286 287 288 289 290 291 | /** * Restauration de base de données, la fonction qui le fait vraiment * @param string $file Chemin absolu vers la base de données à utiliser * @return mixed true si rien ne va plus, ou self::NEED_UPGRADE si la version de la DB * ne correspond pas à la version de Garradin (mise à jour nécessaire). */ | | | | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | /** * Restauration de base de données, la fonction qui le fait vraiment * @param string $file Chemin absolu vers la base de données à utiliser * @return mixed true si rien ne va plus, ou self::NEED_UPGRADE si la version de la DB * ne correspond pas à la version de Garradin (mise à jour nécessaire). */ protected function restoreDB($file, $user_id = false, $check_foreign_keys = false, $do_backup = true) { $return = 1; // Essayons déjà d'ouvrir la base de données à restaurer en lecture try { $db = new \SQLite3($file, \SQLITE3_OPEN_READONLY); } catch (\Exception $e) { throw new UserException('Le fichier fourni n\'est pas une base de données valide. ' . 'Message d\'erreur de SQLite : ' . $e->getMessage(), self::NOT_A_DB); } |
︙ | ︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | 'Message d\'erreur de SQLite : ' . $e->getMessage(), self::NOT_A_DB); } if (strtolower(trim($check)) != 'ok') { throw new UserException('Le fichier fourni est corrompu. SQLite a trouvé ' . $check . ' erreurs.'); } // On ne peut pas faire de vérifications très poussées sur la structure de la base de données, // celle-ci pouvant changer d'une version à l'autre et on peut vouloir importer une base // un peu vieille, mais on vérifie quand même que ça ressemble un minimum à une base garradin $table = $db->querySingle('SELECT 1 FROM sqlite_master WHERE type=\'table\' AND tbl_name=\'config\';'); if (!$table) { throw new UserException('Le fichier fourni ne semble pas contenir de données liées à Garradin.'); } // On récupère la version $version = $db->querySingle('SELECT valeur FROM config WHERE cle=\'version\';'); | > > > > > > > > > > | | > > > > | | | | < | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | 'Message d\'erreur de SQLite : ' . $e->getMessage(), self::NOT_A_DB); } if (strtolower(trim($check)) != 'ok') { throw new UserException('Le fichier fourni est corrompu. SQLite a trouvé ' . $check . ' erreurs.'); } if ($check_foreign_keys) { $check = $db->querySingle('PRAGMA foreign_key_check;'); if ($check) { throw new UserException('Le fichier fourni est corrompu. Certaines clés étrangères référencent des lignes qui n\'existent pas.'); } } // On ne peut pas faire de vérifications très poussées sur la structure de la base de données, // celle-ci pouvant changer d'une version à l'autre et on peut vouloir importer une base // un peu vieille, mais on vérifie quand même que ça ressemble un minimum à une base garradin $table = $db->querySingle('SELECT 1 FROM sqlite_master WHERE type=\'table\' AND tbl_name=\'config\';'); if (!$table) { throw new UserException('Le fichier fourni ne semble pas contenir de données liées à Garradin.'); } // On récupère la version $version = $db->querySingle('SELECT valeur FROM config WHERE cle=\'version\';'); // On ne permet pas de restaurer une vieille version if (version_compare($version, '0.9.8', '<')) { throw new UserException(sprintf('Ce fichier a été créé avec une version trop ancienne (%s), il n\'est pas possible de le restaurer.', $version)); } // Vérification de l'AppID pour les versions récentes $appid = $db->querySingle('PRAGMA application_id;', false); if ($appid !== DB::APPID) { throw new UserException('Ce fichier n\'est pas une sauvegarde Garradin (application_id ne correspond pas).', self::NO_APP_ID); } if ($user_id) { // Empêchons l'admin de se tirer une balle dans le pied $is_still_admin = $db->querySingle('SELECT 1 FROM membres_categories WHERE id = (SELECT id_categorie FROM membres WHERE id = ' . (int) $user_id . ') |
︙ | ︙ | |||
370 371 372 373 374 375 376 377 378 379 380 381 382 383 | } if (!copy($file, DB_FILE)) { rename($backup, DB_FILE); throw new \RuntimeException('Unable to copy backup DB to main location.'); } if ($return & self::NOT_AN_ADMIN) { // Forcer toutes les catégories à pouvoir gérer les droits $db = DB::getInstance(); $db->update('membres_categories', [ 'droit_membres' => Membres::DROIT_ADMIN, | > > > > | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | } if (!copy($file, DB_FILE)) { rename($backup, DB_FILE); throw new \RuntimeException('Unable to copy backup DB to main location.'); } if (!$do_backup) { unlink($backup); } if ($return & self::NOT_AN_ADMIN) { // Forcer toutes les catégories à pouvoir gérer les droits $db = DB::getInstance(); $db->update('membres_categories', [ 'droit_membres' => Membres::DROIT_ADMIN, |
︙ | ︙ |
Added src/include/lib/Garradin/Services/Fees.php version [07a27702c2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | <?php namespace Garradin\Services; use Garradin\Config; use Garradin\DB; use Garradin\Entities\Services\Fee; use KD2\DB\EntityManager; class Fees { protected $service_id; public function __construct(int $id) { $this->service_id = $id; } static public function get(int $id) { return EntityManager::findOneById(Fee::class, $id); } /** * If $user_id is specified, then it will return a column 'user_amount' containing the amount that this specific user should pay */ static public function listAllByService(?int $user_id = null) { $db = DB::getInstance(); $sql = 'SELECT *, CASE WHEN amount THEN amount ELSE NULL END AS user_amount FROM services_fees ORDER BY id_service, label COLLATE NOCASE;'; $result = $db->get($sql); if (!$user_id) { return $result; } foreach ($result as &$row) { if ($row->formula) { $sql = sprintf('SELECT %s FROM membres WHERE id = %d;', $row->formula, $user_id); $row->user_amount = $db->firstColumn($sql); } } return $result; } public function listWithStats() { $db = DB::getInstance(); return $db->get('SELECT f.*, (SELECT COUNT(DISTINCT id_user) FROM services_users WHERE id_fee = f.id AND expiry_date >= date() AND paid = 1) AS nb_users_ok, (SELECT COUNT(DISTINCT id_user) FROM services_users WHERE id_fee = f.id AND expiry_date < date()) AS nb_users_expired, (SELECT COUNT(DISTINCT id_user) FROM services_users WHERE id_fee = f.id AND paid = 0) AS nb_users_unpaid FROM services_fees f WHERE id_service = ? ORDER BY transliterate_to_ascii(label) COLLATE NOCASE;', $this->service_id); } } |
Added src/include/lib/Garradin/Services/Reminders.php version [09c61c980b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | <?php namespace Garradin\Services; use Garradin\Config; use Garradin\DB; use Garradin\Plugin; use Garradin\Utils; use Garradin\Entities\Services\Reminder; use KD2\DB\EntityManager; use const Garradin\WWW_URL; use const Garradin\ADMIN_URL; class Reminders { static public function list() { return DB::getInstance()->get('SELECT s.label AS service_label, sr.* FROM services_reminders sr INNER JOIN services s ON s.id = sr.id_service ORDER BY s.label COLLATE NOCASE;'); } static public function get(int $id) { return EntityManager::findOneById(Reminder::class, $id); } static public function listSentForUser(int $user_id) { return DB::getInstance()->get('SELECT rs.date AS sent_date, r.delay, s.label, rs.id AS sent_id, s.id AS service_id FROM services_reminders_sent rs INNER JOIN services_reminders r ON r.id = rs.id_reminder INNER JOIN services s ON s.id = rs.id_service WHERE rs.id_user = ?;', $user_id); } static public function listSentForReminder(int $reminder_id) { return DB::getInstance()->get('SELECT rs.date AS sent_date, r.delay, s.label, rs.id AS sent_id, s.id AS service_id FROM services_reminders_sent rs INNER JOIN services_reminders r ON r.id = rs.id_reminder INNER JOIN services s ON s.id = rs.id_service WHERE rs.id_reminder = ?;', $user_id); } static public function listForService(int $service_id) { return DB::getInstance()->get('SELECT * FROM services_reminders WHERE id_service = ? ORDER BY delay, subject;', $service_id); } /** * Remplacer les tags dans le contenu/sujet du mail * @param string $content Chaîne à traiter * @param array $data Données supplémentaires à utiliser comme tags (tableau associatif) * @return string $content dont les tags ont été remplacés par le contenu correct */ static public function replaceTagsInContent(string $content, ?array $data = null) { $config = Config::getInstance(); $tags = [ '#NOM_ASSO' => $config->get('nom_asso'), '#ADRESSE_ASSO' => $config->get('adresse_asso'), '#EMAIL_ASSO' => $config->get('email_asso'), '#SITE_ASSO' => $config->get('site_asso'), '#URL_RACINE' => WWW_URL, '#URL_SITE' => WWW_URL, '#URL_ADMIN' => ADMIN_URL, ]; if (!empty($data) && is_array($data)) { foreach ($data as $key=>$value) { $key = '#' . strtoupper($key); $tags[$key] = $value; } } return strtr($content, $tags); } /** * Envoi de mail pour rappel automatisé */ static public function sendAuto(\stdClass $reminder) { $replace = [ 'identite' => $reminder->identity, 'date_rappel' => Utils::date_fr($reminder->reminder_date), 'date_expiration' => Utils::date_fr($reminder->expiry_date), 'nb_jours' => $reminder->nb_days, 'delai' => $reminder->delay, ]; $subject = self::replaceTagsInContent($reminder->subject, $replace); $text = self::replaceTagsInContent($reminder->body, $replace); // Envoi du mail Utils::sendEmail(Utils::EMAIL_CONTEXT_PRIVATE, $reminder->email, $subject, $text, $reminder->id_user); $db = DB::getInstance(); $db->insert('services_reminders_sent', [ 'id_service' => $reminder->id_service, 'id_user' => $reminder->id_user, 'id_reminder' => $reminder->id_reminder, ]); Plugin::fireSignal('rappels.auto', $reminder); return true; } /** * Envoi des rappels automatiques par e-mail * @return boolean TRUE en cas de succès */ static public function sendPending() { $db = DB::getInstance(); $config = Config::getInstance(); $sql = 'SELECT date(su.expiry_date, sr.delay || \' days\') AS reminder_date, ABS(julianday(date()) - julianday(expiry_date)) AS nb_days, MAX(sr.delay) AS delay, sr.subject, sr.body, s.label, s.description, su.expiry_date, sr.id AS id_reminder, su.id_service, su.id_user, m.email, m.%s AS identity FROM services_users su INNER JOIN services s ON s.id = su.id_service INNER JOIN services_reminders sr ON sr.id_service = su.id_service -- Join with users, but not ones part of a hidden category INNER JOIN membres m ON su.id_user = m.id AND m.email IS NOT NULL AND (m.id_categorie NOT IN (SELECT id FROM membres_categories WHERE cacher = 1)) -- Join with sent reminders to exclude users that already have received this reminder LEFT JOIN services_reminders_sent srs ON srs.id_reminder = sr.id AND srs.id_user = su.id_user WHERE date() > date(su.expiry_date, sr.delay || \' days\') AND srs.id IS NULL GROUP BY su.id_user, s.id ORDER BY su.id_user;'; $sql = sprintf($sql, $config->get('champ_identite')); foreach ($db->iterate($sql) as $row) { self::sendAuto($row); } return true; } } |
Added src/include/lib/Garradin/Services/Services.php version [8034954296].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <?php namespace Garradin\Services; use Garradin\Config; use Garradin\DB; use Garradin\Entities\Services\Service; use KD2\DB\EntityManager; class Services { static public function get(int $id) { return EntityManager::findOneById(Service::class, $id); } static public function listAssoc() { return DB::getInstance()->getAssoc('SELECT id, label FROM services ORDER BY label COLLATE NOCASE;'); } static public function listGroupedWithFees(?int $user_id = null) { $services = DB::getInstance()->getGrouped('SELECT id, label, duration, start_date, end_date, description, CASE WHEN end_date IS NOT NULL THEN end_date WHEN duration IS NOT NULL THEN date(\'now\', \'+\'||duration||\' days\') ELSE NULL END AS expiry_date FROM services;'); $fees = Fees::listAllByService($user_id); $out = []; foreach ($services as $service) { $out[$service->id] = $service; $out[$service->id]->fees = []; } foreach ($fees as $fee) { $out[$fee->id_service]->fees[] = $fee; } return $out; } static public function listWithStats() { $db = DB::getInstance(); return $db->get('SELECT s.*, (SELECT COUNT(DISTINCT id_user) FROM services_users WHERE id_service = s.id AND expiry_date >= date() AND paid = 1) AS nb_users_ok, (SELECT COUNT(DISTINCT id_user) FROM services_users WHERE id_service = s.id AND expiry_date < date()) AS nb_users_expired, (SELECT COUNT(DISTINCT id_user) FROM services_users WHERE id_service = s.id AND paid = 0) AS nb_users_unpaid FROM services s ORDER BY transliterate_to_ascii(s.label) COLLATE NOCASE;'); } } |
Added src/include/lib/Garradin/Services/Services_User.php version [2e5fb9387a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | <?php namespace Garradin\Services; use Garradin\DB; use Garradin\DynamicList; use Garradin\Entities\Services\Service_User; use KD2\DB\EntityManager; class Services_User { static public function get(int $id) { return EntityManager::findOneById(Service_User::class, $id); } static public function countForUser(int $user_id) { return DB::getInstance()->count(Service_User::TABLE, 'id_user = ?', $user_id); } static public function listDistinctForUser(int $user_id) { return DB::getInstance()->get('SELECT s.label, MAX(su.expiry_date) AS expiry_date, sf.label AS fee_label, su.paid, s.end_date, CASE WHEN su.expiry_date < date() THEN -1 WHEN su.expiry_date >= date() THEN 1 ELSE 0 END AS status FROM services_users su INNER JOIN services s ON s.id = su.id_service INNER JOIN services_fees sf ON sf.id = su.id_fee WHERE su.id_user = ? GROUP BY su.id_service ORDER BY expiry_date DESC;', $user_id); } static public function perUserList(int $user_id): DynamicList { $columns = [ 'id' => [ 'select' => 'su.id', ], 'id_account' => [ 'select' => 'sf.id_account', ], 'label' => [ 'select' => 's.label', 'label' => 'Activité', ], 'date' => [ 'label' => 'Date d\'inscription', 'select' => 'su.date', ], 'expiry' => [ 'label' => 'Date d\'expiration', 'select' => 'MAX(su.expiry_date)', ], 'fee' => [ 'label' => 'Tarif', 'select' => 'sf.label', ], 'paid' => [ 'label' => 'Payé', 'select' => 'su.paid', ], 'amount' => [ 'label' => 'Reste à régler', 'select' => 'expected_amount - SUM(tl.debit)', ], ]; $tables = 'services_users su INNER JOIN services s ON s.id = su.id_service LEFT JOIN services_fees sf ON sf.id = su.id_fee LEFT JOIN acc_transactions_users tu ON tu.id_service_user = su.id LEFT JOIN acc_transactions_lines tl ON tl.id_transaction = tu.id_transaction'; $conditions = sprintf('su.id_user = %d', $user_id); $list = new DynamicList($columns, $tables, $conditions); $list->orderBy('date', true); $list->groupBy('su.id'); $list->setCount('COUNT(DISTINCT su.id)'); return $list; } } |
Modified src/include/lib/Garradin/Squelette.php from [c51c3077ae] to [1036393224].
︙ | ︙ | |||
581 582 583 584 585 586 587 | default: break; } } if (trim($loopContent)) { | | | | | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | default: break; } } if (trim($loopContent)) { $loop_start .= '$row[\'url\'] = Fichiers::_getURL($row[\'id\'], $row[\'nom\'], $row[\'hash\']); '; $loop_start .= '$row[\'miniature\'] = $row[\'image\'] ? Fichiers::_getURL($row[\'id\'], $row[\'nom\'], $row[\'hash\'], 200) : \'\'; '; $loop_start .= '$row[\'moyenne\'] = $row[\'image\'] ? Fichiers::_getURL($row[\'id\'], $row[\'nom\'], $row[\'hash\'], 500) : \'\'; '; } $query .= $where . ' ' . $order; if (!$limit || $limit > 100) $limit = 100; |
︙ | ︙ | |||
644 645 646 647 648 649 650 | { $query = 'SELECT 0 LIMIT 0;'; } } try { // Sécurité anti injection, à la compilation seulement | | | 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 | { $query = 'SELECT 0 LIMIT 0;'; } } try { // Sécurité anti injection, à la compilation seulement $statement = $db->protectSelect(null, $query); } catch (\Exception $e) { throw new \KD2\MiniSkelMarkupException("Erreur SQL dans la requête : ".$e->getMessage() . "\n " . $query); } $hash = sha1(uniqid(mt_rand(), true)); |
︙ | ︙ | |||
819 820 821 822 823 824 825 826 827 828 829 830 831 832 | elseif (substr($uri, -1) == '/') { $skel = 'rubrique.html'; $_GET['uri'] = $_REQUEST['uri'] = substr($uri, 1, -1); } elseif (preg_match('!^/admin/!', $uri)) { throw new UserException('Cette page n\'existe pas.'); } else { $_GET['uri'] = $_REQUEST['uri'] = substr($uri, 1); if (preg_match('!^[\w\d_-]+$!i', $_GET['uri']) | > | 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 | elseif (substr($uri, -1) == '/') { $skel = 'rubrique.html'; $_GET['uri'] = $_REQUEST['uri'] = substr($uri, 1, -1); } elseif (preg_match('!^/admin/!', $uri)) { http_response_code(404); throw new UserException('Cette page n\'existe pas.'); } else { $_GET['uri'] = $_REQUEST['uri'] = substr($uri, 1); if (preg_match('!^[\w\d_-]+$!i', $_GET['uri']) |
︙ | ︙ |
Modified src/include/lib/Garradin/Squelette_Filtres.php from [4ef78402d4] to [d1aad48bcc].
︙ | ︙ | |||
96 97 98 99 100 101 102 | } elseif (date('Ymd', $date) == date('Ymd', strtotime('tomorrow'))) { $jour = 'demain'; } elseif (date('Y', $date) == date('Y')) { | | | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | } elseif (date('Ymd', $date) == date('Ymd', strtotime('tomorrow'))) { $jour = 'demain'; } elseif (date('Y', $date) == date('Y')) { $jour = strtolower(Utils::strftime_fr($date, '%A %e %B')); } else { $jour = strtolower(Utils::strftime_fr($date, '%e %B %Y')); } if ($avec_heure) { return sprintf('%s, %s', $jour, $heure); } |
︙ | ︙ |
Modified src/include/lib/Garradin/Template.php from [f7f37fea68] to [dc008398eb].
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; use KD2\Form; use Garradin\Membres\Session; class Template extends \KD2\Smartyer { static protected $_instance = null; static public function getInstance() { | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace Garradin; use KD2\Form; use KD2\HTTP; use KD2\Translate; use Garradin\Membres\Session; use Garradin\Entities\Accounting\Account; class Template extends \KD2\Smartyer { static protected $_instance = null; static public function getInstance() { |
︙ | ︙ | |||
36 37 38 39 40 41 42 | // pour les éléments statiques (genre /admin/static/admin.css?v0.9.0) // car cela dévoilerait la version de Garradin utilisée, posant un souci // en cas de faille, on cache donc la version utilisée, chaque instance // aura sa propre version $this->assign('version_hash', substr(sha1(garradin_version() . garradin_manifest() . ROOT . SECRET_KEY), 0, 10)); $this->assign('www_url', WWW_URL); | | | < > > > > > < < | < < < < | < < < < | < < < < < < < < | < < | | < < < < | < < > > > > > > > > > > > > > > > > > > > > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | // pour les éléments statiques (genre /admin/static/admin.css?v0.9.0) // car cela dévoilerait la version de Garradin utilisée, posant un souci // en cas de faille, on cache donc la version utilisée, chaque instance // aura sa propre version $this->assign('version_hash', substr(sha1(garradin_version() . garradin_manifest() . ROOT . SECRET_KEY), 0, 10)); $this->assign('www_url', WWW_URL); $this->assign('self_url', Utils::getSelfURI()); $this->assign('self_url_no_qs', Utils::getSelfURI(false)); $this->assign('is_logged', false); $this->assign('password_pattern', sprintf('.{%d,}', Session::MINIMUM_PASSWORD_LENGTH)); $this->assign('password_length', Session::MINIMUM_PASSWORD_LENGTH); $this->register_compile_function('continue', function ($pos, $block, $name, $raw_args) { if ($block == 'continue') { return 'continue;'; } }); $this->register_function('form_errors', [$this, 'formErrors']); $this->register_function('show_error', [$this, 'showError']); $this->register_function('form_field', [$this, 'formField']); $this->register_function('html_champ_membre', [$this, 'formChampMembre']); $this->register_function('input', [$this, 'formInput']); $this->register_function('custom_colors', [$this, 'customColors']); $this->register_function('plugin_url', ['Garradin\Utils', 'plugin_url']); $this->register_function('diff', [$this, 'diff']); $this->register_function('pagination', [$this, 'pagination']); $this->register_function('format_droits', [$this, 'formatDroits']); $this->register_function('csrf_field', function ($params) { return Form::tokenHTML($params['key']); }); $this->register_function('icon', [$this, 'widgetIcon']); $this->register_function('button', [$this, 'widgetButton']); $this->register_function('linkbutton', [$this, 'widgetLinkButton']); $this->register_modifier('strlen', 'strlen'); $this->register_modifier('dump', ['KD2\ErrorManager', 'dump']); $this->register_modifier('get_country_name', ['Garradin\Utils', 'getCountryName']); $this->register_modifier('format_tel', [$this, 'formatPhoneNumber']); $this->register_modifier('abs', 'abs'); $this->register_modifier('display_champ_membre', [$this, 'displayChampMembre']); $this->register_modifier('format_bytes', ['Garradin\Utils', 'format_bytes']); $this->register_modifier('strftime_fr', [Utils::class, 'strftime_fr']); $this->register_modifier('date_fr', [Utils::class, 'date_fr']); $this->register_modifier('date_long', [Utils::class, 'date_fr']); $this->register_modifier('date_short', function ($dt) { return Utils::date_fr($dt, 'd/m/Y'); }); $this->register_modifier('html_money', [$this, 'htmlMoney']); $this->register_modifier('money_currency', [$this, 'htmlMoneyCurrency']); $this->register_modifier('format_wiki', function ($str) { $str = Utils::SkrivToHTML($str); $str = Squelette_Filtres::typo_fr($str); return $str; }); $this->register_modifier('liens_wiki', function ($str, $prefix) { return preg_replace_callback('!<a href="([^/.:@]+)">!i', function ($matches) use ($prefix) { return '<a href="' . $prefix . Wiki::transformTitleToURI($matches[1]) . '">'; }, $str); }); } protected function htmlMoney($number, bool $hide_empty = true): string { if ($hide_empty && !$number) { return ''; } return sprintf('<b class="money">%s</b>', Utils::money_format($number, ',', ' ', $hide_empty)); } protected function htmlMoneyCurrency($number, bool $hide_empty = true): string { $out = $this->htmlMoney($number, $hide_empty); if ($out !== '') { $out .= ' ' . Config::getInstance()->get('monnaie'); } return $out; } protected function formErrors($params) { $form = $this->getTemplateVars('form'); if (!$form->hasErrors()) { return ''; } $errors = $form->getErrorMessages(!empty($params['membre']) ? true : false); $errors = array_map([$this, 'escape'], $errors); $errors = array_map('nl2br', $errors); return '<div class="block error"><ul><li>' . implode('</li><li>', $errors) . '</li></ul></div>'; } protected function showError($params) { if (!$params['if']) { return ''; } return '<p class="block error">' . $this->escape($params['message']) . '</p>'; } protected function widgetIcon(array $params): string { if (empty($params['href'])) { return sprintf('<b class="icn">%s</b>', Utils::iconUnicode($params['shape'])); } return sprintf('<a href="%s" class="icn" title="%s">%s</a>', $this->escape(ADMIN_URL . $params['href']), $this->escape($params['label']), Utils::iconUnicode($params['shape'])); } protected function widgetButton(array $params): string { $icon = Utils::iconUnicode($params['shape']); $label = isset($params['label']) ? $this->escape($params['label']) : ''; unset($params['label'], $params['shape']); if (!isset($params['type'])) { $params['type'] = 'button'; } if (!isset($params['class'])) { $params['class'] = ''; } if (isset($params['name']) && !isset($params['value'])) { $params['value'] = 1; } $params['class'] .= ' icn-btn'; array_walk($params, function (&$v, $k) { $v = sprintf('%s="%s"', $k, $this->escape($v)); }); $params = implode(' ', $params); return sprintf('<button %s data-icon="%s">%s</button>', $params, $icon, $label); } protected function widgetLinkButton(array $params): string { $href = $params['href']; $shape = $params['shape']; $label = $params['label']; // href can be prefixed with '!' to make the URL relative to ADMIN_URL if (substr($href, 0, 1) == '!') { $href = ADMIN_URL . substr($params['href'], 1); } unset($params['href'], $params['shape'], $params['label']); array_walk($params, function (&$v, $k) { $v = sprintf('%s="%s"', $k, $this->escape($v)); }); $params = implode(' ', $params); return sprintf('<a class="icn-btn" data-icon="%s" href="%s" %s>%s</a>', Utils::iconUnicode($shape), $this->escape($href), $params, $this->escape($label)); } protected function formInput(array $params) { static $params_list = ['value', 'default', 'type', 'help', 'label', 'name', 'options', 'source']; // Extract params and keep attributes separated $attributes = array_diff_key($params, array_flip($params_list)); $params = array_intersect_key($params, array_flip($params_list)); extract($params, \EXTR_SKIP); if (!isset($name, $type)) { throw new \InvalidArgumentException('Missing name or type'); } $current_value = null; $current_value_from_user = false; if (isset($_POST[$name])) { $current_value = $_POST[$name]; $current_value_from_user = true; } elseif (isset($source) && is_object($source) && isset($source->$name)) { $current_value = $source->$name; } elseif (isset($source) && is_array($source) && isset($source[$name])) { $current_value = $source[$name]; } elseif (isset($default)) { $current_value = $default; } if ($type == 'date' && is_object($current_value) && $current_value instanceof \DateTimeInterface) { $current_value = $current_value->format('d/m/Y'); } elseif ($type == 'date' && is_string($current_value)) { if ($v = \DateTime::createFromFormat('!Y-m-d', $current_value)) { $current_value = $v->format('d/m/Y'); } } $attributes['id'] = 'f_' . $name; $attributes['name'] = $name; if ($type == 'radio' || $type == 'checkbox') { $attributes['id'] .= '_' . $value; if ($current_value == $value) { $attributes['checked'] = 'checked'; } $attributes['value'] = $value; } elseif ($type == 'date') { $type = 'text'; $attributes['placeholder'] = 'JJ/MM/AAAA'; $attributes['data-input'] = 'date'; $attributes['size'] = 12; $attributes['maxlength'] = 10; $attributes['pattern'] = '\d\d?/\d\d?/\d{4}'; } // Create attributes string if (array_key_exists('required', $attributes)) { $attributes['required'] = 'required'; } if (!empty($attributes['disabled'])) { $attributes['disabled'] = 'disabled'; unset($attributes['required']); } else { unset($attributes['disabled']); } if (array_key_exists('required', $attributes) || array_key_exists('fake_required', $attributes)) { $required_label = ' <b title="Champ obligatoire">(obligatoire)</b>'; } else { $required_label = ' <i>(facultatif)</i>'; } // Fake required: doesn't set the required attribute, just the label // (useful for form elements that are hidden by JS) unset($attributes['fake_required']); $attributes_string = $attributes; array_walk($attributes_string, function (&$v, $k) { $v = sprintf('%s="%s"', $k, $v); }); $attributes_string = implode(' ', $attributes_string); if ($type == 'select') { $input = sprintf('<select %s>', $attributes_string); foreach ($options as $_key => $_value) { $input .= sprintf('<option value="%s"%s>%s</option>', $_key, $current_value == $_key ? ' selected="selected"' : '', $this->escape($_value)); } $input .= '</select>'; } elseif ($type == 'select_groups') { $input = sprintf('<select %s>', $attributes_string); foreach ($options as $optgroup => $suboptions) { $input .= sprintf('<optgroup label="%s">', $this->escape($optgroup)); foreach ($suboptions as $_key => $_value) { $input .= sprintf('<option value="%s"%s>%s</option>', $_key, $current_value == $_key ? ' selected="selected"' : '', $this->escape($_value)); } $input .= '</optgroup>'; } $input .= '</select>'; } elseif ($type == 'textarea') { $input = sprintf('<textarea %s>%s</textarea>', $attributes_string, $this->escape($current_value)); } elseif ($type == 'list') { $multiple = !empty($attributes['multiple']); $values = ''; $delete_btn = $this->widgetButton(['shape' => 'delete']); if (null !== $current_value) { foreach ($current_value as $v => $l) { $values .= sprintf('<span class="label"><input type="hidden" name="%s[%s]" value="%s" /> %3$s %s</span>', $this->escape($name), $this->escape($v), $this->escape($l), $multiple ? $delete_btn : ''); } } $button = $this->widgetButton([ 'shape' => $multiple ? 'plus' : 'menu', 'value' => (substr($attributes['target'], 0, 4) === 'http') ? $attributes['target'] : ADMIN_URL . $attributes['target'], 'label' => $multiple ? 'Ajouter' : 'Sélectionner', 'data-multiple' => $multiple ? '1' : '0', 'data-name' => $name, ]); $input = sprintf('<span id="%s_container" class="input-list">%s%s</span>', $this->escape($attributes['id']), $button, $values); } elseif ($type == 'money') { if (null !== $current_value && !$current_value_from_user) { $current_value = Utils::money_format($current_value, ',', ''); } $currency = Config::getInstance()->get('monnaie'); $input = sprintf('<nobr><input type="text" pattern="[0-9]*([.,][0-9]{1,2})?" inputmode="decimal" size="8" class="money" %s value="%s" /><b>%s</b></nobr>', $attributes_string, $this->escape($current_value), $currency); } else { $value = isset($attributes['value']) ? '' : sprintf(' value="%s"', $this->escape($current_value)); $input = sprintf('<input type="%s" %s %s />', $type, $attributes_string, $value); } // No label? then we only want the input without the widget if (empty($label)) { if (!array_key_exists('label', $params) && ($type == 'radio' || $type == 'checkbox')) { $input .= sprintf('<label for="%s"></label>', $attributes['id']); } return $input; } if ($type == 'file') { $input .= sprintf('<input type="hidden" name="MAX_FILE_SIZE" value="%d" id="f_maxsize" />', Utils::return_bytes(Utils::getMaxUploadSize())); } $label = sprintf('<label for="%s">%s</label>', $attributes['id'], $this->escape($label)); if ($type == 'radio' || $type == 'checkbox') { $out = sprintf('<dd>%s %s', $input, $label); if (isset($help)) { $out .= sprintf(' <em class="help">(%s)</em>', $this->escape($help)); } $out .= '</dd>'; } else { $out = sprintf('<dt>%s%s</dt><dd>%s</dd>', $label, $required_label, $input); if ($type == 'file') { $out .= sprintf('<dd class="help"><small>Taille maximale : %s</small></dd>', Utils::format_bytes(Utils::getMaxUploadSize())); } if (isset($help)) { $out .= sprintf('<dd class="help">%s</dd>', $this->escape($help)); } } return $out; } protected function formField(array $params, $escape = true) { if (!isset($params['name'])) { throw new \BadFunctionCallException('name argument is mandatory'); |
︙ | ︙ | |||
238 239 240 241 242 243 244 | $couleur2 = implode(', ', sscanf($couleur2, '#%02x%02x%02x')); $out = ' <style type="text/css"> :root { --gMainColor: %s; --gSecondColor: %s; | < < < | < | > > > > > > > > | | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 | $couleur2 = implode(', ', sscanf($couleur2, '#%02x%02x%02x')); $out = ' <style type="text/css"> :root { --gMainColor: %s; --gSecondColor: %s; --gBgImage: url("%s"); } </style>'; return sprintf($out, $couleur1, $couleur2, $image_fond); } protected function displayChampMembre($v, $config = null) { if (is_string($config)) { $config = Config::getInstance()->get('champs_membres')->get($config); } if (null === $config) { return htmlspecialchars($v); } switch ($config->type) { case 'checkbox': return $v ? 'Oui' : 'Non'; case 'email': return '<a href="mailto:' . rawurlencode($v) . '">' . htmlspecialchars($v) . '</a>'; case 'tel': return '<a href="tel:' . rawurlencode($v) . '">' . htmlspecialchars($v) . '</a>'; case 'url': return '<a href="' . htmlspecialchars($v) . '">' . htmlspecialchars($v) . '</a>'; case 'country': return Utils::getCountryName($v); case 'date': return Utils::date_fr($v); case 'multiple': $out = []; foreach ($config->options as $b => $name) { if ($v & (0x01 << $b)) $out[] = $name; |
︙ | ︙ | |||
439 440 441 442 443 444 445 | if ($type != 'checkbox') { $out .= ' <dd>' . $field . '</dd>'; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 | if ($type != 'checkbox') { $out .= ' <dd>' . $field . '</dd>'; } return $out; } protected function diff(array $params) { if (!isset($params['old']) || !isset($params['new'])) { |
︙ | ︙ |
Added src/include/lib/Garradin/Upgrade.php version [d98424ca2c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | <?php namespace Garradin; use Garradin\Membres\Session; class Upgrade { static public function preCheck() { $config = Config::getInstance(); $v = $config->getVersion(); if (version_compare($v, garradin_version(), '>=')) { throw new UserException("Pas de mise à jour à faire."); } if (!$v || version_compare($v, '0.9.8', '<')) { throw new UserException("Votre version de Garradin est trop ancienne pour être mise à jour. Mettez à jour vers Garradin 0.9.8 avant de faire la mise à jour vers cette version."); } Install::checkAndCreateDirectories(); if (Static_Cache::exists('upgrade')) { $path = Static_Cache::getPath('upgrade'); throw new UserException('Une mise à jour est déjà en cours.' . PHP_EOL . 'Si celle-ci a échouée et que vous voulez ré-essayer, supprimez le fichier suivant:' . PHP_EOL . $path); } // Voir si l'utilisateur est loggé, on le fait ici pour le cas où // il y aurait déjà eu des entêtes envoyés au navigateur plus bas $session = new Session; $user_is_logged = $session->isLogged(true); } static public function upgrade() { $config = Config::getInstance(); $v = $config->getVersion(); $session = new Session; $user_is_logged = $session->isLogged(true); Static_Cache::store('upgrade', 'Mise à jour en cours.'); $db = DB::getInstance(); // Créer une sauvegarde automatique $backup_name = (new Sauvegarde)->create('pre-upgrade-' . garradin_version()); try { if (version_compare($v, '1.0.0-alpha1', '<')) { $db->beginSchemaUpdate(); $db->import(ROOT . '/include/data/1.0.0_migration.sql'); $db->commitSchemaUpdate(); // Import nouveau plan comptable $chart = new \Garradin\Entities\Accounting\Chart; $chart->label = 'Plan comptable associatif 2018'; $chart->country = 'FR'; $chart->code = 'PCA2018'; $chart->save(); $chart->accounts()->importCSV(ROOT . '/include/data/charts/fr_2018.csv'); } if (version_compare($v, '1.0.0-beta1', '>=') && version_compare($v, '1.0.0-beta6', '<')) { $db->beginSchemaUpdate(); $db->import(ROOT . '/include/data/1.0.0-beta6_migration.sql'); $db->commitSchemaUpdate(); } if (version_compare($v, '1.0.0-beta6', '>=') && version_compare($v, '1.0.0-beta8', '<')) { $db->beginSchemaUpdate(); $db->import(ROOT . '/include/data/1.0.0-beta8_migration.sql'); $db->commitSchemaUpdate(); } if (version_compare($v, '1.0.0-beta1', '>=') && version_compare($v, '1.0.0-rc3', '<')) { $db->beginSchemaUpdate(); $db->import(ROOT . '/include/data/1.0.0-rc3_migration.sql'); $db->commitSchemaUpdate(); } // Vérification de la cohérence des clés étrangères $db->foreignKeyCheck(); Utils::clearCaches(); $config->setVersion(garradin_version()); Static_Cache::remove('upgrade'); // Réinstaller les plugins système si nécessaire Plugin::checkAndInstallSystemPlugins(); // Mettre à jour les plugins si nécessaire foreach (Plugin::listInstalled() as $id=>$infos) { // Ne pas tenir compte des plugins dont le code n'est pas dispo if ($infos->disabled) { continue; } $plugin = new Plugin($id); if ($plugin->needUpgrade()) { $plugin->upgrade(); } unset($plugin); } } catch (\Exception $e) { $s = new Sauvegarde; $s->restoreFromLocal($backup_name); $s->remove($backup_name); Static_Cache::remove('upgrade'); throw $e; } // Forcer à rafraîchir les données de la session si elle existe if ($user_is_logged) { $session->refresh(); } } } |
Modified src/include/lib/Garradin/Utils.php from [4d9bf0c755] to [8eb825d6d4].
1 2 3 4 5 6 | <?php namespace Garradin; use KD2\Security; use KD2\Form; | | | | | | | > > > | > > > > > > > > > > > > | > > > | > > | > | | > > > > > > > | | < < < < < < < < < < < < < < < < < < | < < < < < | < < < < | < < < < < < < > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | <?php namespace Garradin; use KD2\Security; use KD2\Form; use KD2\HTTP; use KD2\Translate; use KD2\SMTP; class Utils { const EMAIL_CONTEXT_BULK = 'bulk'; const EMAIL_CONTEXT_PRIVATE = 'private'; const EMAIL_CONTEXT_SYSTEM = 'system'; static protected $skriv = null; const FRENCH_DATE_NAMES = [ 'January'=>'Janvier', 'February'=>'Février', 'March'=>'Mars', 'April'=>'Avril', 'May'=>'Mai', 'June'=>'Juin', 'July'=>'Juillet', 'August'=>'Août', 'September'=>'Septembre', 'October'=>'Octobre', 'November'=>'Novembre', 'December'=>'Décembre', 'Monday'=>'Lundi', 'Tuesday'=>'Mardi', 'Wednesday'=>'Mercredi', 'Thursday'=>'Jeudi','Friday'=>'Vendredi','Saturday'=>'Samedi','Sunday'=>'Dimanche', 'Feb'=>'Fév','Apr'=>'Avr','Jun'=>'Juin', 'Jul'=>'Juil','Aug'=>'Aout','Dec'=>'Déc', 'Mon'=>'Lun','Tue'=>'Mar','Wed'=>'Mer','Thu'=>'Jeu','Fri'=>'Ven','Sat'=>'Sam','Sun'=>'Dim']; static public function get_datetime($ts) { if (is_object($ts) && $ts instanceof \DateTimeInterface) { return $ts; } elseif (is_numeric($ts)) { return new \DateTime('@' . $ts); } elseif (strlen($ts) == 10) { return \DateTime::createFromFormat('!Y-m-d', $ts); } elseif (strlen($ts) == 19) { return \DateTime::createFromFormat('Y-m-d H:i:s', $ts); } else { return null; } } static public function strftime_fr($ts, $format) { $ts = self::get_datetime($ts); if (null === $ts) { return $ts; } $date = strftime($format, $ts->getTimestamp()); $date = strtr($date, self::FRENCH_DATE_NAMES); $date = strtolower($date); return $date; } static public function date_fr($ts, $format = null) { $ts = self::get_datetime($ts); if (null === $ts) { return $ts; } if (is_null($format)) { $format = 'd/m/Y à H:i'; } $date = $ts->format($format); $date = strtr($date, self::FRENCH_DATE_NAMES); $date = strtolower($date); return $date; } /** * @deprecated */ static public function checkDate($str) { if (!preg_match('!^(\d{4})-(\d{2})-(\d{2})$!', $str, $match)) return false; if (!checkdate($match[2], $match[3], $match[1])) return false; return true; } /** * @deprecated */ static public function checkDateTime($str) { if (!preg_match('!^(\d{4}-\d{2}-\d{2})[T ](\d{2}):(\d{2})!', $str, $match)) return false; if (!self::checkDate($match[1])) return false; if ((int) $match[2] < 0 || (int) $match[2] > 23) return false; if ((int) $match[3] < 0 || (int) $match[3] > 59) return false; if (isset($match[4]) && ((int) $match[4] < 0 || (int) $match[4] > 59)) return false; return true; } static public function moneyToInteger($value) { if (trim($value) === '') { return 0; } if (!preg_match('/^-?(\d+)(?:[,.](\d{1,2}))?$/', $value, $match)) { throw new UserException(sprintf('Le format du montant est invalide : %s. Format accepté, exemple : 142,02', $value)); } $value = $match[1] . str_pad(@$match[2], 2, '0', STR_PAD_RIGHT); $value = (int) $value; return $value; } static public function money_format($number, string $dec_point = ',', string $thousands_sep = ' ', $zero_if_empty = true): string { if ($number == 0) { return $zero_if_empty ? '0' : '0,00'; } $sign = $number < 0 ? '-' : ''; $number = abs((int) $number); $decimals = substr('0' . $number, -2); $number = (int) substr($number, 0, -2); return sprintf('%s%s%s%s', $sign, number_format($number, 0, $dec_point, $thousands_sep), $dec_point, $decimals); } static public function getRequestURI() { if (!empty($_SERVER['REQUEST_URI'])) return $_SERVER['REQUEST_URI']; else return false; |
︙ | ︙ | |||
143 144 145 146 147 148 149 150 151 152 153 154 155 156 | if (is_array($qs)) { $uri .= '?' . http_build_query($qs); } return str_replace('/admin', '', ADMIN_URL) . $uri; } public static function redirect($destination=false, $exit=true) { if (empty($destination) || !preg_match('/^https?:\/\//', $destination)) { if (empty($destination)) $destination = WWW_URL; | > > > > > > > > > > | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | if (is_array($qs)) { $uri .= '?' . http_build_query($qs); } return str_replace('/admin', '', ADMIN_URL) . $uri; } static public function getSelfURI(bool $qs = true) { return str_replace(substr(WWW_URL, 0, -1), '', self::getSelfURL($qs)); } static public function getModifiedURL(string $new) { return HTTP::mergeURLs(self::getSelfURL(), $new); } public static function redirect($destination=false, $exit=true) { if (empty($destination) || !preg_match('/^https?:\/\//', $destination)) { if (empty($destination)) $destination = WWW_URL; |
︙ | ︙ | |||
219 220 221 222 223 224 225 | * $listLength représente la longueur d'items de la pagination à génerer * * @param int $current * @param int $total * @param int $bypage * @param int $listLength * @param bool $showLast Toggle l'affichage du dernier élément de la pagination | | | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | * $listLength représente la longueur d'items de la pagination à génerer * * @param int $current * @param int $total * @param int $bypage * @param int $listLength * @param bool $showLast Toggle l'affichage du dernier élément de la pagination * @return array|null */ public static function getGenericPagination($current, $total, $bypage, $listLength=11, $showLast = true) { if ($total <= $bypage) return null; $total = ceil($total / $bypage); if ($total < $current) return null; $length = ($listLength / 2); $begin = $current - ceil($length); if ($begin < 1) { $begin = 1; |
︙ | ︙ | |||
401 402 403 404 405 406 407 | static public function safe_unlink($path) { if (!@unlink($path)) { return true; } | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | static public function safe_unlink($path) { if (!@unlink($path)) { return true; } if (!file_exists($path)) { return true; } throw new \RuntimeException(sprintf('Impossible de supprimer le fichier %s: %s', $path, error_get_last())); return true; } static public function safe_mkdir($path, $mode = 0777, $recursive = false) { return @mkdir($path, $mode, $recursive) || is_dir($path); } static public function suggestPassword() { return Security::getRandomPassphrase(ROOT . '/include/data/dictionary.fr'); } static public function normalizePhoneNumber($n) { return preg_replace('![^\d\+\(\)p#,;-]!', '', trim($n)); } static public function write_ini_string($in) { |
︙ | ︙ | |||
557 558 559 560 561 562 563 | case 'G': case 'g': return (int)$size_str * pow(1024, 3); case 'M': case 'm': return (int)$size_str * pow(1024, 2); case 'K': case 'k': return (int)$size_str * 1024; default: return $size_str; } } | | > | | | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | case 'G': case 'g': return (int)$size_str * pow(1024, 3); case 'M': case 'm': return (int)$size_str * pow(1024, 2); case 'K': case 'k': return (int)$size_str * 1024; default: return $size_str; } } static public function format_bytes($size) { if ($size > (1024 * 1024)) return number_format(round($size / 1024 / 1024, 2), 2, ',', '') . ' Mo'; elseif ($size > 1024) return round($size / 1024) . ' Ko'; else return $size . ' o'; } static public function deleteRecursive($path) { if (!file_exists($path)) |
︙ | ︙ | |||
586 587 588 589 590 591 592 | if (is_dir($path . '/' . $file)) { if (!self::deleteRecursive($path . '/' . $file)) return false; } else { | | | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | if (is_dir($path . '/' . $file)) { if (!self::deleteRecursive($path . '/' . $file)) return false; } else { self::safe_unlink($path . '/' . $file); } } $dir->close(); rmdir($path); return true; |
︙ | ︙ | |||
621 622 623 624 625 626 627 | if (!(is_numeric($params['query']) && (int)$params['query'] === 1) && $params['query'] !== true) $url .= $params['query']; } return $url; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | if (!(is_numeric($params['query']) && (int)$params['query'] === 1) && $params['query'] !== true) $url .= $params['query']; } return $url; } static public function sendEmail($context, $recipient, $subject, $content, $id_membre = null, $pgp_key = null) { // Ne pas envoyer de mail à des adresses invalides if (!SMTP::checkEmailIsValid($recipient, false)) { throw new UserException('Adresse email invalide: ' . $recipient); } |
︙ | ︙ | |||
828 829 830 831 832 833 834 | { $raw_headers .= sprintf("%s: %s\r\n", $name, $value); } return \mail($to, $subject, $content, $raw_headers); } } | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 | { $raw_headers .= sprintf("%s: %s\r\n", $name, $value); } return \mail($to, $subject, $content, $raw_headers); } } static public function iconUnicode(string $shape): string { switch ($shape) { case 'up': return '↑'; case 'down': return '↓'; case 'export': return '↷'; case 'reset': return '↺'; case 'upload': return '⇑'; case 'download': return '⇓'; case 'home': return '⌂'; case 'print': return '⎙'; case 'star': return '★'; case 'check': return '☑'; case 'settings': return '☸'; case 'alert': return '⚠'; case 'mail': return '✉'; case 'edit': return '✎'; case 'delete': return '✘'; case 'help': return '❓'; case 'plus': return '➕'; case 'minus': return '➖'; case 'logout': return '⤝'; case 'eye-off': return '⤫'; case 'menu': return '𝍢'; case 'eye': return '👁'; case 'user': return '👤'; case 'users': return '👪'; case 'calendar': return '📅'; case 'attach': return '📎'; case 'search': return '🔍'; case 'lock': return '🔒'; case 'unlock': return '🔓'; case 'folder': return '🗀'; case 'document': return '🗅'; case 'bold': return 'B'; case 'italic': return 'I'; case 'header': return 'H'; case 'paragraph': return '§'; case 'list-ol': return 'ģ'; case 'list-ul': return '•'; case 'table': return '◫'; case 'radio-unchecked': return '◯'; case 'uncheck': return '☐'; case 'radio-checked': return '⬤'; case 'image': return '🖻'; case 'left': return '←'; case 'right': return '→'; default: throw new \InvalidArgumentException('Unknown icon shape: ' . $shape); } } static public function array_transpose(array $array): array { $out = []; $count = null; foreach ($array as $column => $rows) { if (null !== $count && count($rows) != $count) { throw new \LogicException('Array is inconsistent'); } $count = count($rows); foreach ($rows as $k => $v) { if (!isset($out[$k])) { $out[$k] = []; } $out[$k][$column] = $v; } } return $out; } static public function rgbHexToDec(string $hex) { return sscanf($hex, '#%02x%02x%02x'); } /** * Converts an RGB color value to HSV. Conversion formula * adapted from http://en.wikipedia.org/wiki/HSV_color_space. * Assumes r, g, and b are contained in the set [0, 255] and * returns h, s, and v in the set [0, 1]. * * @param Number r The red color value * @param Number g The green color value * @param Number b The blue color value * @return Array The HSV representation */ static public function rgbToHsv($r, $g = null, $b = null) { if (is_string($r) && is_null($g) && is_null($b)) { list($r, $g, $b) = self::rgbHexToDec($r); } $r /= 255; $g /= 255; $b /= 255; $max = max($r, $g, $b); $min = min($r, $g, $b); $h = $s = $v = $max; $d = $max - $min; $s = ($max == 0) ? 0 : $d / $max; if($max == $min) { $h = 0; // achromatic } else { switch($max) { case $r: $h = ($g - $b) / $d + ($g < $b ? 6 : 0); break; case $g: $h = ($b - $r) / $d + 2; break; case $b: $h = ($r - $g) / $d + 4; break; } $h /= 6; } return array($h * 360, $s, $v); } static public function HTTPCache(string $hash, int $expiry): bool { $etag = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : null; $last_modified = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : null; if ($etag === $hash && $last_modified <= $expiry) { header('HTTP/1.1 304 Not Modified', true, 304); exit; } header(sprintf('Last-Modified: %s GMT', gmdate('D, d M Y H:i:s', $expiry))); header(sprintf('Etag: %s', $hash)); header('Cache-Control: private'); return false; } } |
Modified src/include/lib/Garradin/Wiki.php from [640f809bb6] to [6ab9be5a8f].
︙ | ︙ | |||
465 466 467 468 469 470 471 | 'id' => $id, 'titre' => $res->titre, 'uri' => $res->uri, ]; if ($id == $res->parent) { | | | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | 'id' => $id, 'titre' => $res->titre, 'uri' => $res->uri, ]; if ($id == $res->parent) { throw new \Exception('Parent! ' . $id . '/' . $res->parent); } $id = (int)$res->parent; } return array_reverse($flat); } |
︙ | ︙ |
Modified src/include/lib/dependencies.list from [7b518732e5] to [b716c7d0a7].
1 | KD2/data/ | > | > | | | > > > | < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | KD2/data/ KD2/DB/AbstractEntity.php KD2/DB/DB.php KD2/DB/EntityManager.php KD2/DB/SQLite3.php KD2/ErrorManager.php KD2/FileInfo.php KD2/Form.php KD2/HTTP.php KD2/Graphics/Image.php KD2/Graphics/QRCode.php KD2/Graphics/SVG/Pie.php KD2/Graphics/SVG/Plot.php KD2/MiniSkel.php KD2/Office/Calc/Writer.php KD2/Security.php KD2/Security_OTP.php KD2/SimpleDiff.php KD2/SkrivLite.php KD2/Smartyer.php KD2/SMTP.php KD2/Translate.php KD2/UserSession.php KD2/ZipWriter.php |
Modified src/include/test_required.php from [69fc54870f] to [a96dd46521].
︙ | ︙ | |||
30 31 32 33 34 35 36 | echo "Pour plus d'informations consulter http://dev.kd2.org/garradin/Probl%C3%A8mes%20fr%C3%A9quents\n"; } exit; } test_requis( | | | | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | echo "Pour plus d'informations consulter http://dev.kd2.org/garradin/Probl%C3%A8mes%20fr%C3%A9quents\n"; } exit; } test_requis( version_compare(phpversion(), '7.2', '>='), 'PHP 7.2 ou supérieur requis. PHP version ' . phpversion() . ' installée.' ); test_requis( defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH, 'L\'algorithme de hashage de mot de passe Blowfish n\'est pas présent (pas installé ou pas compilé).' ); test_requis( class_exists('SQLite3'), 'Le module de base de données SQLite3 n\'est pas disponible.' ); $v = \SQLite3::version(); test_requis( version_compare($v['versionString'], '3.16', '>='), 'SQLite3 version 3.16 ou supérieur requise. Version installée : ' . $v['versionString'] ); test_requis( file_exists(__DIR__ . '/lib/KD2'), 'Librairie KD2 non disponible.' ); |
Added src/templates/acc/_simple_help.tpl version [09ea62fa86].
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <details> <summary class="help block"> Attention : dans cette vue simplifiée, {if $type == Entities\Accounting\Account::TYPE_THIRD_PARTY}les dettes de ce tiers envers l'association apparaissent au crédit (positif) et les créances au débit (négatif) ! {elseif $type}les écritures apparaissent tels que sur le relevé de banque ou le journal de caisse ! {else}les comptes de banque, caisse, dépenses et tiers apparaissent de manière « simplifiée » ! {/if} C'est l'inverse de la {if $link}<a href="{$link}">{/if}la vue comptable{if $link}</a>{/if} en comptabilité en partie double.</summary> <div class="help block"> <p>L'extrait de compte fourni par la banque fonctionne « à l'envers », parce qu'il est établi du point de vue de la banque :</p> <ul> <li>les sommes versées sur votre compte (salaires etc.) constituent pour elle une ressource ( = crédit ; simultanément, cela augmente la dette de la banque à votre égard, ou réduit votre dette à son égard si vous êtes « débiteur »),</li> <li>les sommes retirées (paiement de chèques, carte bleue, etc.) constituent une utilisation ( = débit).</li> </ul> <p>Du point de vue du client de la banque, dans une comptabilité en partie double, ce que la banque appelle crédit (une entrée d'argent) est un débit (c'est une utilisation de l'argent), et inversement (un débit pour la banque est une ressource de son client, donc, pour lui, un crédit). (<a href="https://fr.wikipedia.org/wiki/Comptabilit%C3%A9_en_partie_double">Source Wikipedia</a>)</p> </div> </details> |
Added src/templates/acc/_year_select.tpl version [9d69235d94].
> > > > > | 1 2 3 4 5 | <nav class="acc-year"> <h4>Exercice sélectionné :</h4> <h3>{$current_year.label} — {$current_year.start_date|date_short} au {$current_year.end_date|date_short}</h3> <footer>{linkbutton label="Changer d'exercice" href="!acc/years/select.php?from=%s"|args:rawurlencode($self_url) shape="settings"}</footer> </nav> |
Added src/templates/acc/accounts/deposit.tpl version [970d3a07a5].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | {include file="admin/_head.tpl" title="Dépôt en banque : %s — %s"|args:$account.code,$account.label current="acc/accounts" js=1} <p class="help"> Cocher les cases correspondant aux montants à déposer, une nouvelle écriture sera générée. </p> {form_errors} <form method="post" action="{$self_url}" data-focus="1"> <table class="list"> <thead> <tr> <td class="check"><input type="checkbox" title="Tout cocher / décocher" id="f_all" /><label for="f_all"></label></td> <td></td> <td>Date</td> <td>Réf. écriture</td> <td>Réf. ligne</td> <th>Libellé</th> <td class="money">Montant</td> <td class="money">Solde cumulé</td> </tr> </thead> <tbody> {foreach from=$journal item="line"} {if isset($line.sum)} <tr> <td colspan="5"></td> <td class="money">{if $line.sum > 0}-{/if}{$line.sum|abs|raw|html_money:false}</td> <th>Solde au {$line.date|date_short}</th> <td colspan="2"></td> </tr> {else} <tr> <td class="check"> {input type="checkbox" name="deposit[%d]"|args:$line.id value="1" data-debit=$line.debit|abs data-credit=$line.credit default=$line.checked} </td> <td class="num"><a href="{$admin_url}acc/transactions/details.php?id={$line.id}">#{$line.id}</a></td> <td>{$line.date|date_short}</td> <td>{$line.reference}</td> <td>{$line.line_reference}</td> <th>{$line.label}</th> <td class="money">{$line.debit|raw|html_money}</td> <td class="money">{if $line.running_sum > 0}-{/if}{$line.running_sum|abs|raw|html_money:false}</td> </tr> {/if} {/foreach} </tbody> </table> <fieldset> <legend>Détails de l'écriture de dépôt</legend> <dl> {input type="text" name="label" label="Libellé" required=1 default="Dépôt en banque"} {input type="date" name="date" default=$date label="Date" required=1} {input type="money" name="amount" label="Montant" required=1} {input type="list" target="acc/charts/accounts/selector.php?chart=%d&targets=%d"|args:$account.id_chart,$target name="account_transfer" label="Compte de dépôt" required=1} {input type="text" name="reference" label="Numéro de pièce comptable"} {input type="textarea" name="notes" label="Remarques" rows=4 cols=30} </dl> </fieldset> <p class="submit"> {csrf_field key="acc_deposit_%s"|args:$account.id} {button type="submit" name="save" label="Enregistrer" class="main" shape="check"} </p> </form> {literal} <script type="text/javascript"> var total = 0; $('tbody input[type=checkbox]').forEach((e) => { e.addEventListener('change', () => { var v = e.getAttribute('data-debit') || e.getAttribute('data-credit'); v = parseInt(v, 10); total += e.checked ? v : -v; if (total < 0) { total = 0; } $('#f_amount').value = g.formatMoney(total); }); }); $('#f_all').addEventListener('change', (e) => { $('#f_amount').value = ''; total = 0; }); </script> {/literal} {include file="admin/_foot.tpl"} |
Added src/templates/acc/accounts/index.tpl version [d00593bab9].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | {include file="admin/_head.tpl" title="Comptes favoris" current="acc/accounts"} {include file="acc/_year_select.tpl"} <nav class="tabs"> <ul> <li class="current"><a href="{$admin_url}acc/accounts/">Comptes favoris</a></li> <li><a href="{$admin_url}acc/reports/trial_balance.php?year={$current_year.id}">Balance générale (tous les comptes)</a></li> <li><a href="{$admin_url}acc/search.php?year={$current_year.id}">Recherche</a></li> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} <li><a href="{$admin_url}acc/charts/accounts/all.php?id={$chart_id}">Plan comptable</a></li> {/if} </ul> </nav> {include file="acc/_simple_help.tpl" link="../reports/trial_balance.php?year=%d"|args:$current_year.id type=null} {if !empty($grouped_accounts)} <table class="list"> <thead> <tr> <td class="num">Numéro</td> <th>Compte</th> <td class="money">Solde</td> <td></td> <td></td> </tr> </thead> {foreach from=$grouped_accounts item="group"} <tbody> <tr> <td colspan="5"><h2 class="ruler">{$group.label}</h2></td> </tr> {foreach from=$group.accounts item="account"} <tr> <td class="num"><a href="{$admin_url}acc/accounts/journal.php?id={$account.id}&year={$current_year.id}">{$account.code}</a></td> <th><a href="{$admin_url}acc/accounts/journal.php?id={$account.id}&year={$current_year.id}">{$account.label}</a></th> <td class="money"> {if $account.sum < 0}<strong class="error">{/if} {$account.sum|raw|money_currency:false} {if $account.sum < 0}</strong>{/if} </td> <td> {if $account.type == Entities\Accounting\Account::TYPE_THIRD_PARTY} <em class="alert"> {if $account.sum < 0}(Dette) {elseif $account.sum > 0}(Créance) {/if} </em> {/if} </td> <td class="actions"> {linkbutton label="Journal" shape="menu" href="journal.php?id=%d&year=%d"|args:$account.id,$current_year.id} {if $session->canAccess('compta', Membres::DROIT_ADMIN)} {if $account.type == Entities\Accounting\Account::TYPE_BANK} {linkbutton label="Rapprochement" shape="check" href="reconcile.php?id=%d"|args:$account.id} {elseif $account.type == Entities\Accounting\Account::TYPE_OUTSTANDING} {linkbutton label="Dépôt en banque" shape="check" href="deposit.php?id=%d"|args:$account.id} {/if} {/if} </td> </tr> {/foreach} </tbody> {/foreach} </table> {/if} <p class="help"> Note : n'apparaissent ici que les comptes favoris. Pour voir le solde de tous les comptes, se référer à la <a href="{$admin_url}acc/reports/trial_balance.php?year={$current_year.id}">balance générale de l'exercice</a>. </p> {include file="admin/_foot.tpl"} |
Added src/templates/acc/accounts/journal.tpl version [1e2a345225].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | {include file="admin/_head.tpl" title="Journal : %s - %s"|args:$account.code:$account.label current="acc/accounts" body_id="rapport" js=1} {if empty($year)} {include file="acc/_year_select.tpl"} {else} <nav class="acc-year"> <h4>Exercice sélectionné :</h4> <h3>{$year.label} — {$year.start_date|date_short} au {$year.end_date|date_short}</h3> </nav> {/if} {if $account.type} {if $simple && $account::isReversed($account.type)} {include file="acc/_simple_help.tpl" link="?id=%d&simple=0&year=%d"|args:$account.id,$year.id type=$account.type} {/if} {if $simple} {if $account.type == $account::TYPE_THIRD_PARTY} {if $sum < 0} <p class="alert block">Vous devez <strong>{$sum|abs|raw|money_currency}</strong> à ce tiers.</p> {elseif $sum > 0} <p class="alert block">Ce tiers vous doit <strong>{$sum|abs|raw|money_currency}</strong>.</p> {else} <p class="confirm block">Vous ne devez pas d'argent à ce tiers, et il ne vous en doit pas non plus.</p> {/if} {elseif $account.type == $account::TYPE_BANK} {if $sum < 0} <p class="error block">Ce compte est à découvert de <strong>{$sum|abs|raw|money_currency}</strong> à la banque.</p> {elseif $sum >= 0} <p class="confirm block">Ce compte est créditeur de <strong>{$sum|abs|raw|money_currency}</strong> à la banque.</p> {/if} {elseif $account.type == $account::TYPE_CASH} {if $sum < 0} <p class="error block">Cette caisse est débiteur de <strong>{$sum|abs|raw|money_currency}</strong>. Est-ce normal ? Une vérification est peut-être nécessaire ?</p> {elseif $sum >= 0} <p class="confirm block">Cette caisse est créditrice de <strong>{$sum|abs|raw|money_currency}</strong>.</p> {/if} {elseif $account.type == $account::TYPE_OUTSTANDING} {if $sum < 0} <p class="error block">Ce compte est débiteur <strong>{$sum|abs|raw|money_currency}</strong>. Est-ce normal ? Une vérification est peut-être nécessaire ?</p> {elseif $sum >= 0} <p class="confirm block">Ce compte d'attente est créditeur de <strong>{$sum|abs|raw|money_currency}</strong>. {if $sum > 200}Un dépôt à la banque serait peut-être une bonne idée ?{/if}</p> {/if} {/if} {/if} <nav class="tabs"> <aside> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} {linkbutton href="%s&export=csv"|args:$self_url label="Export CSV" shape="export"} {linkbutton href="%s&export=ods"|args:$self_url label="Export tableur" shape="export"} {/if} {if $year.id == CURRENT_YEAR_ID} {linkbutton href="!acc/transactions/new.php?account=%d"|args:$account.id label="Saisir une écriture dans ce compte" shape="plus"} {/if} </aside> <ul> <li{if $simple} class="current"{/if}><a href="?id={$account.id}&simple=1&year={$year.id}">Vue simplifiée</a></li> <li{if !$simple} class="current"{/if}><a href="?id={$account.id}&simple=0&year={$year.id}">Vue comptable</a></li> </ul> </nav> {/if} <form method="post" action="{$admin_url}acc/transactions/actions.php"> {include file="common/dynamic_list_head.tpl" check=$can_edit} {foreach from=$list->iterate() item="line"} <tr> {if $can_edit} <td class="check"> {input type="checkbox" name="check[%s]"|args:$line.id_line value=$line.id default=0} </td> {/if} <td class="num"><a href="{$admin_url}acc/transactions/details.php?id={$line.id}">#{$line.id}</a></td> <td>{$line.date|date_short}</td> {if $simple} <td class="money">{if $line.change > 0}+{else}-{/if}{$line.change|abs|raw|html_money}</td> {else} <td class="money">{$line.debit|raw|html_money}</td> <td class="money">{$line.credit|raw|html_money}</td> {/if} {if isset($line->sum)} <td class="money">{$line.sum|raw|html_money:false}</td> {/if} <td>{$line.reference}</td> <th>{$line.label}</th> {if !$simple}<td>{$line.line_label}</td>{/if} <td>{$line.line_reference}</td> <td class="num">{if $line.id_analytical}<a href="{$admin_url}acc/reports/statement.php?analytical={$line.id_analytical}">{$line.code_analytical}</a>{/if}</td> <td class="actions"> {if ($line.status & Entities\Accounting\Transaction::STATUS_WAITING)} {if $line.type == Entities\Accounting\Transaction::TYPE_DEBT} {linkbutton shape="check" label="Régler cette dette" href="!acc/transactions/new.php?payoff_for=%d"|args:$line.id} {elseif $line.type == Entities\Accounting\Transaction::TYPE_CREDIT} {linkbutton shape="export" label="Régler cette créance" href="!acc/transactions/new.php?payoff_for=%d"|args:$line.id} {/if} {/if} {linkbutton href="!acc/transactions/details.php?id=%d"|args:$line.id label="Détails" shape="search"} </td> </tr> {/foreach} </tbody> <tfoot> <tr> {if $can_edit} <td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all2" /><label for="f_all2"></label></td> {/if} {if !$simple}<td></td>{/if} <td colspan="3">Solde</td> <td class="money">{$sum|raw|html_money:false}</td> {if !$simple}<td></td>{/if} <td class="actions" colspan="5"> {if $can_edit} <em>Pour les écritures cochées :</em> <input type="hidden" name="from" value="{$self_url}" /> <input type="hidden" name="year" value="{$year.id}" /> {csrf_field key="projects_action"} <select name="action"> <option value="">— Choisir une action à effectuer —</option> <option value="change_analytical">Ajouter/enlever d'un projet</option> <option value="delete">Supprimer les écritures</option> </select> <noscript> {button type="submit" value="OK" shape="right" label="Valider"} </noscript> {/if} </td> </tr> </tfoot> </table> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/accounts/reconcile.tpl version [eccd019e3c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | {include file="admin/_head.tpl" title="Rapprochement : %s — %s"|args:$account.code,$account.label current="acc/accounts" js=1} {include file="acc/_year_select.tpl"} <nav class="tabs"> <ul> <li class="current"><a href="{$admin_url}acc/accounts/reconcile.php?id={$account.id}">Rapprochement manuel</a></li> <li><a href="{$admin_url}acc/accounts/reconcile_assist.php?id={$account.id}">Rapprochement assisté</a></li> </ul> </nav> <form method="get" action="{$self_url_no_qs}"> {if $prev || $next} <fieldset class="shortFormRight"> <legend>Rapprochement par mois</legend> <p> {if $prev} {linkbutton shape="left" href=$prev.url label=$prev.date|date_fr:'F Y'} {/if} {if $next} {linkbutton shape="right" href=$next.url label=$next.date|date_fr:'F Y'} {/if} </p> </fieldset> {/if} <fieldset class="shortFormLeft"> <legend>Période de rapprochement</legend> <p> Du {input type="date" name="start" default=$start} au {input type="date" name="end" default=$end} </p> <p> <label>{input type="checkbox" name="only" value=1 default=$only} Seulement les écritures non rapprochées</label> <input type="hidden" name="id" value="{$account.id}" /> <input type="submit" value="Afficher" /> </p> </fieldset> </form> <p class="block help"> Les écritures apparaissent ici dans le sens du relevé de banque, à l'inverse des journaux comptables. </p> {form_errors} <form method="post" action="{$self_url}"> <table class="list"> <thead> <tr> <td class="check"><input type="checkbox" title="Tout cocher / décocher" id="f_all" /><label for="f_all"></label></td> <td></td> <td>Date</td> <td class="money">Débit</td> <td class="money">Crédit</td> <td class="money">Solde cumulé</td> <td class="money">Solde rapproché</td> <th>Libellé</th> <th>Réf. écriture</th> <th>Réf. ligne</th> </tr> </thead> <tbody> {foreach from=$journal item="line"} {if isset($line->sum)} <tr> <td colspan="5"></td> <td class="money">{if $line.sum > 0}-{/if}{$line.sum|abs|raw|html_money:false}</td> <td class="money">{if $line.reconciled_sum > 0}-{/if}{$line.reconciled_sum|abs|raw|html_money}</td> <th>Solde au {$line.date|date_short}</th> <td colspan="2"></td> </tr> {else} <tr> <td class="check"> {input type="checkbox" name="reconcile[%d]"|args:$line.id_line value="1" default=$line.reconciled} </td> <td class="num"><a href="{$admin_url}acc/transactions/details.php?id={$line.id}">#{$line.id}</a></td> <td>{$line.date|date_short}</td> <td class="money">{$line.credit|raw|html_money}</td> <td class="money">{$line.debit|raw|html_money}</td> {* Not a bug! Credit/debit is reversed here to reflect the bank statement *} <td class="money">{if $line.running_sum > 0}-{/if}{$line.running_sum|abs|raw|html_money:false}</td> <td class="money">{if $line.reconciled_sum > 0}-{/if}{$line.reconciled_sum|abs|raw|html_money:false}</td> <th>{$line.label}</th> <td>{$line.reference}</td> <td>{$line.line_reference}</td> </tr> {/if} {/foreach} </tbody> </table> <p class="submit"> {csrf_field key="acc_reconcile_%s"|args:$account.id} {button type="submit" name="save" label="Enregistrer" class="main" shape="check"} {if $next} {button type="submit" name="save_next" label="Enregistrer et aller au mois suivant" class="main minor" shape="right"} {/if} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/accounts/reconcile_assist.tpl version [06c3b7fb54].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | {include file="admin/_head.tpl" title="Rapprochement : %s — %s"|args:$account.code,$account.label current="acc/accounts" js=1} {include file="acc/_year_select.tpl"} <nav class="tabs"> <ul> <li><a href="{$admin_url}acc/accounts/reconcile.php?id={$account.id}">Rapprochement manuel</a></li> <li class="current"><a href="{$admin_url}acc/accounts/reconcile_assist.php?id={$account.id}">Rapprochement assisté</a></li> </ul> </nav> {form_errors} <form method="post" action="{$self_url}" enctype="multipart/form-data"> {if !$csv->loaded()} <fieldset> <legend>Relevé de compte</legend> <p class="help block"> Le rapprochement assisté permet de s'aider d'un relevé de compte au format CSV pour trouver les écritures manquantes ou erronées.<br /> <a href="https://fossil.kd2.org/garradin/wiki?name=Compta/Rapprochement_assist%C3%A9" target="_blank">Aide détaillée</a> </p> <dl> {include file="common/_csv_help.tpl"} {input type="file" name="file" label="Fichier CSV" accept=".csv,text/csv" required=1} </dl> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="upload" label="Envoyer le fichier" class="main" shape="upload"} </p> </fieldset> {elseif !$csv->ready()} {include file="common/_csv_match_columns.tpl"} <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="cancel" value="1" label="Annuler" shape="left"} {button type="submit" name="assign" label="Continuer" class="main" shape="right"} </p> {else} <fieldset> <legend>Relevé de compte</legend> <dl> <dt> Nombre de lignes </dt> <dd> {$csv->count()} </dd> <dt> Période couverte </dt> <dd> Du {$start|date_short} au {$end|date_short} </dd> </dl> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="cancel" value="1" label="Annuler" shape="left"} </p> </fieldset> {/if} </form> {if !empty($lines)} <p class="block help"> Les écritures apparaissent ici dans le sens du relevé de banque, à l'inverse des journaux comptables. </p> <form method="post" action="{$self_url}"> <table class="list"> <thead> <tr> <th colspan="6">Journal du compte (compta)</th> <td class="separator"></td> <th colspan="4" class="separator">Extrait de compte (banque)</th> </tr> <tr> <td class="check"><input type="checkbox" title="Tout cocher / décocher" id="f_all" /><label for="f_all"></label></td> <td></td> <td>Date</td> <td class="money">Mouvement</td> <td class="money">Solde cumulé</td> <th style="text-align: right">Libellé</th> <td class="separator"></td> <th class="separator">Libellé</th> <td class="money">Mouvement</td> <td class="money">Solde cumulé</td> <td>Date</td> </tr> </thead> <tbody> {foreach from=$lines key="line_id" item="line"} {if isset($line->journal->sum)} <tr> <td colspan="4"></td> <td class="money">{if $line.journal.sum > 0}-{/if}{$line.journal.sum|abs|raw|html_money:false}</td> <th style="text-align: right">Solde au {$line.journal.date|date_short}</th> <td class="separator"></td> <td class="separator"></td> <td colspan="3"></td> </tr> {else} <tr> {if isset($line->journal)} <td class="check"> {input type="checkbox" name="reconcile[%d]"|args:$line.journal.id_line value="1" default=$line.journal.reconciled} </td> <td class="num"><a href="{$admin_url}acc/transactions/details.php?id={$line.journal.id}">#{$line.journal.id}</a></td> <td>{$line.journal.date|date_short}</td> <td class="money"> {if $line.journal.credit} {* Not a bug! Credit/debit is reversed here to reflect the bank statement *} -{$line.journal.credit|raw|html_money} {else} {$line.journal.debit|raw|html_money} {/if} </td> <td class="money">{if $line.journal.running_sum > 0}-{/if}{$line.journal.running_sum|abs|raw|html_money:false}</td> <th style="text-align: right">{$line.journal.label}</th> {else} <td colspan="5"></td> <td style="text-align: right"> {if $line.add} {* FIXME later add ability to pre-fill multi-line transactions in new.php {linkbutton label="Créer cette écriture" target="_blank" href="%s&create=%s"|args:$self_url,$line_id shape="plus"} *} {/if} </td> {/if} <td class="separator"> {if $line->journal && $line->csv} == {else} <b class="icn">⚠</b> {/if} </td> {if isset($line->csv)} <th class="separator">{$line.csv.label}</th> <td class="money"> {$line.csv.amount|raw|html_money} </td> <td class="money">{$line.csv.running_sum|raw|html_money}</td> <td>{$line.csv.date|date_short}</td> {else} <td colspan="4" class="separator"></td> {/if} </tr> {/if} {/foreach} </tbody> </table> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" class="main" shape="check"} </p> </form> {/if} {include file="admin/_foot.tpl"} |
Added src/templates/acc/accounts/simple.tpl version [57003f8670].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | {include file="admin/_head.tpl" title="Suivi : %s"|args:$types[$type] current="acc/simple" js=1} {if empty($year)} {include file="acc/_year_select.tpl"} {else} <nav class="acc-year"> <h4>Exercice sélectionné :</h4> <h3>{$year.label} — {$year.start_date|date_short} au {$year.end_date|date_short}</h3> </nav> {/if} <nav class="tabs"> <aside> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} {linkbutton href="?type=%d&export=csv"|args:$type label="Export CSV" shape="export"} {linkbutton href="?type=%d&export=ods"|args:$type label="Export tableur" shape="export"} {/if} </aside> <ul> {foreach from=$types key="key" item="label"} <li{if $type == $key} class="current"{/if}><a href="?type={$key}">{$label}</a></li> {/foreach} </ul> </nav> {if !$list->count()} <p class="alert block"> Aucune écriture à afficher. </p> {else} <form method="post" action="{$admin_url}acc/transactions/actions.php"> {include file="common/dynamic_list_head.tpl" check=$can_edit} {foreach from=$list->iterate() item="line"} <tr> {if $can_edit} <td class="check"> {input type="checkbox" name="check[%s]"|args:$line.id_line value=$line.id default=0} </td> {/if} <td class="num"><a href="{$admin_url}acc/transactions/details.php?id={$line.id}">#{$line.id}</a></td> <td>{$line.date|date_short}</td> <td class="money">{$line.change|abs|raw|html_money}</td> <td>{$line.reference}</td> <th>{$line.label}</th> <td>{$line.line_reference}</td> <td class="num">{if $line.id_analytical}<a href="{$admin_url}acc/reports/statement.php?analytical={$line.id_analytical}">{$line.code_analytical}</a>{/if}</td> <td class="actions"> {if $line.type == Entities\Accounting\Transaction::TYPE_DEBT && ($line.status & Entities\Accounting\Transaction::STATUS_WAITING)} {linkbutton shape="check" label="Régler cette dette" href="!acc/transactions/new.php?payoff_for=%d"|args:$line.id} {elseif $line.type == Entities\Accounting\Transaction::TYPE_CREDIT && ($line.status & Entities\Accounting\Transaction::STATUS_WAITING)} {linkbutton shape="export" label="Régler cette créance" href="!acc/transactions/new.php?payoff_for=%d"|args:$line.id} {/if} {linkbutton href="!acc/transactions/details.php?id=%d"|args:$line.id label="Détails" shape="search"} </td> </tr> {/foreach} </tbody> {if $can_edit} <tfoot> <tr> <td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all2" /><label for="f_all2"></label></td> <td class="actions" colspan="10"> <em>Pour les écritures cochées :</em> <input type="hidden" name="from" value="{$self_url}" /> <input type="hidden" name="year" value="{$year.id}" /> {csrf_field key="projects_action"} <select name="action"> <option value="">— Choisir une action à effectuer —</option> <option value="change_analytical">Ajouter/enlever d'un projet</option> <option value="delete">Supprimer les écritures</option> </select> <noscript> {button type="submit" value="OK" shape="right" label="Valider"} </noscript> </td> </tr> </tfoot> {/if} </table> </form> {pagination url=$list->paginationURL() page=$list.page bypage=$list.per_page total=$list->count()} {/if} {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/accounts/_account_form.tpl version [67f92e389c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | <dl> {input type="select" label="Type de compte favori" name="type" source=$account required=true options=$types} <dd class="help">Le statut de compte favori est utilisé pour les écritures <em>« simplifiées »</em> (recettes, dépenses, dettes, créances, virements), pour la liste des comptes, et également pour proposer certaines fonctionnalités (rapprochement pour les comptes bancaires, règlement rapide de dette et créance, dépôt de chèques).</dd> <dd class="help">Un compte qui n'a pas de type favori ne pourra être utilisé que dans une saisie avancée, et ne sera visible que dans les rapports de l'exercice.</dd> {if !$simple} <dt><label for="f_position_0">Position au bilan ou résultat</label>{if !$edit_disabled} <b>(obligatoire)</b>{/if}</dt> <dd class="help">La position permet d'indiquer dans quelle partie du bilan ou du résultat doit figurer le compte.</dd> <dd class="help">Les comptes inscrits en actif ou passif figureront dans le bilan, alors que ceux inscrits en produit ou charge figureront au compte de résultat.</dd> {input type="radio" label="Ne pas utiliser ce compte au bilan ni au résultat" name="position" value=0 source=$account disabled=$edit_disabled} {input type="radio" label="Bilan : actif" name="position" value=Entities\Accounting\Account::ASSET source=$account help="ce que possède l'association : stocks, locaux, soldes bancaires, etc." disabled=$edit_disabled} {input type="radio" label="Bilan : passif" name="position" value=Entities\Accounting\Account::LIABILITY source=$account help="ce que l'association doit : dettes, provisions, réserves, etc." disabled=$edit_disabled} {input type="radio" label="Bilan : actif ou passif" name="position" value=Entities\Accounting\Account::ASSET_OR_LIABILITY source=$account help="le compte sera placé à l'actif si son solde est débiteur, ou au passif s'il est créditeur" disabled=$edit_disabled} {input type="radio" label="Résultat : charge" name="position" value=Entities\Accounting\Account::EXPENSE source=$account help="dépenses" disabled=$edit_disabled} {input type="radio" label="Résultat : produit" name="position" value=Entities\Accounting\Account::REVENUE source=$account help="recettes" disabled=$edit_disabled} {/if} </dl> <dl id="code_container"> {input type="text" label="Code" maxlength="10" name="code" source=$account required=true help="Le code du compte sert à trier le compte dans le plan comptable, attention à choisir un code qui correspond au plan comptable." disabled=$edit_disabled} </dl> <dl> {input type="text" label="Libellé" name="label" source=$account required=true disabled=$edit_disabled} {input type="textarea" label="Description" name="description" source=$account} </dl> {if isset($translate_type_position, $translate_type_codes)} <script type="text/javascript"> var types_positions = {$translate_type_position|escape:json}; var types_codes = {$translate_type_codes|escape:json}; var simple = {$simple|escape:json}; {literal} $('#f_type').onchange = changeType; function changeType() { var v = $('#f_type').value; if ($('#f_position_0')) { if (v in types_positions) { $('#f_position_' + types_positions[v]).checked = true; } else { $('#f_position_3').checked = true; } } var code = $('#f_code'); if (types_codes[v]) { code.value = types_codes[v]; } else { code.value = ''; } if (simple && !(v in types_codes)) { g.toggle('#code_container', true); } else if (simple) { g.toggle('#code_container', false); } } changeType(); {/literal} </script> {/if} |
Added src/templates/acc/charts/accounts/_nav.tpl version [ec091420e5].
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <nav class="tabs"> <ul> <li class="current"><a href="{$admin_url}acc/charts/">Plans comptables</a></li> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} <li><a href="{$admin_url}acc/charts/import.php">Importer un plan comptable</a></li> {/if} </ul> <ul class="sub"> <li class="title">{$chart.label}</li> <li{if $current == 'favorites'} class="current"{/if}><a href="{$admin_url}acc/charts/accounts/?id={$chart.id}">Comptes favoris</a></li> <li{if $current == 'all'} class="current"{/if}><a href="{$admin_url}acc/charts/accounts/all.php?id={$chart.id}">Tous les comptes</a></li> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} <li{if $current == 'new'} class="current"{/if}><a href="{$admin_url}acc/charts/accounts/new.php?id={$chart.id}"><strong>Ajouter un compte</strong></a></li> {/if} </ul> </nav> |
Added src/templates/acc/charts/accounts/all.tpl version [532b7dcf92].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | {include file="admin/_head.tpl" title="Plan comptable"|args:$chart.label current="acc/charts"} {include file="acc/charts/accounts/_nav.tpl" current="all"} <p class="help"> Les comptes marqués comme « <em>Ajouté</em> » ont été ajoutés au plan comptable officiel par vous-même. </p> <table class="accounts"> <tbody> {foreach from=$accounts item="account"} <tr class="account-level-{$account.code|strlen}"> <td>{$account.code}</td> <th>{$account.label}</th> <td> {if $account.type} {icon shape="star"} <?=Entities\Accounting\Account::TYPES_NAMES[$account->type]?> {/if} </td> <td> {if $account.user}<em>Ajouté</em>{/if} </td> <td class="actions"> {if $session->canAccess('compta', Membres::DROIT_ADMIN) && !$chart.archived} {if $account.user || !$chart.code} {linkbutton shape="delete" label="Supprimer" href="!acc/charts/accounts/delete.php?id=%d"|args:$account.id} {/if} {linkbutton shape="edit" label="Modifier" href="!acc/charts/accounts/edit.php?id=%d"|args:$account.id} {/if} </td> </tr> {/foreach} </tbody> </table> {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/accounts/delete.tpl version [b79c3f0fab].
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | {include file="admin/_head.tpl" title="Supprimer un compte" current="acc/charts"} {include file="common/delete_form.tpl" legend="Supprimer ce plan comptable ?" warning="Êtes-vous sûr de vouloir supprimer le compte « %s — %s » ?"|args:$account.code,$account.label alert="Attention, le compte ne pourra pas être supprimé si des écritures y sont affectées (sauf en tant que compte analytique)." csrf_key="acc_accounts_delete_%s"|args:$account.id } {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/accounts/edit.tpl version [241af32062].
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | {include file="admin/_head.tpl" title="Modifier un compte" current="acc/charts" js=1} {form_errors} <form method="post" action="{$self_url}" data-focus="1"> {if $edit_disabled} <p class="block alert"> Il n'est pas possible de modifier le libellé, le code ou la position de ce compte car il {if $account.user}est utilisé par des écritures liées à des exercices clôturés{else}fait partie du plan comptable officiel{/if}.<br /> Pour pouvoir modifier ce compte pour l'exercice courant, il est conseillé de <a href="{$admin_url}acc/charts/?from={$account.id_chart}">créer un nouveau plan comptable</a> en y recopiant l'ancien plan comptable. </p> {/if} <fieldset> <legend>Modifier un compte</legend> {include file="acc/charts/accounts/_account_form.tpl" simple=false} </fieldset> <p class="submit"> {csrf_field key="acc_accounts_edit_%s"|args:$account.id} {button type="submit" name="edit" label="Enregistrer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/accounts/index.tpl version [d986fd5237].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | {include file="admin/_head.tpl" title="Comptes favoris" current="acc/charts"} {include file="acc/charts/accounts/_nav.tpl" current="favorites"} <table class="list"> {foreach from=$accounts_grouped item="group"} <tbody> <tr> <td colspan="3"><h2 class="ruler">{$group.label}</h2></td> <td class="actions"> {if !$chart.archived} {linkbutton label="Ajouter un compte" shape="plus" href="!acc/charts/accounts/new.php?id=%d&type=%d"|args:$chart.id,$group.type} {/if} </td> </tr> {foreach from=$group.accounts item="account"} <tr> <td class="num">{$account.code}</td> <th>{$account.label}</th> <td class="desc">{$account.description}</td> <td class="actions"> {if $session->canAccess('compta', Membres::DROIT_ADMIN) && !$chart.archived} {if $account.user || !$chart.code} {linkbutton shape="delete" label="Supprimer" href="!acc/charts/accounts/delete.php?id=%d"|args:$account.id} {/if} {linkbutton shape="edit" label="Modifier" href="!acc/charts/accounts/edit.php?id=%d"|args:$account.id} {/if} </td> </tr> {/foreach} </tbody> {/foreach} </table> {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/accounts/new.tpl version [0a5cffb23e].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | {include file="admin/_head.tpl" title="Nouveau compte" current="acc/charts" js=1} {include file="acc/charts/accounts/_nav.tpl" current="new"} {form_errors} <form method="post" action="{$self_url}" data-focus="1"> <fieldset> <legend>Créer un nouveau compte</legend> {include file="acc/charts/accounts/_account_form.tpl" simple=$simple edit_disabled=false} </fieldset> <p class="submit"> {csrf_field key="acc_accounts_new"} {button type="submit" name="save" label="Créer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/accounts/selector.tpl version [0f9678a076].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | {include file="admin/_head.tpl" title="Sélectionner un compte" body_id="popup" is_popup=true js=1} {if empty($grouped_accounts) && empty($accounts)} <p class="block alert">Le plan comptable ne comporte aucun compte de ce type. Pour afficher des comptes ici, les <a href="{$www_url}admin/acc/charts/accounts/all.php?id={$chart.id}" target="_blank">modifier dans le plan comptable</a> en sélectionnant le type de compte favori voulu.</td> {elseif isset($grouped_accounts)} {foreach from=$grouped_accounts item="group"} <h2 class="ruler">{$group.label}</h2> <table class="list"> <tbody> {foreach from=$group.accounts item="account"} <tr> <td>{$account.code}</td> <th>{$account.label}</th> <td class="desc">{$account.description}</td> <td class="actions"> <button class="icn-btn" value="{$account.id}" data-label="{$account.code} — {$account.label}" data-icon="→">Sélectionner</button> </td> </tr> {/foreach} </tbody> </table> {/foreach} {else} <h2 class="ruler"> <input type="text" placeholder="Recherche rapide" id="lookup" /> <label>{input type="checkbox" name="typed_only" value=1 default=1} N'afficher que les comptes favoris</label> </h2> <table class="accounts"> <tbody> {foreach from=$accounts item="account"} <tr class="account-level-{$account.code|strlen} t{$account.type}"> <td>{$account.code}</td> <th>{$account.label}</th> <td> {if $account.type} {icon shape="star"} <?=Entities\Accounting\Account::TYPES_NAMES[$account->type]?> {/if} </td> <td class="actions"> <button class="icn-btn" value="{$account.id}" data-label="{$account.code} — {$account.label}" data-icon="→">Sélectionner</button> </td> </tr> {/foreach} </tbody> </table> {/if} {literal} <script type="text/javascript"> RegExp.escape = function(string) { return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') }; function normalizeString(str) { return str.normalize('NFD').replace(/[\u0300-\u036f]/g, "") } var buttons = document.querySelectorAll('button'); buttons.forEach((e) => { e.onclick = () => { window.parent.g.inputListSelected(e.value, e.getAttribute('data-label')); }; }); buttons[0].focus(); var rows = document.querySelectorAll('table tr'); rows.forEach((e) => { e.classList.add('clickable'); var l = e.querySelector('td').innerText + ' ' + e.querySelector('th').innerText; e.setAttribute('data-search-label', normalizeString(l)); e.onclick = (evt) => { if (evt.target.tagName && evt.target.tagName == 'BUTTON') { return; } e.querySelector('button').click(); }; }); var q = document.getElementById('lookup'); if (q) { q.onkeyup = (e) => { var query = new RegExp(RegExp.escape(normalizeString(q.value)), 'i'); rows.forEach((elm) => { if (elm.getAttribute('data-search-label').match(query)) { elm.style.display = null; } else { elm.style.display = 'none'; } }); }; q.focus(); } var o = document.getElementById('f_typed_only_1'); if (o) { o.onchange = () => { g.toggle('.t0', !o.checked); }; g.toggle('.t0', !o.checked); } </script> {/literal} {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/delete.tpl version [664469a9cf].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | {include file="admin/_head.tpl" title="Supprimer un plan comptable" current="acc/charts"} {include file="common/delete_form.tpl" legend="Supprimer ce plan comptable ?" warning="Êtes-vous sûr de vouloir supprimer le plan comptable « %s » ?"|args:$chart.label csrf_key="acc_charts_delete_%s"|args:$chart.id } {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/edit.tpl version [4d0d3e1da3].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | {include file="admin/_head.tpl" title="Modifier un plan comptable" current="acc/charts" js=1} {form_errors} <form method="post" action="{$self_url}" data-focus="1"> <fieldset> <legend>Modifier un plan comptable</legend> <dl> {input type="text" name="label" label="Libellé" required=1 source=$chart} {input type="select" name="country" label="Pays" required=1 options=$country_list source=$chart} <dt><label for="f_archived_1">Archivage</label></dt> {input type="checkbox" name="archived" value="1" source=$chart label="Plan comptable archivé" help="Ce plan comptable ne pourra plus être modifié"} </dl> <p class="submit"> {csrf_field key="acc_charts_edit_%d"|args:$chart.id} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </fieldset> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/import.tpl version [71b9d6ba2c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | {include file="admin/_head.tpl" title="Importer un nouveau plan comptable" current="acc/charts" js=1} <nav class="tabs"> <ul> <li><a href="{$admin_url}acc/charts/">Plans comptables</a></li> <li class="current"><a href="{$admin_url}acc/charts/import.php">Importer un plan comptable</a></li> </ul> </nav> {form_errors} <form method="post" action="{$self_url}" enctype="multipart/form-data" data-focus="1"> <fieldset> <legend>Importer un plan comptable</legend> <dl> {input type="text" name="label" label="Libellé" required=1} {input type="select" name="country" label="Pays" required=1 options=$country_list default=$config.pays} {input type="file" name="file" label="Fichier CSV" accept=".csv,text/csv" required=1} <dd class="help"> Règles à suivre pour créer le fichier CSV : <ul> <li>Il est recommandé d'utiliser LibreOffice pour créer le fichier CSV</li> <li>Le fichier doit être en UTF-8</li> <li>Le séparateur doit être le point-virgule ou la virgule</li> <li>Cocher l'option <em>"Mettre en guillemets toutes les cellules du texte"</em></li> <li>Le fichier doit comporter les colonnes suivantes : <em>{$columns}</em></li> <li>Pour obtenir un exemple du format attendu, faire un export d'un plan comptable existant</li> </ul> </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="acc_charts_import"} {button type="submit" name="import" label="Importer" shape="upload" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/charts/index.tpl version [edc5b4d9b1].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | {include file="admin/_head.tpl" title="Gestion des plans comptables" current="acc/charts"} <nav class="tabs"> <ul> <li class="current"><a href="{$admin_url}acc/charts/">Plans comptables</a></li> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} <li><a href="{$admin_url}acc/charts/import.php">Importer un plan comptable</a></li> {/if} </ul> </nav> {if $_GET.msg == 'OPEN'} <p class="block alert"> Il n'existe aucun exercice ouvert. {if $session->canAccess('compta', Membres::DROIT_ADMIN)} Merci d'en <a href="{$admin_url}acc/years/new.php">créer un nouveau</a> pour pouvoir saisir des écritures. {/if} </p> {/if} {if count($list)} <table class="list"> <thead> <td>Pays</td> <th>Libellé</th> <td>Type</td> <td>Archivé</td> <td></td> </thead> <tbody> {foreach from=$list item="item"} <tr{if $item.archived} class="disabled"{/if}> <td>{$item.country|get_country_name}</td> <th><a href="{$admin_url}acc/charts/accounts/?id={$item.id}">{$item.label}</a></th> <td>{if $item.code}Officiel{else}Personnel{/if}</td> <td>{if $item.archived}<em>Archivé</em>{/if}</td> <td class="actions"> {linkbutton shape="star" label="Comptes favoris" href="!acc/charts/accounts/?id=%d"|args:$item.id} {linkbutton shape="menu" label="Tous les comptes" href="!acc/charts/accounts/all.php?id=%d"|args:$item.id} {if $session->canAccess('compta', Membres::DROIT_ADMIN)} {linkbutton shape="edit" label="Modifier" href="!acc/charts/edit.php?id=%d"|args:$item.id} {linkbutton shape="export" label="Export CSV" href="!acc/charts/export.php?id=%d"|args:$item.id} {linkbutton shape="export" label="Export tableur" href="!acc/charts/export.php?id=%d&ods"|args:$item.id} {if !$item.code && !$item.archived} {linkbutton shape="delete" label="Supprimer" href="!acc/charts/delete.php?id=%d"|args:$item.id} {/if} {/if} </td> </tr> {/foreach} </tbody> </table> {/if} {if $session->canAccess('compta', Membres::DROIT_ADMIN)} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Créer un nouveau plan comptable</legend> <dl> {input type="select_groups" name="copy" options=$charts_groupped label="Recopier depuis" required=1 default=$from} {input type="text" name="label" label="Libellé" required=1} {input type="select" name="country" label="Pays" required=1 options=$country_list default=$config.pays} </dl> <p class="submit"> {csrf_field key="acc_charts_new"} {button type="submit" name="new" label="Créer" shape="right" class="main"} </p> </fieldset> </form> {/if} {include file="admin/_foot.tpl"} |
Added src/templates/acc/index.tpl version [cd50a72c90].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | {include file="admin/_head.tpl" title="Comptabilité" current="acc"} {foreach from=$years item="year"} <section class="year-infos"> <h2 class="ruler">{$year.label} — Du {$year.start_date|date_short} au {$year.end_date|date_short}</h2> <nav class="tabs"> <aside> {linkbutton shape="search" href="!acc/search.php?year=%d"|args:$year.id label="Recherche"} {if $session->canAccess('compta', Membres::DROIT_ADMIN)} {linkbutton shape="upload" href="!acc/years/import.php?year=%d"|args:$year.id label="Import & export"} {/if} </aside> <ul> <li><a href="{$admin_url}acc/reports/graphs.php?year={$year.id}">Graphiques</a></li> <li><a href="{$admin_url}acc/reports/trial_balance.php?year={$year.id}">Balance générale</a></li> <li><a href="{$admin_url}acc/reports/journal.php?year={$year.id}">Journal général</a></li> <li><a href="{$admin_url}acc/reports/ledger.php?year={$year.id}">Grand livre</a></li> <li><a href="{$admin_url}acc/reports/statement.php?year={$year.id}">Compte de résultat</a></li> <li><a href="{$admin_url}acc/reports/balance_sheet.php?year={$year.id}">Bilan</a></li> </ul> </nav> {if $year.has_transactions} <section class="graphs"> {foreach from=$graphs key="url" item="label"} <figure> <img src="{$url|args:'year='|cat:$year.id}" alt="" /> <figcaption>{$label}</figcaption> </figure> {/foreach} </section> {/if} </section> {foreachelse} <p class="block alert"> Il n'y a aucun exercice ouvert en cours.<br /> {linkbutton label="Ouvrir un nouvel exercice" shape="plus" href="!acc/years/new.php"} </p> {/foreach} {include file="admin/_foot.tpl"} |
Added src/templates/acc/reports/_header.tpl version [c9b9d26764].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <div class="year-header"> <nav class="tabs noprint"> <ul> {if isset($analytical)} <li><strong><a href="{$admin_url}acc/reports/projects.php">Projets</a></strong></li> {/if} <li{if $current == "graphs"} class="current"{/if}><a href="{$admin_url}acc/reports/graphs.php?{$criterias_query}">Graphiques</a></li> <li{if $current == "trial_balance"} class="current"{/if}><a href="{$admin_url}acc/reports/trial_balance.php?{$criterias_query}">Balance générale</a></li> <li{if $current == "journal"} class="current"{/if}><a href="{$admin_url}acc/reports/journal.php?{$criterias_query}">Journal général</a></li> <li{if $current == "ledger"} class="current"{/if}><a href="{$admin_url}acc/reports/ledger.php?{$criterias_query}">Grand livre</a></li> <li{if $current == "statement"} class="current"{/if}><a href="{$admin_url}acc/reports/statement.php?{$criterias_query}">Compte de résultat</a></li> <li{if $current == "balance_sheet"} class="current"{/if}><a href="{$admin_url}acc/reports/balance_sheet.php?{$criterias_query}">Bilan</a></li> </ul> </nav> <h2>{$config.nom_asso}</h2> {if isset($analytical)} <h3>Projet : {$analytical.label}</h3> {/if} {if isset($year)} <p>Exercice comptable {if $year.closed}clôturé{else}en cours{/if} du {$year.start_date|date_short} au {$year.end_date|date_short}, généré le {$close_date|date_short}</p> {/if} <p class="noprint print-btn"> <button onclick="window.print(); return false;" class="icn-btn" data-icon="⎙">Imprimer</button> </p> </div> |
Added src/templates/acc/reports/_journal.tpl version [37e07b0e8b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <table class="list multi"> <thead> <tr> <td>Réf.</td> <td>Date</td> <th>Libellé</th> <td>Comptes</td> <td class="money">Débit</td> <td class="money">Crédit</td> <td>Libellé ligne</td> <td>Réf. ligne</td> </tr> </thead> {foreach from=$journal item="transaction"} <tbody> <tr> <td rowspan="{$transaction.lines|count}" class="num"><a href="{$admin_url}acc/transactions/details.php?id={$transaction.id}">{if $transaction.reference}{$transaction.reference}{else}#{$transaction.id}{/if}</a></td> <td rowspan="{$transaction.lines|count}">{$transaction.date|date_short}</td> <th rowspan="{$transaction.lines|count}">{$transaction.label}</th> {foreach from=$transaction.lines item="line"} <td>{$line.account_code} - {$line.account_label}</td> <td class="money">{$line.debit|raw|html_money}</td> <td class="money">{$line.credit|raw|html_money}</td> <td>{$line.label}</td> <td>{$line.reference}</td> </tr> <tr> {/foreach} </tr> </tbody> {/foreach} </table> |
Added src/templates/acc/reports/_statement_table.tpl version [59dd236cd8].
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <table class="list"> {if !empty($caption)} <caption><h3>{$caption}</h3></caption> {/if} <tbody> {foreach from=$accounts item="account"} <tr class="compte"> <td class="num"> {if !empty($year)}<a href="{$admin_url}acc/accounts/journal.php?id={$account.id}&year={$year.id}">{$account.code}</a> {else}{$account.code} {/if} </td> <th>{$account.label}</th> <td class="money">{$account.sum|raw|html_money}</td> </tr> {/foreach} </tbody> </table> |
Added src/templates/acc/reports/balance_sheet.tpl version [0249d23d75].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | {include file="admin/_head.tpl" title="Bilan" current="acc/years"} {include file="acc/reports/_header.tpl" current="balance_sheet"} <table class="statement"> <colgroup> <col width="50%" /> <col width="50%" /> </colgroup> <tbody> <tr> <td> {include file="acc/reports/_statement_table.tpl" accounts=$asset caption="Actif"} </td> <td> {include file="acc/reports/_statement_table.tpl" accounts=$liability caption="Passif"} </td> </tr> </tbody> <tfoot> <tr> <td> <table> <tfoot> <tr> <th>Total actif</th> <td class="money">{$asset_sum|raw|html_money:false}</td> </tr> </tfoot> </table> </td> <td> <table> <tfoot> <tr> <th>Total passif</th> <td class="money">{$liability_sum|raw|html_money:false}</td> </tr> </tfoot> </table> </td> </tr> </tfoot> </table> <p class="help">Toutes les écritures sont libellées en {$config.monnaie}.</p> {include file="admin/_foot.tpl"} |
Added src/templates/acc/reports/graphs.tpl version [526c29e562].
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | {include file="admin/_head.tpl" title="Graphiques" current="acc"} {include file="acc/reports/_header.tpl" current="graphs"} <section class="year-infos"> <section class="graphs"> {foreach from=$graphs key="url" item="label"} <figure> <img src="{$url|args:$criterias_query}" alt="" /> <figcaption>{$label}</figcaption> </figure> {/foreach} </section> </section> {include file="admin/_foot.tpl"} |
Added src/templates/acc/reports/journal.tpl version [5b585d401b].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | {include file="admin/_head.tpl" title="Journal général" current="acc/years"} {include file="acc/reports/_header.tpl" current="journal"} {include file="acc/reports/_journal.tpl"} <p class="help">Toutes les écritures sont libellées en {$config.monnaie}.</p> {include file="admin/_foot.tpl"} |
Added src/templates/acc/reports/ledger.tpl version [58b1dc5251].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | {include file="admin/_head.tpl" title="Grand livre" current="acc/years"} {include file="acc/reports/_header.tpl" current="ledger"} <div class="year-header noprint"> <button type="button" data-icon="↓" class="icn-btn" id="open_details">Déplier tous les comptes</button> <button type="button" data-icon="↑" class="icn-btn" id="close_details">Replier tous les comptes</button> </div> {foreach from=$ledger item="account"} <details open="open"> <summary><h2 class="ruler"><a href="{$admin_url}acc/accounts/journal.php?id={$account.id}&year={$account.id_year}">{$account.code} — {$account.label}</a></h2></summary> <table class="list"> <colgroup> <col width="5%" /> <col width="5%" /> <col width="10%" /> <col width="50%" /> <col width="10%" /> <col width="10%" /> <col width="10%" /> </colgroup> <thead> <tr> <td>Réf.</td> <td>Réf. ligne</td> <td>Date</td> <th>Intitulé</th> <td class="money">Débit</td> <td class="money">Crédit</td> <td class="money">Solde</td> </tr> </thead> <tbody> {foreach from=$account.lines item="line"} <tr> <td class="num"><a href="{$admin_url}acc/transactions/details.php?id={$line.id}">{if $line.reference}{$line.reference}{else}#{$line.id}{/if}</a></td> <td class="num">{$line.line_reference}</td> <td>{$line.date|date_short}</td> <th>{$line.label}{if $line.line_label} <em>({$line.line_label})</em>{/if}</th> <td class="money">{$line.debit|raw|html_money}</td> <td class="money">{$line.credit|raw|html_money}</td> <td class="money">{$line.running_sum|raw|html_money:false}</td> </tr> {/foreach} </tbody> <tfoot> <tr> <td colspan="3"></td> <th>Solde final</th> <td class="money">{$account.debit|raw|html_money}</td> <td class="money">{$account.credit|raw|html_money}</td> <td class="money">{$account.sum|raw|html_money:false}</td> </tr> </tfoot> </table> </details> {if isset($account->all_debit)} <table class="list"> <colgroup> <col width="70%" /> <col width="10%" /> <col width="10%" /> <col width="10%" /> </colgroup> <tfoot> <tr> <td><strong>Totaux</strong></td> <td class="money">{$account.all_debit|raw|html_money:false}</td> <td class="money">{$account.all_credit|raw|html_money:false}</td> <td></td> </tr> </tfoot> </table> {/if} {/foreach} {literal} <script type="text/javascript"> document.querySelector('#open_details').onclick = () => { document.querySelectorAll('details').forEach((e) => { e.setAttribute('open', 'open'); }); }; document.querySelector('#close_details').onclick = () => { document.querySelectorAll('details').forEach((e) => { e.removeAttribute('open'); }); }; </script> {/literal} <p class="help">Toutes les écritures sont libellées en {$config.monnaie}.</p> {include file="admin/_foot.tpl"} |
Added src/templates/acc/reports/projects.tpl version [c5b8848ec2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | {include file="admin/_head.tpl" title="Projets" current="acc/years"} <nav class="tabs"> {if CURRENT_YEAR_ID} <aside> {linkbutton label="Créer un nouveau compte de projet" href="!acc/charts/accounts/new.php?id=%d&type=%d"|args:$current_year.id_chart,$analytical_type shape="plus"} </aside> {/if} <ul> <li><a href="{$admin_url}acc/years/">Exercices</a></li> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} <li><a href="{$admin_url}acc/years/new.php">Nouvel exercice</a></li> {/if} <li class="current"><a href="{$admin_url}acc/reports/projects.php">Projets <em>(compta analytique)</em></a></li> </ul> <ul class="sub"> <li{if !$by_year} class="current"{/if}><a href="{$self_url_no_qs}">Par projet</a></li> <li{if $by_year} class="current"{/if}><a href="{$self_url_no_qs}?by_year=1">Par exercice</a></li> </ul> </nav> {if !empty($list)} <table class="list"> <thead> <tr> <td>Année</td> <td></td> <td class="money">Débits</td> <td class="money">Crédits</td> <td class="money">Solde</td> </tr> </thead> {foreach from=$list item="parent"} <tbody> <tr> <th colspan="5"> <h2 class="ruler">{$parent.label}</h2> </th> </tr> {foreach from=$parent.items item="item"} <tr> <th>{$item.label}</th> <td> <span class="noprint"> <a href="{$admin_url}acc/reports/graphs.php?analytical={$item.id_account}&year={$item.id_year}">Graphiques</a> | <a href="{$admin_url}acc/reports/trial_balance.php?analytical={$item.id_account}&year={$item.id_year}">Balance générale</a> | <a href="{$admin_url}acc/reports/journal.php?analytical={$item.id_account}&year={$item.id_year}">Journal général</a> | <a href="{$admin_url}acc/reports/ledger.php?analytical={$item.id_account}&year={$item.id_year}">Grand livre</a> | <a href="{$admin_url}acc/reports/statement.php?analytical={$item.id_account}&year={$item.id_year}">Compte de résultat</a> | <a href="{$admin_url}acc/reports/balance_sheet.php?analytical={$item.id_account}&year={$item.id_year}">Bilan</a> </span> </td> <td class="money">{$item.debit|raw|html_money}</td> <td class="money">{$item.credit|raw|html_money}</td> <td class="money">{$item.sum|raw|html_money:false}</td> </tr> {/foreach} </tbody> {/foreach} </table> {else} <p class="block alert"> Il n'y a pas de projet visible en cours. {if $current_year && !$analytical_accounts_count} {linkbutton label="Créer un nouveau compte de projet" href="!acc/charts/accounts/new.php?id=%d&type=%d"|args:$current_year.id_chart,$analytical_type shape="plus"} {else} Le solde des projets apparaîtra quand des écritures seront affectées à ces projets. {/if} </p> {/if} {include file="admin/_foot.tpl"} |
Added src/templates/acc/reports/statement.tpl version [8f97001d6f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | {include file="admin/_head.tpl" title="Compte de résultat" current="acc/years"} {include file="acc/reports/_header.tpl" current="statement"} <table class="statement"> <colgroup> <col width="50%" /> <col width="50%" /> </colgroup> <tbody> <tr> <td> {include file="acc/reports/_statement_table.tpl" accounts=$expense caption="Charges"} </td> <td> {include file="acc/reports/_statement_table.tpl" accounts=$revenue caption="Produits"} </td> </tr> </tbody> <tfoot> <tr> <td> <table> <tfoot> <tr> <th>Total charges</th> <td class="money">{$expense_sum|raw|html_money:false}</td> </tr> </tfoot> </table> </td> <td> <table> <tfoot> <tr> <th>Total produits</th> <td class="money">{$revenue_sum|raw|html_money:false}</td> </tr> </tfoot> </table> </td> </tr> {if $result} <tr> <td> {if ($result < 0)} <table> <tfoot> <tr> <th>Résultat (perte)</th> <td class="money">{$result|raw|html_money:false}</td> </tr> </tfoot> </table> {/if} </td> <td> {if ($result >= 0)} <table> <tfoot> <tr> <th>Résultat (excédent)</th> <td class="money">{$result|raw|html_money:false}</td> </tr> </tfoot> </table> {/if} </td> </tr> {/if} </tfoot> </table> <p class="help">Toutes les écritures sont libellées en {$config.monnaie}.</p> {include file="admin/_foot.tpl"} |
Added src/templates/acc/reports/trial_balance.tpl version [f08d97e86e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | {include file="admin/_head.tpl" title="Balance générale" current="acc/years"} {include file="acc/reports/_header.tpl" current="trial_balance"} <table class="list"> <thead> <tr> <td>Numéro</td> <th>Compte</th> <td class="money">Total des débits</td> <td class="money">Total des crédits</td> <td class="money">Solde débiteur</td> <td class="money">Solde créditeur</td> </tr> </thead> <tbody> {foreach from=$balance item="account"} <tr> <td class="num"> {if !empty($year)}<a href="{$admin_url}acc/accounts/journal.php?id={$account.id}&year={$year.id}">{$account.code}</a> {else}{$account.code} {/if} </td> <th>{$account.label}</th> <td class="money">{$account.debit|raw|html_money}</td> <td class="money">{$account.credit|raw|html_money}</td> <td class="money">{if $account.sum < 0}{$account.sum|abs|escape|html_money}{/if}</td> <td class="money">{if $account.sum > 0}{$account.sum|abs|escape|html_money}{/if}</td> </tr> {/foreach} </tbody> </table> <p class="help">Toutes les écritures sont libellées en {$config.monnaie}.</p> {include file="admin/_foot.tpl"} |
Added src/templates/acc/search.tpl version [3ea0dd29df].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | {include file="admin/_head.tpl" title="Recherche" current="acc" js=1 custom_js=['query_builder.min.js']} <nav class="tabs"> <ul> <li class="current"><a href="{$self_url}">Recherche</a></li> <li><a href="saved_searches.php">Recherches enregistrées</a></li> </ul> </nav> {include file="common/search/advanced.tpl" action_url=$self_url} {if !empty($result)} {*if $session->canAccess('compta', Membres::DROIT_ECRITURE)} <form method="post" action="{$admin_url}membres/action.php" class="memberList"> {/if*} <p class="help">{$result|count} écritures trouvées pour cette recherche.</p> <table class="list search"> <thead> <tr> {*if $session->canAccess('membres', Membres::DROIT_ADMIN)}<td class="check"><input type="checkbox" value="Tout cocher / décocher" /></td>{/if*} {foreach from=$result_header item="label"} <td>{$label}</td> {/foreach} <td></td> </tr> </thead> <tbody> {foreach from=$result item="row"} <tr> {*if $session->canAccess('membres', Membres::DROIT_ADMIN)}<td class="check"><input type="checkbox" name="selected[]" value="{$row.id}" /></td>{/if*} {foreach from=$row key="key" item="value"} {if $key == 'id'} <td class="num"> <a href="{$admin_url}acc/transactions/details.php?id={$value}">{$value}</a> </td> {else} <td> {if $key == 'credit' || $key == 'debit'} {$value|raw|html_money:false} {elseif null == $value} <em>(nul)</em> {else} {$value} {/if} </td> {/if} {/foreach} <td class="actions"> {linkbutton shape="search" label="Détails" href="!acc/transactions/details.php?id=%d"|args:$row.id} </td> </tr> {/foreach} </tbody> {*if $session->canAccess('membres', Membres::DROIT_ADMIN)} {include file="admin/membres/_list_actions.tpl" colspan=count($result_header)+1} {/if*} </table> {*if $session->canAccess('membres', Membres::DROIT_ECRITURE)} </form> {/if*} {elseif $result !== null} <p class="block alert"> Aucun résultat trouvé. </p> </form> {/if} {include file="admin/_foot.tpl"} |
Added src/templates/acc/transactions/_lines_form.tpl version [25878c61c0].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <?php assert(is_array($lines)); assert(is_array($analytical_accounts)); assert(!isset($lines_accounts) || is_array($lines_accounts)); ?> <table class="list transaction-lines"> <thead> <tr> <td>Compte</td> <td>Débit</td> <td>Crédit</td> <td>Réf. ligne</td> <td>Libellé ligne</td> {if count($analytical_accounts) > 1} <td>Projet</td> {/if} <td></td> </tr> </thead> <tbody> {foreach from=$lines key="k" item="line"} <tr> <td> {input type="list" target="acc/charts/accounts/selector.php?chart=%d"|args:$chart_id name="lines[account][]" default=$line.account} </td> <td class="money">{input type="money" name="lines[debit][]" default=$line.debit size=5}</td> <td class="money">{input type="money" name="lines[credit][]" default=$line.credit size=5}</td> <td>{input type="text" name="lines[reference][]" default=$line.reference size=10}</td> <td>{input type="text" name="lines[label][]" default=$line.label}</td> {if count($analytical_accounts) > 1} <td>{input default=$line.id_analytical type="select" name="lines[id_analytical][]" options=$analytical_accounts}</td> {/if} <td>{button label="Enlever" title="Enlever la ligne" shape="minus" min="2" name="remove_line"}</td> </tr> {/foreach} </tbody> <tfoot> <tr> <th>Total</th> <td class="money">{input type="money" name="debit_total" readonly="readonly" tabindex="-1" }</td> <td class="money">{input type="money" name="credit_total" readonly="readonly" tabindex="-1" }</td> <td colspan="{if count($analytical_accounts) > 1}3{else}2{/if}" id="lines_message"></td> <td>{button label="Ajouter" title="Ajouter une ligne" shape="plus"}</td> </tr> </tfoot> </table> |
Added src/templates/acc/transactions/actions_analytical.tpl version [326812a369].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | {include file="admin/_head.tpl" title="Ajouter/supprimer des écritures à un projet" current="acc/accounts"} {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Affecter {$count} écritures sélectionnées à un projet</legend> <dl> <dd> {input type="select" name="id_analytical" options=$analytical_accounts label="Projet à utiliser" help="Pour retirer les écritures de leur projet actuellement affecté, sélectionner simplement « Aucun projet »."} </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="acc_actions"} <input type="hidden" name="action" value="add" /> {button type="submit" name="change_analytical" label="Modifier les écritures" shape="right" class="main"} {if isset($extra)} {foreach from=$extra key="key" item="value"} {if is_array($value)} {foreach from=$value key="subkey" item="subvalue"} <input type="hidden" name="{$key}[{$subkey}]" value="{$subvalue}" /> {/foreach} {else} <input type="hidden" name="{$key}" value="{$value}" /> {/if} {/foreach} {/if} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/transactions/actions_delete.tpl version [94d2ed495a].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | {include file="admin/_head.tpl" title="Supprimer %d écritures"|args:$count current="acc"} {include file="common/delete_form.tpl" legend="Supprimer ces écritures ?" warning="Êtes-vous sûr de vouloir supprimer %d écritures ?"|args:$count confirm="Cocher cette case pour confirmer la suppression" csrf_key=$csrf_key extra=$extra } {include file="admin/_foot.tpl"} |
Added src/templates/acc/transactions/creator.tpl version [75918e5101].
> > > > > | 1 2 3 4 5 | {include file="admin/_head.tpl" title="Écritures crées par %s"|args:$transaction_creator.identite current="acc/accounts"} {include file="acc/reports/_journal.tpl"} {include file="admin/_foot.tpl"} |
Added src/templates/acc/transactions/delete.tpl version [a0b4d20f5c].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | {include file="admin/_head.tpl" title="Supprimer l'écriture n°%d"|args:$transaction.id current="acc"} {include file="common/delete_form.tpl" legend="Supprimer cette écriture ?" warning="Êtes-vous sûr de vouloir supprimer l'écriture n°%d « %s » ?"|args:$transaction.id,$transaction.label csrf_key="acc_delete_%s"|args:$transaction.id } {include file="admin/_foot.tpl"} |
Added src/templates/acc/transactions/details.tpl version [f76172b6ec].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | {include file="admin/_head.tpl" title="Écriture n°%d"|args:$transaction.id current="acc"} {if $session->canAccess('compta', Membres::DROIT_ADMIN) && !$transaction->validated && !$tr_year->closed} <nav class="tabs"> <ul> <li><a href="edit.php?id={$transaction.id}">Modifier cette écriture</a></li> <li><a href="delete.php?id={$transaction.id}">Supprimer cette écriture</a></li> </ul> </nav> {/if} {if $session->canAccess('compta', Membres::DROIT_ECRITURE) && $transaction.status & $transaction::STATUS_WAITING} <div class="block alert"> {if $transaction.type == $transaction::TYPE_DEBT} <h3>Dette en attente</h3> {linkbutton shape="check" label="Enregistrer le règlement de cette dette" href="!acc/transactions/new.php?payoff_for=%d"|args:$transaction.id} {else} <h3>Créance en attente</h3> {linkbutton shape="export" label="Enregistrer le règlement de cette créance" href="!acc/transactions/new.php?payoff_for=%d"|args:$transaction.id} {/if} </div> {/if} <dl class="describe"> {if $transaction.id_related} <dt>Écriture liée à</dt> <dd><a href="{$admin_url}acc/transactions/details.php?id={$transaction.id_related}">#{$transaction.id_related}</a> {if $transaction.type == $transaction::TYPE_DEBT || $transaction.type == $transaction::TYPE_CREDIT}(en règlement de){/if} </dd> {/if} <dt>Libellé</dt> <dd><h2>{$transaction.label}</h2></dd> <dt>Date</dt> <dd>{$transaction.date|date_fr:'l j F Y (d/m/Y)'}</dd> <dt>Numéro pièce comptable</dt> <dd>{if trim($transaction.reference)}{$transaction.reference}{else}-{/if}</dd> <dt>Exercice</dt> <dd> <a href="{$admin_url}acc/reports/ledger.php?year={$transaction.id_year}">{$tr_year.label}</a> | Du {$tr_year.start_date|date_short} au {$tr_year.end_date|date_short} | <strong>{if $tr_year.closed}Clôturé{else}En cours{/if}</strong> </dd> <dt>Écriture créée par</dt> <dd> {if $transaction.id_creator} {if $session->canAccess('compta', Membres::DROIT_ACCES)} <a href="{$admin_url}membres/fiche.php?id={$transaction.id_creator}">{$creator_name}</a> {else} {$creator_name} {/if} {else} <em>membre supprimé</em> {/if} </dd> <dt>Écriture liée à</dt> {if empty($related_users)} <dd><em>Aucun membre n'est lié à cette écriture.</em></dd> {else} {foreach from=$related_users item="u"} <dd> <a href="{$admin_url}membres/fiche.php?id={$u.id}">{$u.identity}</a> {if $u.id_service_user}— en règlement d'une <a href="{$admin_url}services/user.php?id={$u.id}&only={$u.id_service_user}">activité</a>{/if} </dd> {/foreach} {/if} <dt>Remarques</dt> <dd>{if trim($transaction.notes)}{$transaction.notes|escape|nl2br}{else}-{/if}</dd> <dt>Fichiers joints</dt> {foreach from=$files item="file"} <dd> <aside class="file"> <a target="_blank" href="{$file.url}">{$file.nom}</a> <small>({$file.type}, {$file.taille|format_bytes})</small> {linkbutton shape="download" href=$file.url target="_blank" label="Télécharger"} {linkbutton shape="delete" href="!acc/transactions/delete_file.php?id=%d&from=%d"|args:$file.id,$transaction.id label="Supprimer"} </aside> </dd> {foreachelse} <dd>-</dd> {/foreach} </dl> <table class="list"> <thead> <tr> <td class="num">N° compte</td> <th>Compte</th> <td class="money">Débit</td> <td class="money">Crédit</td> <td>Libellé</td> <td>Référence</td> <td>Projet</td> </tr> </thead> <tbody> {foreach from=$transaction->getLinesWithAccounts() item="line"} <tr> <td class="num"><a href="{$admin_url}acc/accounts/journal.php?id={$line.id_account}&year={$transaction.id_year}">{$line.account_code}</a></td> <td>{$line.account_name}</td> <td class="money">{if $line.debit}{$line.debit|escape|html_money}{/if}</td> <td class="money">{if $line.credit}{$line.credit|escape|html_money}{/if}</td> <td>{$line.label}</td> <td>{$line.reference}</td> <td> {if $line.id_analytical} <a href="{$admin_url}acc/reports/statement.php?analytical={$line.id_analytical}">{$line.analytical_name}</a> {/if} </td> </tr> {/foreach} </tbody> </table> {include file="admin/_foot.tpl"} |
Added src/templates/acc/transactions/edit.tpl version [61ebad2980].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | {include file="admin/_head.tpl" title="Modification d'une écriture" current="acc/simple" js=1} <form method="post" action="{$self_url}" enctype="multipart/form-data" data-focus="#f_date"> {form_errors} <fieldset> <legend>Type d'écriture</legend> <dl> {foreach from=$types_details item="type"} <dd class="radio-btn"> {input type="radio" name="type" value=$type.id source=$transaction label=null} <label for="f_type_{$type.id}"> <div> <h3>{$type.label}</h3> {if !empty($type.help)} <p>{$type.help}</p> {/if} </div> </label> </dd> {/foreach} </dl> </fieldset> <fieldset> <legend>Informations</legend> <dl> {input type="date" name="date" label="Date" required=1 source=$transaction} {input type="text" name="label" label="Libellé" required=1 source=$transaction} {input type="text" name="reference" label="Numéro de pièce comptable" help="Numéro de facture, de note de frais, etc."} </dl> <dl data-types="all-but-advanced"> {input type="money" name="amount" label="Montant" required=1 default=$amount} </dl> </fieldset> {foreach from=$types_details item="type"} <fieldset data-types="t{$type.id}"> <legend>{$type.label}</legend> {if $type.id == $transaction::TYPE_ADVANCED} {* Saisie avancée *} {include file="acc/transactions/_lines_form.tpl" chart_id=$current_year.id_chart} {else} <dl> {foreach from=$type.accounts key="key" item="account"} <?php $selected = $types_accounts[$key] ?? null; ?> {input type="list" target="acc/charts/accounts/selector.php?targets=%s&chart=%d"|args:$account.targets_string,$chart_id name="account_%d_%d"|args:$type.id,$key label=$account.label required=1 default=$selected} {/foreach} </dl> {/if} </fieldset> {/foreach} <fieldset> <legend>Détails facultatifs</legend> <dl data-types="t{$transaction::TYPE_REVENUE} t{$transaction::TYPE_EXPENSE} t{$transaction::TYPE_TRANSFER}"> {input type="text" name="payment_reference" label="Référence de paiement" help="Numéro de chèque, numéro de transaction CB, etc." source=$transaction} </dl> <dl> {input type="list" multiple=true name="users" label="Membres associés" target="membres/selector.php" default=$linked_users} {input type="textarea" name="notes" label="Remarques" rows=4 cols=30 source=$transaction} {input type="file" name="file" label="Ajouter un fichier joint"} </dl> <dl data-types="all-but-advanced"> {if count($analytical_accounts) > 1} {input type="select" name="id_analytical" label="Projet (compte analytique)" options=$analytical_accounts} {/if} </dl> </fieldset> <p class="submit"> {csrf_field key="acc_edit_%d"|args:$transaction.id} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> {literal} <script type="text/javascript" defer="defer" async="async"> g.script('scripts/accounting.js', () => { initTransactionForm(); }); </script> {/literal} {include file="admin/_foot.tpl"} |
Added src/templates/acc/transactions/new.tpl version [0ea620ce9f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | {include file="admin/_head.tpl" title="Saisie d'une écriture" current="acc/new" js=1} {include file="acc/_year_select.tpl"} <form method="post" action="{$self_url}" enctype="multipart/form-data" data-focus="1"> {form_errors} {if $ok} <p class="block confirm"> L'écriture numéro <a href="details.php?id={$ok}">{$ok}</a> a été ajoutée. (<a href="details.php?id={$ok}">Voir l'écriture</a>) </p> {/if} {if $payoff_for} <input type="hidden" name="type" value="{$transaction.type}" /> <input type="hidden" name="payoff_for" value="{$payoff_for.id}" /> <input type="hidden" name="{$payoff_for.form_account_name}[{$payoff_for.id_account}]" value="-" /> <fieldset> <legend>{if $payoff_for.type == $transaction::TYPE_DEBT}Règlement de dette{else}Règlement de créance{/if}</legend> <dl> <dt>Écriture d'origine</dt> <dd><a class="num" href="{$admin_url}acc/transactions/details.php?id={$payoff_for.id}">#{$payoff_for.id}</a></dd> {input type="list" target="acc/charts/accounts/selector.php?targets=%s&chart=%d"|args:$payoff_targets,$chart_id name=$payoff_for.form_target_name label="Compte de règlement" required=1} </dl> </fieldset> {else} <fieldset> <legend>Type d'écriture</legend> <dl> {foreach from=$types_details item="type"} <dd class="radio-btn"> {input type="radio" name="type" value=$type.id source=$transaction label=null} <label for="f_type_{$type.id}"> <div> <h3>{$type.label}</h3> {if !empty($type.help)} <p>{$type.help}</p> {/if} </div> </label> </dd> {/foreach} </dl> </fieldset> {/if} <fieldset> <legend>Informations</legend> <dl> {input type="date" name="date" default=$date label="Date" required=1 source=$transaction} {input type="text" name="label" label="Libellé" required=1 source=$transaction} {input type="text" name="reference" label="Numéro de pièce comptable" help="Numéro de facture, de note de frais, etc."} </dl> <dl data-types="all-but-advanced"> {input type="money" name="amount" label="Montant" required=1 default=$amount} </dl> </fieldset> {if !$payoff_for} {foreach from=$types_details item="type"} <fieldset data-types="t{$type.id}"> <legend>{$type.label}</legend> {if $type.id == $transaction::TYPE_ADVANCED} {* Saisie avancée *} {include file="acc/transactions/_lines_form.tpl" chart_id=$current_year.id_chart} {else} <dl> {foreach from=$type.accounts key="key" item="account"} {input type="list" target="acc/charts/accounts/selector.php?targets=%s&chart=%d"|args:$account.targets_string,$chart_id name="account_%d_%d"|args:$type.id,$key label=$account.label required=1} {/foreach} </dl> {/if} </fieldset> {/foreach} {/if} <fieldset> <legend>Détails facultatifs</legend> <dl data-types="t{$transaction::TYPE_REVENUE} t{$transaction::TYPE_EXPENSE} t{$transaction::TYPE_TRANSFER}"> {input type="text" name="payment_reference" label="Référence de paiement" help="Numéro de chèque, numéro de transaction CB, etc." source=$transaction} </dl> <dl> {input type="list" multiple=true name="users" label="Membres associés" target="membres/selector.php"} {input type="textarea" name="notes" label="Remarques" rows=4 cols=30} {input type="file" name="file" label="Fichier joint"} </dl> <dl data-types="all-but-advanced"> {if count($analytical_accounts) > 1} {input type="select" name="id_analytical" label="Projet (compte analytique)" options=$analytical_accounts} {/if} </dl> </fieldset> <p class="submit"> {csrf_field key="acc_transaction_new"} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> <script type="text/javascript" defer="defer" async="async"> let is_new = {if $payoff_for}false{else}true{/if}; {literal} g.script('scripts/accounting.js', () => { initTransactionForm(is_new && !$('.block').length); }); </script> {/literal} {include file="admin/_foot.tpl"} |
Added src/templates/acc/transactions/service_user.tpl version [a8761edf6b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | {include file="admin/_head.tpl" title="Écritures liées à une inscription" current="acc/accounts"} <p> {linkbutton href="!membres/fiche.php?id=%d"|args:$user_id label="Retour à la fiche membre" shape="user"} </p> {include file="acc/reports/_journal.tpl"} <h2 class="ruler">Solde des comptes</h2> <table class="list"> <thead> <tr> <td>Numéro</td> <th>Compte</th> <td class="money">Solde débiteur</td> <td class="money">Solde créditeur</td> </tr> </thead> <tbody> {foreach from=$balance item="account"} <tr> <td class="num"><a href="{$admin_url}acc/accounts/journal.php?id={$account.id}">{$account.code}</a></td> <th>{$account.label}</th> <td class="money">{if $account.sum < 0}{$account.sum|raw|html_money}{/if}</td> <td class="money">{if $account.sum > 0}{$account.sum|raw|html_money}{/if}</td> </tr> {/foreach} </tbody> </table> {include file="admin/_foot.tpl"} |
Added src/templates/acc/transactions/user.tpl version [fca819aadf].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | {include file="admin/_head.tpl" title="Écritures liées à %s"|args:$transaction_user.identite current="acc/accounts"} <p> {linkbutton href="!membres/fiche.php?id=%d"|args:$transaction_user.id label="Retour à la fiche membre" shape="user"} </p> {include file="acc/reports/_journal.tpl"} <h2 class="ruler">Solde des comptes</h2> <form method="get" action="{$self_url_no_qs}"> <fieldset> <legend>Exercice</legend> <dl> {input type="select" name="year" options=$years onchange="this.form.submit();" default=$year} </dl> <input type="hidden" name="id" value="{$transaction_user.id}" /> <noscript> <input type="submit" value="OK" /> </noscript> </fieldset> </form> <p class="block help">Cette liste représente le solde des comptes uniquement pour les écritures liées à ce membre.</p> <table class="list"> <thead> <tr> <td>Numéro</td> <th>Compte</th> <td class="money">Solde débiteur</td> <td class="money">Solde créditeur</td> </tr> </thead> <tbody> {foreach from=$balance item="account"} <tr> <td class="num"><a href="{$admin_url}acc/accounts/journal.php?id={$account.id}">{$account.code}</a></td> <th>{$account.label}</th> <td class="money">{if $account.sum < 0}{$account.sum|raw|html_money}{/if}</td> <td class="money">{if $account.sum > 0}{$account.sum|raw|html_money}{/if}</td> </tr> {/foreach} </tbody> </table> {include file="admin/_foot.tpl"} |
Added src/templates/acc/years/balance.tpl version [4fd7ac96b2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | {include file="admin/_head.tpl" title="Balance d'ouverture" current="acc/years" js=1} {form_errors} {if $year->countTransactions()} <p class="block alert"> <strong>Attention !</strong> Cet exercice a déjà des écritures, peut-être avez-vous déjà renseigné la balance d'ouverture ? </p> {/if} <form method="post" action="{$self_url}"> <fieldset> <legend>Exercice : « {$year.label} » du {$year.start_date|date_short} au {$year.end_date|date_short}</legend> {if null === $previous_year} <dl> <dt><label for="f_from_year">Reprendre les soldes de fermeture d'un exercice clôturé</label></dt> <dd> <select id="f_from_year" name="from_year"> <option value="">-- Aucun</option> {foreach from=$years item="year"} <option value="{$year.id}">{$year.label} — {$year.start_date|date_short} au {$year.end_date|date_short}</option> {/foreach} </select> </dd> </dl> {elseif 0 === $previous_year} <p class="alert block">Il n'existe aucun exercice clôturé, il n'est donc pas possible de reprendre une balance de clôture.</p> {else} <p class="help"> Renseigner ici les soldes d'ouverture (débiteur ou créditeur) des comptes. </p> <table class="list transaction-lines"> <thead> <tr> {if $chart_change} <td>Ancien compte</td> <th>Nouveau compte</th> {else} <th>Compte</th> {/if} <td>Débit</td> <td>Crédit</td> <td></td> </tr> </thead> <tbody> {foreach from=$lines key="k" item="line"} <tr> {if $chart_change} <td>{$line.code} — {$line.label}</td> {/if} <th> {input type="list" target="acc/charts/accounts/selector.php?chart=%d"|args:$year.id_chart name="lines[account][]" default=$line.account_selected} </th> <td>{input type="money" name="lines[debit][]" default=$line.debit size=5}</td> <td>{input type="money" name="lines[credit][]" default=$line.credit size=5}</td> <td>{button label="Enlever la ligne" shape="minus" min="1" name="remove_line"}</td> </tr> {/foreach} </tbody> <tfoot> <tr> <th>Total</th> {if $chart_change} <td></td> {/if} <td>{input type="money" name="debit_total" readonly="readonly" tabindex="-1" }</td> <td>{input type="money" name="credit_total" readonly="readonly" tabindex="-1" }</td> <td>{button label="Ajouter une ligne" shape="plus"}</td> </tr> </tfoot> </table> {/if} </fieldset> <p class="submit"> {if null === $previous_year} {button type="submit" name="next" label="Continuer" shape="right" class="main"} - ou - {linkbutton shape="reset" href="!acc/years/" label="Passer cet étape"} <i class="help">(Il sera toujours possible de reprendre la balance d'ouverture plus tard.)</i> {elseif $previous_year} {csrf_field key="acc_years_balance_%s"|args:$year.id} <input type="hidden" name="from_year" value="{$previous_year.id}" /> {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} {literal} <script type="text/javascript" defer="defer" async="async"> g.script('scripts/accounting.js', () => { initTransactionForm(); }); </script> {/literal} {/if} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/years/close.tpl version [a98ff863c3].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | {include file="admin/_head.tpl" title="Clôturer un exercice" current="acc/years"} {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Clôturer un exercice</legend> <h3 class="warning"> Êtes-vous sûr de vouloir clôturer l'exercice « {$year.label} » ? </h3> <p class="block alert"> Un exercice clôturé ne peut plus être rouvert ou modifié !<br /> Il ne sera plus possible de modifier ou supprimer les écritures de l'exercice clôturé. </p> <dl> <dt>Début de l'exercice</dt> <dd>{$year.start_date|date_short}</dd> <dt>Fin de l'exercice</dt> <dd>{$year.end_date|date_short}</dd> </h3> </fieldset> <p class="help">Les soldes créditeurs ou débiteurs de chaque compte pourront être reportés automatiquement lors de l'ouverture de l'exercice suivant.</p> <p class="submit"> {csrf_field key="acc_years_close_%d"|args:$year.id} {button type="submit" name="close" label="Clôturer" shape="lock" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/years/delete.tpl version [d401db76d9].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | {include file="admin/_head.tpl" title="Supprimer un exercice" current="acc/years"} {include file="common/delete_form.tpl" legend="Supprimer cet exercice ?" warning="Êtes-vous sûr de vouloir supprimer l'exercice « %s » et ses %d écritures ?"|args:$year.label,$nb_transactions alert="Attention, il ne sera pas possible de récupérer les écritures supprimées." confirm="Cocher cette case pour confirmer la suppression de cet exercice et des %d écritures liées."|args:$nb_transactions csrf_key="acc_years_delete_%s"|args:$year.id } {include file="admin/_foot.tpl"} |
Added src/templates/acc/years/edit.tpl version [8d14799369].
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | {include file="admin/_head.tpl" title="Modifier un exercice" current="acc/years" js=1} {form_errors} <form method="post" action="{$self_url}" data-focus="1"> <fieldset> <legend>Modifier un exercice</legend> <dl> {input type="text" label="Libellé" name="label" source=$year required=true} {input type="date" label="Début de l'exercice" name="start_date" source=$year required=true} {input type="date" label="Fin de l'exercice" name="end_date" source=$year required=true} </dl> </fieldset> <p class="submit"> {csrf_field key="acc_years_edit_%s"|args:$year.id} {button type="submit" name="edit" label="Enregistrer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/years/import.tpl version [83c69987e2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | {include file="admin/_head.tpl" title="Importer des écritures" current="acc/years"} <nav class="acc-year"> <h4>Exercice sélectionné :</h4> <h3>{$year.label} — {$year.start_date|date_short} au {$year.end_date|date_short}</h3> </nav> <nav class="tabs"> <ul> <li class="current"><a href="{$admin_url}acc/years/import.php?id={$year.id}">Import</a></li> <li><a href="{$admin_url}acc/years/import.php?id={$year.id}&export=csv">Export journal général - CSV</a></li> <li><a href="{$admin_url}acc/years/import.php?id={$year.id}&export=ods">Export journal général - tableur</a></li> </ul> </nav> {form_errors} <form method="post" action="{$self_url}" enctype="multipart/form-data"> {if $csv->loaded()} {include file="common/_csv_match_columns.tpl"} <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="cancel" value="1" label="Annuler" shape="left"} {button type="submit" name="assign" label="Continuer" class="main" shape="right"} </p> {else} <fieldset> <legend>Import d'écritures</legend> <dl> <dt><label for="f_type_garradin">Format de fichier</label></dt> {input type="radio" name="type" value="garradin" label="Journal général au format CSV Garradin" default="garradin"} {input type="radio" name="type" value="csv" label="Journal au format CSV libre"} {include file="common/_csv_help.tpl"} {input type="file" name="file" label="Fichier CSV" accept=".csv,text/csv" required=1} <dd class="help block"> - Les lignes comportant un numéro d'écriture mettront à jour les écritures existantes correspondant à ces numéros (sauf si celles-ci ont été validées), alors que les lignes sans numéro créeront de nouvelles écritures.<br /> - Si le fichier comporte des écritures dont la date est en dehors de l'exercice courant, elles seront ignorées. </dd> </dl> </fieldset> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="load" label="Importer" shape="upload" class="main"} </p> {/if} </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/years/index.tpl version [1a1526a67f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | {include file="admin/_head.tpl" title="Exercices" current="acc/years"} <nav class="tabs"> <ul> <li class="current"><a href="{$self_url}">Exercices</a></li> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} <li><a href="{$admin_url}acc/years/new.php">Nouvel exercice</a></li> {/if} <li><a href="{$admin_url}acc/reports/projects.php">Projets <em>(compta analytique)</em></a></li> </ul> </nav> {if $_GET.msg == 'OPEN'} <p class="block error"> Il n'existe aucun exercice ouvert. {if $session->canAccess('compta', Membres::DROIT_ADMIN)} Merci d'en <a href="{$admin_url}acc/years/new.php">créer un nouveau</a> pour pouvoir saisir des écritures. {/if} </p> {/if} {if !empty($list)} {if count($list) > 1} <section class="year-infos"> <section class="graphs"> <figure> <img src="{$admin_url}acc/reports/graph_plot_all.php?type=assets" alt="" /> </figure> <figure> <img src="{$admin_url}acc/reports/graph_plot_all.php?type=result" alt="" /> </figure> </section> </section> {/if} <dl class="list"> {foreach from=$list item="year"} <dt>{$year.label}</dt> <dd class="desc"> {if $year.closed}Clôturé{else}En cours{/if} | Du {$year.start_date|date_short} au {$year.end_date|date_short} | <a href="../charts/accounts/?id={$year.id_chart}">Plan comptable</a> </dd> <dd class="desc"> <a href="{$admin_url}acc/reports/graphs.php?year={$year.id}">Graphiques</a> | <a href="{$admin_url}acc/reports/trial_balance.php?year={$year.id}">Balance générale</a> | <a href="{$admin_url}acc/reports/journal.php?year={$year.id}">Journal général</a> | <a href="{$admin_url}acc/reports/ledger.php?year={$year.id}">Grand livre</a> | <a href="{$admin_url}acc/reports/statement.php?year={$year.id}">Compte de résultat</a> | <a href="{$admin_url}acc/reports/balance_sheet.php?year={$year.id}">Bilan</a> </dd> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} <dd class="actions"> {linkbutton label="Export CSV" shape="export" href="import.php?id=%d&export=csv"|args:$year.id} {linkbutton label="Export tableur" shape="export" href="import.php?id=%d&export=ods"|args:$year.id} {if !$year.closed} {linkbutton label="Import" shape="upload" href="import.php?id=%d"|args:$year.id} {linkbutton label="Balance d'ouverture" shape="reset" href="balance.php?id=%d"|args:$year.id} {linkbutton label="Modifier" shape="edit" href="edit.php?id=%d"|args:$year.id} {linkbutton label="Clôturer" shape="lock" href="close.php?id=%d"|args:$year.id} {linkbutton label="Supprimer" shape="delete" href="delete.php?id=%d"|args:$year.id} {/if} </dd> {/if} {/foreach} </dl> {else} <p class="block alert"> Il n'y a pas d'exercice en cours. </p> {/if} {include file="admin/_foot.tpl"} |
Added src/templates/acc/years/new.tpl version [9c3fce8b6e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | {include file="admin/_head.tpl" title="Commencer un exercice" current="acc/years" js=1} <nav class="tabs"> <ul> <li><a href="./">Exercices</a></li> <li class="current"><a href="new.php">Nouvel exercice</a></li> </ul> </nav> {form_errors} <form method="post" action="{$self_url}" data-focus="1"> <fieldset> <legend>Commencer un nouvel exercice</legend> <dl> {input type="select_groups" options=$charts name="id_chart" label="Plan comptable" required=true} <dd class="help">Attention, il ne sera pas possible de modifier ou supprimer un compte du plan comptable si le compte est utilisé dans un exercice clôturé.<br /> Si vous souhaitez modifier le plan comptable pour ce nouvel exercice, il est recommandé de créer un nouveau plan comptable, recopié à partir de l'ancien plan comptable. Ainsi tous les comptes seront modifiables et supprimables.</dd> <dd class="help">{linkbutton shape="settings" label="Gestion des plans comptables" href="!acc/charts/"}</dd> {input type="text" name="label" label="Libellé" required=true} {input type="date" label="Début de l'exercice" name="start_date" required=true default=$start_date} {input type="date" label="Fin de l'exercice" name="end_date" required=true default=$end_date} </dl> </fieldset> <p class="submit"> {csrf_field key="acc_years_new"} {button type="submit" name="new" label="Créer ce nouvel exercice" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/acc/years/select.tpl version [5d2df7acaf].
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | {include file="admin/_head.tpl" title="Changer d'exercice" current="acc/years" js=1} <form method="post" action="{$self_url}" data-focus="1"> <fieldset> <legend>Changer l'exercice de travail</legend> <dl> <dd> <select name="year"> {foreach from=$list item="year"} <option value="{$year.id}">{$year.label} — {$year.start_date|date_short} au {$year.end_date|date_short}</option> {/foreach} </select> </dd> <dd class="help">Ici ne peuvent être sélectionnés que les exercices ouverts, car il n'est pas possible de modifier un exercice clos. Pour consulter les rapports pour les exercices clos, voir <a href="{$www_url}admin/acc/years/">la liste des exercices</a>.</dd> </dl> </fieldset> <p class="submit"> {csrf_field key="acc_select_year"} <input type="hidden" name="from" value="{$from}" /> {button type="submit" name="change" label="Changer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/_head.tpl from [ab1e909a41] to [2d4e6a44e7].
︙ | ︙ | |||
64 65 66 67 68 69 70 | {/if} </li> {if $session->canAccess('membres', Membres::DROIT_ACCES)} <li class="member list{if $current == 'membres'} current{elseif $current_parent == 'membres'} current_parent{/if}"><a href="{$admin_url}membres/"><b class="icn">👪</b><i> Membres</i></a> {if $session->canAccess('membres', Membres::DROIT_ECRITURE)} <ul> <li class="member new{if $current == 'membres/ajouter'} current{/if}"><a href="{$admin_url}membres/ajouter.php">Ajouter</a></li> | | | | | > | | | < < < > | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | {/if} </li> {if $session->canAccess('membres', Membres::DROIT_ACCES)} <li class="member list{if $current == 'membres'} current{elseif $current_parent == 'membres'} current_parent{/if}"><a href="{$admin_url}membres/"><b class="icn">👪</b><i> Membres</i></a> {if $session->canAccess('membres', Membres::DROIT_ECRITURE)} <ul> <li class="member new{if $current == 'membres/ajouter'} current{/if}"><a href="{$admin_url}membres/ajouter.php">Ajouter</a></li> <li class="{if $current == 'membres/services'} current{/if}"><a href="{$admin_url}services/">Activités & cotisations</a></li> <li class="member message{if $current == 'membres/message'} current{/if}"><a href="{$admin_url}membres/message_collectif.php">Message collectif</a></li> </ul> {/if} </li> {/if} {if $session->canAccess('compta', Membres::DROIT_ACCES)} <li class="{if $current == 'acc'} current{elseif $current_parent == 'acc'} current_parent{/if}"><a href="{$admin_url}acc/"><b>€</b><i> Comptabilité</i></a> <ul> {if $session->canAccess('compta', Membres::DROIT_ECRITURE)} <li class="{if $current == 'acc/new'} current{/if}"><a href="{$admin_url}acc/transactions/new.php">Saisie</a></li> {/if} <li class="{if $current == 'acc/accounts'} current{/if}"><a href="{$admin_url}acc/accounts/">Comptes</a></li> <li class="{if $current == 'acc/simple'} current{/if}"><a href="{$admin_url}acc/accounts/simple.php">Suivi des écritures</a></li> <li class="{if $current == 'acc/years'} current{/if}"><a href="{$admin_url}acc/years/">Exercices & rapports</a></li> {if $session->canAccess('compta', Membres::DROIT_ECRITURE)} <li class="{if $current == 'acc/charts'} current{/if}"><a href="{$admin_url}acc/charts/">Plans comptables</a></li> {/if} </ul> </li> {/if} {if $session->canAccess('wiki', Membres::DROIT_ACCES)} <li class="wiki{if $current == 'wiki'} current{elseif $current_parent == 'wiki'} current_parent{/if}"><a href="{$admin_url}wiki/"><b class="icn">✎</b><i> Wiki</i></a> <ul> <li class="wiki list{if $current == 'wiki/recent'} current{/if}"><a href="{$admin_url}wiki/recent.php">Dernières modifications</a> <li class="wiki search{if $current == 'wiki/chercher'} current{/if}"><a href="{$admin_url}wiki/chercher.php">Recherche</a> </ul> </li> {/if} {if $session->canAccess('config', Membres::DROIT_ADMIN)} <li class="main config{if $current == 'config'} current{elseif $current_parent == 'config'} current_parent{/if}"><a href="{$admin_url}config/"><b class="icn">☸</b><i> Configuration</i></a> {/if} <li class="{if $current == 'mes_infos'} current{elseif $current_parent == 'mes_infos'} current_parent{/if}"> <a href="{$admin_url}mes_infos.php"><b class="icn">👤</b><i> Mes infos personnelles</i></a> <ul> <li{if $current == 'my_services'} class="current"{/if}><a href="{$admin_url}my_services.php">Mes activités & cotisations</a></li> </ul> </li> {if !defined('Garradin\LOCAL_LOGIN') || !LOCAL_LOGIN} <li class="logout"><a href="{$admin_url}logout.php"><b class="icn">⤝</b><i> Déconnexion</i></a></li> {/if} {/if} </ul> |
︙ | ︙ |
Deleted src/templates/admin/compta/banques/index.tpl version [dfa7e103a3].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/banques/modifier.tpl version [f69ac09d72].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/banques/rapprocher.tpl version [77a239871a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/banques/supprimer.tpl version [f2f4e5378b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/categories/_nav.tpl version [b71d1d8635].
|
| < < < < < < |
Deleted src/templates/admin/compta/categories/ajouter.tpl version [f30b2371c1].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/categories/index.tpl version [7a1c1dcb5e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/categories/modifier.tpl version [75046d7ae0].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/categories/supprimer.tpl version [30d30ea90b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/comptes/ajouter.tpl version [f0cf451809].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/comptes/classe.tpl version [45939485c2].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/comptes/import.tpl version [99c4dfd495].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/comptes/index.tpl version [4936874101].
|
| < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/comptes/journal.tpl version [f69dd30f9f].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/comptes/modifier.tpl version [f906ad5d55].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/comptes/supprimer.tpl version [89dec94900].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/exercices/ajouter.tpl version [c84bd45486].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/exercices/cloturer.tpl version [6f4abfc5df].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/exercices/index.tpl version [ec3f086414].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/exercices/modifier.tpl version [ea0aa3d194].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/exercices/supprimer.tpl version [604797e2eb].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/import.tpl version [5bf6707f89].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/index.tpl version [9d6a3b1dd3].
|
| < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/operations/cotisation.tpl version [a490130f82].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/operations/index.tpl version [5baa65eca3].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/operations/membre.tpl version [8524d38029].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/operations/modifier.tpl version [da5bdb03fc].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/operations/recherche_sql.tpl version [c20d4df351].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/operations/saisir.tpl version [14b3e3ace9].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/operations/supprimer.tpl version [f5372a2a85].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/operations/voir.tpl version [48d792da66].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/projets/index.tpl version [c946bff41c].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/rapports/_header.tpl version [1061b17f5a].
|
| < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/rapports/_table_resultat.tpl version [97ca40a29c].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/rapports/bilan.tpl version [f3d93246ee].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/rapports/compte_resultat.tpl version [4206fc3206].
|
| < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/rapports/grand_livre.tpl version [9f320d7052].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/compta/rapports/journal.tpl version [7a19ce99c8].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/templates/admin/config/_menu.tpl from [cd582bc2fa] to [e4219ce6af].
|
| | > | | | | | | | | > | 1 2 3 4 5 6 7 8 9 10 11 | <nav class="tabs"> <ul> <li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}config/">Général</a></li> <li{if $current == 'categories'} class="current"{/if}><a href="{$admin_url}config/categories/">Catégories de membres</a></li> <li{if $current == 'fiches_membres'} class="current"{/if}><a href="{$admin_url}config/membres.php">Fiche des membres</a></li> <li{if $current == 'site'} class="current"{/if}><a href="{$admin_url}config/site.php">Site public</a></li> <li{if $current == 'donnees'} class="current"{/if}><a href="{$admin_url}config/donnees/">Sauvegarde et restauration</a></li> <li{if $current == 'plugins'} class="current"{/if}><a href="{$admin_url}config/plugins.php">Extensions</a></li> <li{if $current == 'logs'} class="current"{/if}><a href="{$admin_url}config/logs.php?type=errors">Journaux</a></li> </ul> </nav> |
Modified src/templates/admin/config/categories/index.tpl from [7ab8e26a24] to [b1e9086f4b].
︙ | ︙ | |||
14 15 16 17 18 19 20 | <tr> <th>{$cat.nom}</th> <td class="num">{$cat.nombre}</td> <td class="droits"> {format_droits droits=$cat} </td> <td class="actions"> | < < | > > | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <tr> <th>{$cat.nom}</th> <td class="num">{$cat.nombre}</td> <td class="droits"> {format_droits droits=$cat} </td> <td class="actions"> {if $cat.id != $user.id_categorie} {linkbutton shape="delete" label="Supprimer" href="supprimer.php?id=%d"|args:$cat.id} {/if} {linkbutton shape="edit" label="Modifier" href="modifier.php?id=%d"|args:$cat.id} {linkbutton shape="users" label="Liste des membres" href="!membres/?cat=%d"|args:$cat.id} </td> </tr> {/foreach} </tbody> </table> <form method="post" action="{$self_url}"> <fieldset> <legend>Ajouter une catégorie</legend> <dl> <dt><label for="f_nom">Nom</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="nom" id="f_nom" value="{form_field name=nom}" required="required" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="new_cat"} {button type="submit" name="save" label="Ajouter" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/categories/modifier.tpl from [5f082eb8b5] to [fb8b7e4413].
︙ | ︙ | |||
18 19 20 21 22 23 24 | <dd class="help"> Si coché cette catégorie ne sera visible qu'aux administrateurs et ne recevra pas de messages collectifs ou de rappels. </dd> </dl> </fieldset> | < < < < < < < < < < < < < < < < < < < < < < < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <dd class="help"> Si coché cette catégorie ne sera visible qu'aux administrateurs et ne recevra pas de messages collectifs ou de rappels. </dd> </dl> </fieldset> <fieldset> <legend>Droits</legend> <dl class="droits"> <dt><label for="f_droit_connexion_aucun">Les membres de cette catégorie peuvent-ils se connecter ?</label></dt> {if $readonly} <dd class="help"> Il n'est pas possible de désactiver ce droit pour votre propre catégorie. |
︙ | ︙ | |||
150 151 152 153 154 155 156 | <label for="f_droit_config_admin"><b class="admin">☑</b> Oui</label> </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="edit_cat_"|cat:$cat.id} | | | 126 127 128 129 130 131 132 133 134 135 136 137 138 | <label for="f_droit_config_admin"><b class="admin">☑</b> Oui</label> </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="edit_cat_"|cat:$cat.id} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/categories/supprimer.tpl from [9ebed2a419] to [f56242fa31].
︙ | ︙ | |||
20 21 22 23 24 25 26 | aux seuls membres de ce groupe, elles redeviendront lisibles et modifiables par tous les membres ayant accès au wiki ! </p> </fieldset> <p class="submit"> {csrf_field key="delete_cat_"|cat:$cat.id} | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 | aux seuls membres de ce groupe, elles redeviendront lisibles et modifiables par tous les membres ayant accès au wiki ! </p> </fieldset> <p class="submit"> {csrf_field key="delete_cat_"|cat:$cat.id} {button type="submit" name="delete" label="Supprimer" shape="delete" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/donnees/_menu.tpl from [27f416469b] to [96b956198e].
|
| > | | | | | | | | | > | 1 2 3 4 5 6 7 8 9 10 11 | <nav class="tabs"> <ul class="sub"> <li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}config/donnees/">Sauvegarder et restaurer</a></li> <li{if $current == 'import'} class="current"{/if}><a href="{$admin_url}config/donnees/import.php">Import et export</a></li> <li{if $current == 'local'} class="current"{/if}><a href="{$admin_url}config/donnees/local.php">Gestion des sauvegardes</a></li> {if ENABLE_AUTOMATIC_BACKUPS} <li{if $current == 'automatique'} class="current"{/if}><a href="{$admin_url}config/donnees/automatique.php">Configuration de la sauvegarde automatique</a></li> {/if} <li{if $current == 'reset'} class="current"{/if}><a href="{$admin_url}config/donnees/reset.php">Remise à zéro</a></li> </ul> </nav> |
Modified src/templates/admin/config/donnees/automatique.tpl from [1804eff257] to [f0d729ff37].
1 2 3 4 5 6 7 8 9 | {include file="admin/_head.tpl" title="Sauvegarde et restauration" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="automatique"} {form_errors} {if $ok == 'config'} | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | {include file="admin/_head.tpl" title="Sauvegarde et restauration" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="automatique"} {form_errors} {if $ok == 'config'} <p class="block confirm">La configuration a bien été enregistrée.</p> {/if} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Configuration de la sauvegarde automatique</legend> <p class="help"> |
︙ | ︙ |
Modified src/templates/admin/config/donnees/import.tpl from [79252f8a0f] to [19ab1e4db0].
1 2 3 4 5 6 7 8 9 10 11 12 13 | {include file="admin/_head.tpl" title="Import & export" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="import"} <fieldset> <dl> <dt>Membres</dt> <dd><a href="{$admin_url}membres/import.php">Import de la liste des membres</a></dd> <dd><a href="{$admin_url}membres/import.php?export=ods">Export de la liste des membres au format tableur Calc / Excel</a></dd> <dd><a href="{$admin_url}membres/import.php?export=csv">Export de la liste des membres au format CSV</a></dd> <dt>Comptabilité</dt> | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | {include file="admin/_head.tpl" title="Import & export" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="import"} <fieldset> <dl> <dt>Membres</dt> <dd><a href="{$admin_url}membres/import.php">Import de la liste des membres</a></dd> <dd><a href="{$admin_url}membres/import.php?export=ods">Export de la liste des membres au format tableur Calc / Excel</a></dd> <dd><a href="{$admin_url}membres/import.php?export=csv">Export de la liste des membres au format CSV</a></dd> <dt>Comptabilité</dt> <dd><a href="{$admin_url}acc/years/import.php">Import des données comptables</a></dd> <dd><a href="{$admin_url}acc/years/import.php?export=ods">Export des données comptables au format tableur Calc / Excel</a></dd> <dd><a href="{$admin_url}acc/years/import.php?export=csv">Export des données comptables au format CSV</a></dd> </dl> </fieldset> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/donnees/index.tpl from [87fb524e37] to [45e209af0c].
1 2 3 4 5 6 7 8 9 | {include file="admin/_head.tpl" title="Sauvegarde et restauration" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="index"} {form_errors} {if $code == Sauvegarde::INTEGRITY_FAIL && ALLOW_MODIFIED_IMPORT} | | | | | | | > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | {include file="admin/_head.tpl" title="Sauvegarde et restauration" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="index"} {form_errors} {if $code == Sauvegarde::INTEGRITY_FAIL && ALLOW_MODIFIED_IMPORT} <p class="block alert">Pour passer outre, renvoyez le fichier en cochant la case « Ignorer les erreurs ». Attention, si vous avez effectué des modifications dans la base de données, cela peut créer des bugs !</p> {/if} {if $ok} <p class="block confirm"> {if $ok == 'restore'}La restauration a bien été effectuée. Si vous désirez revenir en arrière, vous pouvez utiliser la sauvegarde automatique nommée <em>{$now_date}.avant_restauration.sqlite</em>, sinon vous pouvez l'effacer. {if $ok_code & Sauvegarde::NOT_AN_ADMIN} </p> <p class="block alert"> <strong>Vous n'êtes pas administrateur dans cette sauvegarde.</strong> Garradin a donné les droits d'administration à toutes les catégories afin d'empêcher de ne plus pouvoir se connecter. Merci de corriger les droits des catégories maintenant. {/if} {elseif $ok == 'remove'}La sauvegarde a été supprimée. {/if} </p> {/if} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Téléchargement d'une sauvegarde</legend> <p class="help"> Info : la base de données fait actuellement {$db_size|format_bytes} (dont {$files_size|format_bytes} pour les documents et images). </p> <p class="submit"> {csrf_field key="backup_download"} {button type="submit" name="download" label="Télécharger une copie de la base de données sur mon ordinateur" shape="download" class="main"} </p> </fieldset> </form> <form method="post" action="{$self_url_no_qs}" enctype="multipart/form-data"> <fieldset> <legend><label for="f_file">Restaurer depuis un fichier de sauvegarde</label></legend> <p class="block alert"> Attention, l'intégralité des données courantes seront effacées et remplacées par celles contenues dans le fichier fourni. </p> <p class="help"> Une sauvegarde des données courantes sera effectuée avant le remplacement, en cas de besoin d'annuler cette restauration. </p> <p> {csrf_field key="backup_restore"} <input type="hidden" name="MAX_FILE_SIZE" value="{$max_file_size}" /> <input type="file" name="file" id="f_file" required="required" /> (maximum {$max_file_size|format_bytes}) </p> <p class="submit"> {button type="submit" name="restore_file" label="Restaurer depuis le fichier sélectionné" shape="upload" class="main"} </p> {if $code && ($code == Sauvegarde::INTEGRITY_FAIL && ALLOW_MODIFIED_IMPORT)} <p> {input type="checkbox" name="force_import" value="1" label="Ignorer les erreurs, je sais ce que je fait"} </p> {/if} </fieldset> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/donnees/local.tpl from [4984d48811] to [b1089b8af9].
1 2 3 4 5 6 7 8 9 | {include file="admin/_head.tpl" title="Gestion des sauvegardes" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="local"} {form_errors} {if $ok} | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | {include file="admin/_head.tpl" title="Gestion des sauvegardes" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="local"} {form_errors} {if $ok} <p class="block confirm"> {if $ok == 'create'}Une nouvelle sauvegarde a été créée. {elseif $ok == 'restore'}La restauration a bien été effectuée. Si vous désirez revenir en arrière, vous pouvez utiliser la sauvegarde automatique nommée <em>date-du-jour.avant_restauration.sqlite</em>, sinon vous pouvez l'effacer. {if $ok_code & Sauvegarde::NOT_AN_ADMIN} </p> <p class="block alert"> <strong>Vous n'êtes pas administrateur dans cette sauvegarde.</strong> Garradin a donné les droits d'administration à toutes les catégories afin d'empêcher de ne plus pouvoir se connecter. Merci de corriger les droits des catégories maintenant. {/if} {elseif $ok == 'remove'}La sauvegarde a été supprimée. {/if} </p> {/if} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Copies de sauvegarde disponibles</legend> {if empty($liste)} <p class="help">Aucune copie de sauvegarde disponible.</p> {else} <dl> <dt><label for="f_select">Sélectionner une sauvegarde</label></dt> <dd> <select name="file" id="f_select"> {foreach from=$liste key="f" item="d"} <option value="{$f}">{$f} — {$d|date_long}</option> {/foreach} </select> </dd> <dd class="help"> Attention, en cas de restauration, l'intégralité des données courantes seront effacées et remplacées par celles contenues dans la sauvegarde sélectionnée. Cependant, afin de prévenir toute erreur une sauvegarde des données sera réalisée avant la restauration. </dd> </dl> <p> {csrf_field key="backup_manage"} {button type="submit" name="restore" label="Restaurer cette sauvegarde" shape="reset"} {button type="submit" name="delete" label="Supprimer cette sauvegarde" shape="delete"} </p> {/if} </fieldset> </form> <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Sauvegarde manuelle</legend> <p class="submit"> {csrf_field key="backup_create"} {button type="submit" name="create" label="Créer une nouvelle sauvegarde des données" shape="right" class="main"} </p> </fieldset> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/donnees/reset.tpl from [b44198b72b] to [c696026876].
1 2 3 4 5 6 7 8 9 | {include file="admin/_head.tpl" title="Remise à zéro" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="reset"} {form_errors} {if $ok !== null} | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | {include file="admin/_head.tpl" title="Remise à zéro" current="config"} {include file="admin/config/_menu.tpl" current="donnees"} {include file="admin/config/donnees/_menu.tpl" current="reset"} {form_errors} {if $ok !== null} <p class="block confirm">La remise à zéro a été effectuée. Une sauvegarde a également été créée.</p> </p> {/if} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Remise à zéro</legend> <p class="block error"> Attention : toutes les données seront effacées ! Ceci inclut les membres, les écritures comptables, les pages du wiki, etc. Seul votre compte membre sera re-créé avec le même email et mot de passe. </p> <p class="help"> Une sauvegarde sera automatiquement créée avant de procéder à la remise à zéro. </p> <dl> <dt><label for="f_passe_verif">Votre mot de passe</label> (pour vérification)</dt> |
︙ | ︙ |
Modified src/templates/admin/config/index.tpl from [6189dd4b55] to [4ed6b4f9b0].
1 2 3 4 5 | {include file="admin/_head.tpl" title="Configuration" current="config"} {include file="admin/config/_menu.tpl" current="index"} {if $ok && !$form->hasErrors()} | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | {include file="admin/_head.tpl" title="Configuration" current="config"} {include file="admin/config/_menu.tpl" current="index"} {if $ok && !$form->hasErrors()} <p class="block confirm"> La configuration a bien été enregistrée. </p> {/if} {form_errors} <form method="post" action="{$self_url}"> |
︙ | ︙ | |||
103 104 105 106 107 108 109 | </dl> </fieldset> <fieldset id="couleurs"> <legend>Personnalisation de l'interface</legend> <dl> | < | < | > | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | </dl> </fieldset> <fieldset id="couleurs"> <legend>Personnalisation de l'interface</legend> <dl> {input type="color" pattern="#[a-f0-9]{6}" title="Couleur au format hexadécimal" default=$couleur1 name="couleur1" label="Couleur primaire" placeholder=$couleurs_defaut[0]} {input type="color" pattern="#[a-f0-9]{6}" title="Couleur au format hexadécimal" default=$couleur2 name="couleur2" label="Couleur secondaire" placeholder=$couleurs_defaut[1]} {input type="file" label="Image de fond" name="background" help="Il est conseillé d'utiliser une image en noir et blanc avec un fond blanc pour un meilleur rendu. Dimensions recommandées : 380x200" accept="image/*,*.jpeg,*.jpg,*.png,*.gif"} </dl> <input type="hidden" name="image_fond" id="f_image_fond" data-source="{$background_image_source}" data-default="{$background_image_default}" value="{form_field name=image_fond}" /> </fieldset> <p class="submit"> {csrf_field key="config"} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/logs.tpl from [c62511fc2c] to [64e9f1fe33].
1 2 3 4 5 | {include file="admin/_head.tpl" title="Journaux" current="config" custom_css=["styles/config.css"]} {include file="admin/config/_menu.tpl" current="logs"} {if ERRORS_ENABLE_LOG_VIEW} | > | | | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | {include file="admin/_head.tpl" title="Journaux" current="config" custom_css=["styles/config.css"]} {include file="admin/config/_menu.tpl" current="logs"} {if ERRORS_ENABLE_LOG_VIEW} <nav class="tabs"> <ul class="sub"> {*<li{if $type != 'errors'} class="current"{/if}><a href="{$self_url_no_qs}">Actions utilisateurs</a></li>*} <li{if $type == 'errors'} class="current"{/if}><a href="?type=errors">Erreurs système</a></li> </ul> </nav> {/if} {if isset($reports) && isset($id)} <section class="error"> {foreach from=$main.errors item="error"} <h2 class="ruler">{$error.type}: {$error.message} [Code: {$error.errorCode}]</h2> {if !empty($error.backtrace)} |
︙ | ︙ | |||
57 58 59 60 61 62 63 | {elseif isset($errors)} <p class="help"> Liste des erreurs système et de code rencontrées par Garradin. Cliquer sur un des bugs pour le rapporter aux développeur⋅euses de Garradin. </p> {if !count($errors)} | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | {elseif isset($errors)} <p class="help"> Liste des erreurs système et de code rencontrées par Garradin. Cliquer sur un des bugs pour le rapporter aux développeur⋅euses de Garradin. </p> {if !count($errors)} <p class="block alert">Aucune erreur n'a été trouvée dans le journal error.log</p> {else} <table class="list"> <thead> <tr> <th>Réf.</th> <td>Erreur</td> <td>Occurences</td> |
︙ | ︙ | |||
79 80 81 82 83 84 85 | <th><a href="?type=errors&id={$ref}">{$ref}</a></th> <td> {$error.message}<br /> <tt>{$error.source}</tt> </td> <td>{$error.count}</td> <td>{$error.last_seen|date_fr}</td> | | > > | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | <th><a href="?type=errors&id={$ref}">{$ref}</a></th> <td> {$error.message}<br /> <tt>{$error.source}</tt> </td> <td>{$error.count}</td> <td>{$error.last_seen|date_fr}</td> <td class="actions"> {linkbutton shape="menu" label="Voir les détails" href="%s?type=errors&id=%s"|args:$self_url_no_qs,$ref} </td> </tr> {/foreach} </tbody> </table> {/if} {else} <p class="help"> Cette page permet de suivre les actions effectuées par les utilisateurs. </p> {if empty($list)} <p class="block alert"> Aucune entrée dans le journal d'actions. </p> {/if} {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/membres.tpl from [b07fc3c940] to [ca1ce7a233].
|
| | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | {include file="admin/_head.tpl" current="config" js=1 custom_css=['styles/config.css']} {include file="admin/config/_menu.tpl" current="fiches_membres"} {if isset($status) && $status == 'OK'} <p class="block confirm"> La configuration a bien été enregistrée. </p> {elseif isset($status) && $status == 'ADDED'} <p class="block alert"> Le champ a été ajouté à la fin de la liste. Pour sauvegarder les modifications de la fiche membre cliquer sur le bouton « Enregistrer » en base de page. </p> {/if} {form_errors} {if $review} <p class="help"> Voici ce à quoi ressemblera la nouvelle fiche de membre, vérifiez vos modifications avant d'enregistrer les changements. </p> <p class="block alert"> Attention ! Si vous avez supprimé un champ, les données liées à celui-ci seront supprimées de toutes les fiches de tous les membres. </p> <fieldset> <legend>Fiche membre exemple</legend> <dl> {foreach from=$champs item="champ" key="nom"} {if $nom == 'passe'}{continue}{/if} |
︙ | ︙ | |||
59 60 61 62 63 64 65 | <form method="post" action="{$admin_url}config/membres.php"> <p class="submit"> {csrf_field key="config_membres"} <input type="hidden" name="champs" value="{$champs|escape:json|escape}" /> <input type="submit" name="back" value="← Retour à l'édition" class="minor" /> <input type="submit" name="reset" value="Annuler les changements" class="minor" /> | | | | | | | | | | < | < | | | < | < | | < | | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | <form method="post" action="{$admin_url}config/membres.php"> <p class="submit"> {csrf_field key="config_membres"} <input type="hidden" name="champs" value="{$champs|escape:json|escape}" /> <input type="submit" name="back" value="← Retour à l'édition" class="minor" /> <input type="submit" name="reset" value="Annuler les changements" class="minor" /> {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> {else} <p class="help"> Cette page vous permet de personnaliser les fiches d'information des membres de l'association.<br /> <strong>Attention :</strong> Les champs supprimés de la fiche seront effacés de toutes les fiches de tous les membres, et les données qu'ils contenaient seront perdues. </p> {if !empty($presets)} <form method="post" action="{$self_url}"> <fieldset> <legend>Ajouter un champ pré-défini</legend> <p> <select name="preset" required="required"> <option></option> {foreach from=$presets key="name" item="preset"} <option value="{$name}">{$name} — {$preset.title}</option> {/foreach} </select> {csrf_field key="config_membres"} {button type="submit" name="add" label="Ajouter ce champ à la fiche membre" shape="plus"} </p> </fieldset> </form> {/if} <form method="post" action="{$self_url}"> <fieldset> <legend>Ajouter un champ personnalisé</legend> <dl> <dt><label for="f_name">Nom unique</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd class="help">Ne peut comporter que des lettres minuscules et des tirets bas.</dd> <dd><input type="text" name="new" id="f_name" value="{form_field name=new}" required="required" /></dd> <dt><label for="f_title">Titre</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="new_title" id="f_title" value="{form_field name=new_title}" required="required" /></dd> <dt><label for="f_type">Type de champ</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd> <select name="new_type" id="f_type" required="required"> {foreach from=$types key="type" item="nom"} <option value="{$type}" {form_field name=new_type selected=$type}>{$nom}</option> {/foreach} </select> </dd> </dl> <p> {csrf_field key="config_membres"} {button type="submit" name="add" label="Ajouter ce champ à la fiche membre" shape="plus"} <input type="hidden" name="champs" value="{$champs|escape:json|escape}" /> </p> </fieldset> </form> <form method="post" action="{$self_url}"> <div id="orderFields"> {foreach from=$champs item="champ" key="nom"} {if $nom == 'passe'}{continue}{/if} <fieldset id="f_{$nom}"> <legend>{$nom}</legend> <dl> <dt><label>Type</label></dt> <dd><input type="hidden" name="champs[{$nom}][type]" value="{$champ.type}" />{$champ.type|get_type}</dd> <dt><label for="f_{$nom}_title">Titre</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="champs[{$nom}][title]" id="f_{$nom}_title" value="{form_field data=$champs->$nom name=title}" required="required" /></dd> <dt><label for="f_{$nom}_help">Aide</label></dt> <dd><input type="text" name="champs[{$nom}][help]" id="f_{$nom}_help" value="{form_field data=$champs->$nom name=help}" /></dd> <dt>Préférences</dt> {input type="checkbox" name="champs[%s][private]"|args:$nom value="1" default=$champs->$nom->private label="Caché pour les membres" help="Si coché, ce champ ne sera pas visible par les membres dans leur espace personnel"} {input type="checkbox" name="champs[%s][editable]"|args:$nom value="1" default=$champs->$nom->editable label="Modifiable par les membres" help="Si coché, les membres pourront changer cette information depuis leur espace personnel"} {input type="checkbox" name="champs[%s][mandatory]"|args:$nom value="1" default=$champs->$nom->mandatory label="Champ obligatoire" help="Si coché, ce champ ne pourra rester vide"} {if $champ.type == 'select' || $champ.type == 'multiple'} <dt><label>Options disponibles</label></dt> {if $champ.type == 'multiple'} <dd class="help">Attention changer l'ordre des options peut avoir des effets indésirables.</dd> {else} <dd class="help">Attention renommer ou supprimer une option n'affecte pas ce qui a déjà été enregistré dans les fiches des membres.</dd> {/if} <dd> <{if $champ.type == 'multiple'}ol{else}ul{/if} class="options"> {if !empty($champ.options)} {foreach from=$champ.options key="key" item="opt"} <li><input type="text" name="champs[{$nom}][options][]" value="{$opt}" /></li> {/foreach} {/if} {if $champ.type == 'select' || empty($champ.options) || count($champ.options) < 32} <li><input type="text" name="champs[{$nom}][options][]" value="" /></li> {/if} </dd> {/if} <dt><label for="f_{$nom}_list_row">Numéro de colonne dans la liste des membres</label></dt> <dd class="help">Laisser vide ou indiquer le chiffre zéro pour que ce champ n'apparaisse pas dans la liste des membres. Inscrire un chiffre entre 1 et 10 pour indiquer l'ordre d'affichage du champ dans le tableau de la liste des membres.</dd> <dd><input type="number" id="f_{$nom}_list_row" name="champs[{$nom}][list_row]" min="0" max="10" value="{form_field data=$champs->$nom name=list_row}" /></dd> </dl> </fieldset> {/foreach} </div> <fieldset id="f_passe"> <legend>Mot de passe</legend> <dl> {input type="checkbox" name="champs[passe][private]" value="1" default=$champs.passe.private label="Caché pour les membres" help="Si coché, ce champ ne sera pas visible par les membres dans leur espace personnel"} {input type="checkbox" name="champs[passe][editable]" value="1" default=$champs.passe.editable label="Modifiable par les membres" help="Si coché, les membres pourront changer cette information depuis leur espace personnel"} {input type="checkbox" name="champs[passe][mandatory]" value="1" default=$champs.passe.mandatory label="Champ obligatoire" help="Si coché, ce champ ne pourra rester vide lors de la création d'un membre"} </dl> </fieldset> <p class="submit"> {csrf_field key="config_membres"} {button type="submit" name="reset" label="Annuler les changements" shape="left"} {button type="submit" name="review" label="Vérifier les changements" shape="right" class="main"} <em class="help">(un récapitulatif sera présenté et une confirmation sera demandée)</em> </p> </form> <script type="text/javascript"> var champ_identifiant = "f_{$config.champ_identifiant|escape:'js'}"; var champ_identite = "f_{$config.champ_identite|escape:'js'}"; |
︙ | ︙ |
Modified src/templates/admin/config/plugins.tpl from [d99e6b054a] to [7c6e7921f2].
︙ | ︙ | |||
8 9 10 11 12 13 14 | <form method="post" action="{$self_url}"> <fieldset> <legend>Désinstaller une extension</legend> <h3 class="warning"> Êtes-vous sûr de vouloir supprimer l'extension « {$plugin.nom} » ? </h3> | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <form method="post" action="{$self_url}"> <fieldset> <legend>Désinstaller une extension</legend> <h3 class="warning"> Êtes-vous sûr de vouloir supprimer l'extension « {$plugin.nom} » ? </h3> <p class="block alert"> <strong>Attention</strong> : cette action est irréversible et effacera toutes les données associées à l'extension. </p> </fieldset> <p class="submit"> {csrf_field key="delete_plugin_%s"|args:$plugin.id} {button type="submit" name="delete" label="Désinstaller" shape="delete" class="main"} </p> </form> {else} {if !empty($liste_installes)} <table class="list"> <thead> <tr> |
︙ | ︙ | |||
97 98 99 100 101 102 103 | <p class="help"> Attention : installer une extension non officielle peut présenter des risques de sécurité et de stabilité. </p> <p class="submit"> {csrf_field key="install_plugin"} | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | <p class="help"> Attention : installer une extension non officielle peut présenter des risques de sécurité et de stabilité. </p> <p class="submit"> {csrf_field key="install_plugin"} {button type="submit" name="install" label="Installer" shape="right" class="main"} </p> </form> {/if} {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/site.tpl from [dda2316333] to [bccd1ad764].
1 2 3 4 5 6 7 | {include file="admin/_head.tpl" title="Configuration — Site public" current="config" js=1} {form_errors} {include file="admin/config/_menu.tpl" current="site"} {if $config.desactiver_site} | | | | | > | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | {include file="admin/_head.tpl" title="Configuration — Site public" current="config" js=1} {form_errors} {include file="admin/config/_menu.tpl" current="site"} {if $config.desactiver_site} <div class="block alert"> <h3>Site public désactivé</h3> <p>Le site public est désactivé, les visiteurs sont redirigés automatiquement vers la page de connexion.</p> <form method="post" action="{$self_url}"> <p class="submit"> {csrf_field key="config_site"} {button type="submit" name="activer_site" label="Réactiver le site public" shape="right" class="main"} </p> </form> </div> {elseif isset($edit)} <form method="post" action="{$self_url}"> <h3>Éditer un squelette</h3> {if $ok} <p class="block confirm"> Modifications enregistrées. </p> {/if} <fieldset class="skelEdit"> <legend>{$edit.file}</legend> <p> <textarea name="content" cols="90" rows="50" id="f_content">{form_field name=content data=$edit}</textarea> </p> </fieldset> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> <script type="text/javascript"> var doc_url = "{$admin_url}doc/skel/"; var skel_list = {$sources|escape:json}; var skel_current = "{$edit.file|escape:'js'}"; g.script("scripts/skel_editor.js"); </script> {else} <fieldset> <legend>Activation du site public</legend> <dl> <dt> <form method="post" action="{$self_url}"> <p class="submit"> {button type="submit" name="desactiver_site" label="Désactiver le site public" shape="right" class="main"} {csrf_field key="config_site"} </p> </form> </dt> <dd class="help"> En désactivant le site public, les visiteurs seront automatiquement redirigés vers la page de connexion.<br /> Cette option est utile si vous avez déjà un site web et ne souhaitez pas utiliser la fonctionnalité site web de Garradin. </dd> </dl> |
︙ | ︙ | |||
71 72 73 74 75 76 77 | </fieldset> <form method="post" action="{$self_url}"> <fieldset class="templatesList"> <legend>Squelettes du site</legend> {if $reset_ok} | | | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | </fieldset> <form method="post" action="{$self_url}"> <fieldset class="templatesList"> <legend>Squelettes du site</legend> {if $reset_ok} <p class="block confirm"> Réinitialisation effectuée. Les squelettes ont été remis à jour </p> {/if} <table class="list"> <thead> <tr> <td class="check"></td> <th>Fichier</th> <td>Dernière modification</td> <td></td> </tr> </thead> <tbody> {foreach from=$sources key="source" item="local"} <tr> <td>{if $local && $local.dist}<input type="checkbox" name="select[]" value="{$source}" id="f_source_{$iteration}" /><label for="f_source_{$iteration}"></label>{/if}</td> <th><a href="{$admin_url}config/site.php?edit={$source|escape:'url'}" title="Éditer">{$source}</a></th> <td>{if $local}{$local.mtime|date_fr:'d/m/Y à H:i:s'}{else}<em>(fichier non modifié)</em>{/if}</td> <td class="actions"> {linkbutton shape="edit" label="Éditer" href="?edit=%s"|args:$source} </td> </tr> {/foreach} </tbody> </table> <p class="actions"> |
︙ | ︙ |
Modified src/templates/admin/index.tpl from [68896b2b83] to [7db5737b58].
1 2 3 4 | {include file="admin/_head.tpl" title="Bonjour %s !"|args:$user.identite current="home"} {$banniere|raw} | | > | < < < < < < < < < < < < | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | {include file="admin/_head.tpl" title="Bonjour %s !"|args:$user.identite current="home"} {$banniere|raw} <nav class="tabs"> <ul> <li><a href="{$admin_url}mes_infos.php">Modifier mes informations personnelles</a></li> <li><a href="{$admin_url}my_services.php">Suivi de mes cotisations</a></li> </ul> </nav> <aside class="describe"> <h3>{$config.nom_asso}</h3> {if !empty($config.adresse_asso)} <p> {$config.adresse_asso|escape|nl2br} </p> {/if} {if !empty($config.email_asso)} <p> E-Mail : <a href="mailto:{$config.email_asso}">{$config.email_asso}</a> </p> {/if} {if !empty($config.site_asso)} <p> Web : <a href="{$config.site_asso}" target="_blank">{$config.site_asso}</a> </p> {/if} </aside> <div class="wikiContent"> {$page.contenu.contenu|raw|format_wiki|liens_wiki:'wiki/?'} </div> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/install.tpl from [dd863dea3a] to [157fcf15fc].
1 2 3 | {include file="admin/_head.tpl" title="Garradin - Installation" js=1} {if $disabled} | | | < < < < | < < < | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | {include file="admin/_head.tpl" title="Garradin - Installation" js=1} {if $disabled} <p class="block error">Garradin est déjà installé.</p> {else} <p class="help"> Bienvenue dans Garradin ! Veuillez remplir les quelques informations suivantes pour terminer l'installation. </p> {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Informations sur l'association</legend> <dl> <dt><label for="f_nom_asso">Nom</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="nom_asso" id="f_nom_asso" required="required" value="{form_field name=nom_asso}" /></dd> </dl> </fieldset> <fieldset> <legend>Création du compte administrateur</legend> <dl> <dt><label for="f_nom_membre">Nom et prénom</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="nom_membre" id="f_nom_membre" required="required" value="{form_field name=nom_membre}" /></dd> <dt><label for="f_email_membre">Adresse E-Mail</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="email" name="email_membre" id="f_email_membre" required="required" value="{form_field name=email_membre}" /></dd> <dt><label for="f_passe_membre">Mot de passe</label> (minimum {$password_length} caractères) <b title="(Champ obligatoire)">obligatoire</b></dt> <dd class="help"> Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres. </dd> <dd class="help"> Pas d'idée ? Voici une suggestion choisie au hasard : <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" /> </dd> <dd><input type="password" name="passe" id="f_passe_membre" value="{form_field name=passe}" pattern="{$password_pattern}" required="required" autocomplete="off" /></dd> <dt><label for="f_repasse_membre">Encore le mot de passe</label> (vérification) <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="password" name="passe_confirmed" id="f_repasse_membre" value="{form_field name=passe_confirmed}" pattern="{$password_pattern}" required="required" autocomplete="off" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="install"} {button type="submit" name="save" label="Terminer l'installation" shape="right" class="main"} </p> <script type="text/javascript" src="{$admin_url}static/scripts/loader.js"></script> <script type="text/javascript"> {literal} g.script('scripts/password.js', () => { initPasswordField('pw_suggest', 'f_passe_membre', 'f_repasse_membre'); }); var form = $('form')[0]; form.onsubmit = function () { $('#f_submit').style.opacity = 0; var loader = document.createElement('div'); loader.className = 'loader install'; loader.innerHTML = '<b>Garradin est en cours d\'installation…</b>'; $('#f_submit').parentNode.appendChild(loader); |
︙ | ︙ |
Modified src/templates/admin/login.tpl from [74da885549] to [0141ab4856].
1 2 3 | {include file="admin/_head.tpl" title="Connexion" js=1} {form_errors} | < | | > > > > > | | | | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | {include file="admin/_head.tpl" title="Connexion" js=1} {form_errors} {if $changed} <p class="block confirm"> Votre mot de passe a bien été modifié.<br /> Vous pouvez maintenant l'utiliser pour vous reconnecter. </p> {/if} {if !$ssl_enabled && $prefer_ssl} <p class="block alert"> <strong>Message de sécurité</strong><br /> Nous vous conseillons de vous connecter sur la version <a href="{$own_https_url}">chiffrée (HTTPS) de cette page</a> pour vous connecter. </p> {/if} <p class="block error" style="display: none;" id="old_browser"> Le navigateur que vous utilisez n'est pas supporté. Des fonctionnalités peuvent ne pas fonctionner.<br /> Merci d'utiliser un navigateur web moderne comme <a href="https://www.getfirefox.com/" target="_blank">Firefox</a> ou <a href="https://vivaldi.com/fr/" target="_blank">Vivaldi</a>. </p> <form method="post" action="{$self_url}"> <fieldset> <legend>Connexion</legend> <dl> <dt><label for="f_id">{$id_field_name}</label></dt> <dd><input type="text" name="_id" id="f_id" value="{form_field name=_id}" /></dd> <dt><label for="f_passe">Mot de passe</label></dt> <dd><input type="password" name="password" id="f_passe" value="" autocomplete="current-password" /> {if $ssl_enabled} <b class="icn confirm" title="Connexion chiffrée">🔒</b> <span class="confirm">Connexion sécurisée</span> {else} <b class="icn error" title="Connexion non chiffrée">🔓</b> {if $prefer_ssl} <span class="error">Connexion non-sécurisée !</span> <a href="{$own_https_url}">Se connecter en HTTPS (sécurisé)</a> {else} <span class="alert">Connexion non-sécurisée</span> {/if} {/if} </dd> {input type="checkbox" name="permanent" value="1" label="Rester connecté‑e" help="recommandé seulement sur ordinateur personnel"} </dl> </fieldset> <p class="submit"> {csrf_field key="login"} {button type="submit" name="login" label="Se connecter" shape="right" class="main"} </p> <p class="help"> <a href="{$admin_url}password.php">Pas de mot de passe ou mot de passe perdu ?</a> </p> </form> {literal} <script type="text/javascript"> g.enhancePasswordField($('#f_passe')); if (!!window.document.documentMode) { document.getElementById('old_browser').style.display = 'block'; } </script> {/literal} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/login_otp.tpl from [6560c7df92] to [0b5ffa4503].
︙ | ︙ | |||
12 13 14 15 16 17 18 | <dd class="help">Entrez ici le code donné par l'application d'authentification double facteur.</dd> <dd><input type="text" name="code" id="f_code" value="{form_field name=code}" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="otp"} | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 | <dd class="help">Entrez ici le code donné par l'application d'authentification double facteur.</dd> <dd><input type="text" name="code" id="f_code" value="{form_field name=code}" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="otp"} {button type="submit" name="login" label="Se connecter" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/_list_actions.tpl from [0b734d6ba4] to [143fb71a16].
1 2 | <tfoot> <tr> | | | 1 2 3 4 5 6 7 8 9 10 | <tfoot> <tr> {if $session->canAccess('membres', Membres::DROIT_ADMIN)}<td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all2" /><label for="f_all2"></label></td>{/if} <td class="actions" colspan="{$colspan}"> <em>Pour les membres cochés :</em> {csrf_field key="membres_action"} <select name="action"> <option value="">— Choisir une action à effectuer —</option> <option value="move">Changer de catégorie</option> <option value="csv">Exporter en tableau CSV</option> |
︙ | ︙ |
Modified src/templates/admin/membres/_nav.tpl from [308ec1b1ac] to [419563ac94].
|
| | > | | | | < | | | > | 1 2 3 4 5 6 7 8 9 10 | <nav class="tabs"> <ul> <li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}membres/">Liste des membres</a></li> <li{if $current == 'recherche'} class="current"{/if}><a href="{$admin_url}membres/recherche.php">Recherche avancée</a></li> <li{if $current == 'recherches'} class="current"{/if}><a href="{$admin_url}membres/recherches.php">Recherches enregistrées</a></li> {if $session->canAccess('membres', Membres::DROIT_ADMIN)} <li{if $current == 'import'} class="current"{/if}><a href="{$admin_url}membres/import.php">Import & export</a></li> {/if} </ul> </nav> |
Modified src/templates/admin/membres/action.tpl from [a933fed19a] to [076d7f7b64].
1 2 | {include file="admin/_head.tpl" title="Action collective sur les membres" current="membres"} | | | 1 2 3 4 5 6 7 8 9 10 | {include file="admin/_head.tpl" title="Action collective sur les membres" current="membres"} <p class="block alert"> {$selected|count} membres sélectionnés </p> {form_errors} <form method="post" action="{$self_url}"> {foreach from=$selected item="id"} |
︙ | ︙ | |||
27 28 29 30 31 32 33 | </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="membres_action"} <input type="hidden" name="action" value="move" /> | | | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="membres_action"} <input type="hidden" name="action" value="move" /> {button type="submit" name="confirm" label="Enregistrer" shape="right" class="main"} </p> {elseif $action == 'delete'} <fieldset> <legend>Supprimer les membres sélectionnés ?</legend> <h3 class="warning"> Êtes-vous sûr de vouloir supprimer les {$nb_selected} membres sélectionnés ? </h3> <p class="block alert"> <strong>Attention</strong> : cette action est irréversible et effacera toutes les données personnelles et l'historique de ces membres. </p> <p class="help"> Alternativement, il est aussi possible de déplacer les membres qui ne font plus partie de l'association dans une catégorie « Anciens membres », plutôt que de les effacer complètement. </p> </fieldset> <p class="submit"> {csrf_field key="membres_action"} <input type="hidden" name="action" value="delete" /> {button type="submit" name="confirm" label="Oui, supprimer ces membres" shape="delete" class="main"} </p> {/if} </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/ajouter.tpl from [0fe46b0cf5] to [d82f80846b].
︙ | ︙ | |||
45 46 47 48 49 50 51 | </dd> </dl> </fieldset> {/if} <p class="submit"> {csrf_field key="new_member"} | | | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | </dd> </dl> </fieldset> {/if} <p class="submit"> {csrf_field key="new_member"} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> <script type="text/javascript"> {literal} g.script('scripts/password.js', () => { initPasswordField('pw_suggest', 'f_passe', 'f_repasse'); }); {/literal} </script> {include file="admin/_foot.tpl"} |
Deleted src/templates/admin/membres/cotisations.tpl version [329d9b5092].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/ajout.tpl version [6a2c71a215].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/gestion/modifier.tpl version [0430bb0891].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/gestion/rappel_modifier.tpl version [b2128e65d7].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/gestion/rappel_supprimer.tpl version [e3f2d395a4].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/gestion/rappels.tpl version [2f62692021].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/gestion/supprimer.tpl version [002d1f0636].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/index.tpl version [754a0411a5].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/rappels.tpl version [da02475b4a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/supprimer.tpl version [979b1b65a7].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/cotisations/voir.tpl version [79533ebb65].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/templates/admin/membres/fiche.tpl from [99f7b69c9c] to [4cc42f5c24].
1 2 | {include file="admin/_head.tpl" title="%s (%s)"|args:$membre.identite:$categorie.nom current="membres"} | | > | | | | | < | > | | | > | < | | | | | < < > | < < | < < | < | > > | | | < < < < < | < < < | < | | > > > | | < | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | {include file="admin/_head.tpl" title="%s (%s)"|args:$membre.identite:$categorie.nom current="membres"} <nav class="tabs"> <ul> <li class="current"><a href="{$admin_url}membres/fiche.php?id={$membre.id}">{$membre.identite}</a></li> {if $session->canAccess('membres', Membres::DROIT_ECRITURE)}<li><a href="{$admin_url}membres/modifier.php?id={$membre.id}">Modifier</a></li>{/if} {if $session->canAccess('membres', Membres::DROIT_ADMIN) && $user.id != $membre.id} <li><a href="{$admin_url}membres/supprimer.php?id={$membre.id}">Supprimer</a></li> {/if} </ul> </nav> <dl class="cotisation"> <dt>Activités et cotisations</dt> {foreach from=$services item="service"} <dd> {$service.label} {if $service.status == -1 && $service.end_date} — terminée {elseif $service.status == -1} — <b class="error">en retard</b> {elseif $service.status == 1 && $service.end_date} — <b class="confirm">en cours</b> {elseif $service.status == 1} — <b class="confirm">à jour</b>{/if} {if $service.status.expiry_date} — expire le {$service.expiry_date|date_short}{/if} {if !$service.paid} — <b class="error">À payer !</b>{/if} </dd> {foreachelse} <dd> Ce membre n'est inscrit à aucune activité ou cotisation. </dd> {/foreach} <dd> {if count($services)} {linkbutton href="!services/user.php?id=%d"|args:$membre.id label="Liste des inscriptions aux activités" shape="menu"} {/if} {if $session->canAccess('membres', Membres::DROIT_ECRITURE)} {linkbutton href="!services/save.php?user=%d"|args:$membre.id label="Inscrire à une activité" shape="plus"} {/if} </dd> {if $session->canAccess('membres', Membres::DROIT_ACCES)} {if !empty($transactions_linked)} <dt>Écritures comptables liées</dt> <dd><a href="{$admin_url}acc/transactions/user.php?id={$membre.id}">{$transactions_linked} écritures comptables liées à ce membre</a></dd> {/if} {if !empty($transactions_created)} <dt>Écritures comptables créées</dt> <dd><a href="{$admin_url}acc/transactions/creator.php?id={$membre.id}">{$transactions_created} écritures comptables créées par ce membre</a></dd> {/if} {/if} </dl> <aside class="describe"> <dl class="describe"> <dt>Catégorie</dt> <dd>{$categorie.nom} <span class="droits">{format_droits droits=$categorie}</span></dd> <dt>Inscription</dt> <dd>{$membre.date_inscription|date_short}</dd> <dt>Dernière connexion</dt> <dd>{if empty($membre.date_connexion)}Jamais{else}{$membre.date_connexion|date_long}{/if}</dd> <dt>Mot de passe</dt> <dd> {if empty($membre.passe)} Pas de mot de passe configuré {else} <b class="icn">☑</b> Oui {if !empty($membre.secret_otp)} |
︙ | ︙ | |||
90 91 92 93 94 95 96 | {elseif empty($membre->$c)} <em>(Non renseigné)</em> {elseif $c == $c_config.champ_identite} <strong>{$membre->$c}</strong> {elseif $c_config.type == 'email'} <a href="mailto:{$membre->$c|escape:'url'}">{$membre->$c}</a> {if $c == 'email'} | | | > > | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | {elseif empty($membre->$c)} <em>(Non renseigné)</em> {elseif $c == $c_config.champ_identite} <strong>{$membre->$c}</strong> {elseif $c_config.type == 'email'} <a href="mailto:{$membre->$c|escape:'url'}">{$membre->$c}</a> {if $c == 'email'} {linkbutton href="!membres/message.php?id=%d"|args:$membre.id label="Envoyer un message" shape="mail"} {/if} {elseif $c_config.type == 'tel'} <a href="tel:{$membre->$c}">{$membre->$c|format_tel}</a> {elseif $c_config.type == 'country'} {$membre->$c|get_country_name} {elseif $c_config.type == 'date'} {$membre->$c|date_short} {elseif $c_config.type == 'datetime'} {$membre->$c|date_fr} {elseif $c_config.type == 'password'} ******* {elseif $c_config.type == 'multiple'} <ul> {foreach from=$c_config.options key="b" item="name"} {if $membre->$c & (0x01 << $b)} <li>{$name}</li> |
︙ | ︙ |
Modified src/templates/admin/membres/import.tpl from [1c6c043793] to [a80b676531].
1 2 3 4 | {include file="admin/_head.tpl" title="Import & export des membres" current="membres" js=1} {include file="admin/membres/_nav.tpl" current="import"} | > | | | | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | {include file="admin/_head.tpl" title="Import & export des membres" current="membres" js=1} {include file="admin/membres/_nav.tpl" current="import"} <nav class="tabs"> <ul class="sub"> <li class="current"><a href="{$admin_url}membres/import.php">Importer</a></li> <li><a href="{$admin_url}membres/import.php?export=csv">Exporter en CSV</a></li> <li><a href="{$admin_url}membres/import.php?export=ods">Exporter en classeur Office</a></li> </ul> </nav> {form_errors} {if $ok} <p class="block confirm"> L'import s'est bien déroulé. </p> {/if} <form method="post" action="{$self_url}" enctype="multipart/form-data"> {if $csv->loaded()} {include file="common/_csv_match_columns.tpl"} {else} <fieldset> <legend>Importer depuis un fichier</legend> <dl> <dt><label for="f_file">Fichier à importer</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd class="help">La taille maximale du fichier est de {$max_upload_size|format_bytes}.</dd> <dd><input type="file" name="upload" id="f_file" required="required" /></dd> <dt><label for="f_type">Type de fichier</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd> <input type="radio" name="type" id="f_type" value="garradin" {form_field name=type checked="garradin" default="garradin"} /> <label for="f_type">Fichier CSV de Garradin</label> </dd> <dd class="help"> Export de la liste des membres au format CSV provenant de Garradin. Les lignes comportant un numéro de membre mettront à jour les fiches des membres ayant ce numéro (si le numéro existe), les lignes sans numéro ou avec un numéro inexistant créeront de nouveaux membres. </dd> <dd> <input type="radio" name="type" id="f_type_csv" value="custom" {form_field name=type checked="csv"} /> <label for="f_type_csv">Fichier CSV générique</label> </dd> <dd class="help"> Vous pourrez choisir la correspondance entre colonnes du CSV et champs des fiches membres dans le prochain écran. </dd> </dl> </fieldset> {/if} <p class="submit"> {csrf_field key=$csrf_key} {if $csv->loaded()}{button type="submit" name="cancel" value="1" label="Annuler" shape="left"}{/if} {button type="submit" name="import" label="Importer" shape="upload" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/index.tpl from [079c03ecc2] to [3c5240a563].
1 2 3 4 5 | {include file="admin/_head.tpl" title="Liste des membres" current="membres" js=1} {include file="admin/membres/_nav.tpl" current="index"} {if $sent} | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | {include file="admin/_head.tpl" title="Liste des membres" current="membres" js=1} {include file="admin/membres/_nav.tpl" current="index"} {if $sent} <p class="block confirm">Votre message a été envoyé.</p> {/if} {if !empty($membres_cats)} <form method="get" action="{$self_url}" class="shortFormRight"> <fieldset> <legend>Filtrer par catégorie</legend> <select name="cat" id="f_cat" onchange="this.form.submit();"> |
︙ | ︙ | |||
34 35 36 37 38 39 40 | <form method="post" action="action.php" class="memberList"> {if !empty($liste)} <table class="list"> <thead class="userOrder"> <tr> | | | | | | > > | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | <form method="post" action="action.php" class="memberList"> {if !empty($liste)} <table class="list"> <thead class="userOrder"> <tr> {if $session->canAccess('membres', Membres::DROIT_ADMIN)}<td class="check"><input type="checkbox" title="Tout cocher / décocher" id="f_all" /><label for="f_all"></label></td>{/if} {foreach from=$champs key="c" item="champ"} <td class="{if $order == $c} cur {if $desc}desc{else}asc{/if}{/if}">{if $c == "numero"}Num.{else}{$champ.title}{/if} <a href="?o={$c}&a&cat={$current_cat}" class="icn up">↑</a><a href="?o={$c}&d&cat={$current_cat}" class="icn dn">↓</a></td> {/foreach} <td></td> </tr> </thead> <tbody> {foreach from=$liste item="membre"} <tr> {if $session->canAccess('membres', Membres::DROIT_ADMIN)}<td class="check">{input type="checkbox" name="selected[]" value=$membre.id}</td>{/if} {foreach from=$champs key="c" item="cfg"} <td> {if $c == $config.champ_identite}<a href="{$admin_url}membres/fiche.php?id={$membre.id}">{/if} {$membre->$c|raw|display_champ_membre:$cfg} {if $c == $config.champ_identite}</a>{/if} </td> {/foreach} <td class="actions"> {linkbutton label="Fiche membre" shape="user" href="!membres/fiche.php?id=%d"|args:$membre.id} {if $session->canAccess('membres', Membres::DROIT_ECRITURE)} {linkbutton label="Modifier" shape="edit" href="!membres/modifier.php?id=%d"|args:$membre.id} {/if} </td> </tr> {/foreach} </tbody> {if $session->canAccess('membres', Membres::DROIT_ADMIN)} {include file="admin/membres/_list_actions.tpl" colspan=count((array)$champs)+1} {/if} </table> {pagination url=$pagination_url page=$page bypage=$bypage total=$total} {else} <p class="block alert"> Aucun membre trouvé. </p> {/if} </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/message.tpl from [3012105144] to [4059d1bc38].
︙ | ︙ | |||
19 20 21 22 23 24 25 | <label for="f_copie">Recevoir par e-mail une copie du message envoyé</label> </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="send_message_"|cat:$membre.id} | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 | <label for="f_copie">Recevoir par e-mail une copie du message envoyé</label> </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="send_message_"|cat:$membre.id} {button type="submit" name="save" label="Envoyer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/message_collectif.tpl from [873e17c7a4] to [7c563b6475].
︙ | ︙ | |||
39 40 41 42 43 44 45 | <label for="f_copie">Recevoir par e-mail une copie du message envoyé</label> </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="send_message_co"} | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 | <label for="f_copie">Recevoir par e-mail une copie du message envoyé</label> </dd> </dl> </fieldset> <p class="submit"> {csrf_field key="send_message_co"} {button type="submit" name="send" label="Envoyer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/modifier.tpl from [557472298c] to [2297e4baa2].
1 2 | {include file="admin/_head.tpl" title="Modifier un membre" current="membres" js=1} | | > | | | | | < | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | {include file="admin/_head.tpl" title="Modifier un membre" current="membres" js=1} <nav class="tabs"> <ul> <li><a href="{$admin_url}membres/fiche.php?id={$membre.id}">{$membre.identite}</a></li> <li class="current"><a href="{$admin_url}membres/modifier.php?id={$membre.id}">Modifier</a></li> {if $session->canAccess('membres', Membres::DROIT_ADMIN) && $user.id != $membre.id} <li><a href="{$admin_url}membres/supprimer.php?id={$membre.id}">Supprimer</a></li> {/if} </ul> </nav> {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Informations personnelles</legend> |
︙ | ︙ | |||
46 47 48 49 50 51 52 | </fieldset> {if $membre.secret_otp || $membre.clef_pgp} <fieldset> <legend>Options de sécurité</legend> <dl> {if $membre.secret_otp} | | | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | </fieldset> {if $membre.secret_otp || $membre.clef_pgp} <fieldset> <legend>Options de sécurité</legend> <dl> {if $membre.secret_otp} {input type="checkbox" name="clear_otp" value="1" label="Désactiver l'authentification à double facteur TOTP"} {/if} {if $membre.clef_pgp} {input type="checkbox" name="clear_pgp" value="1" label="Supprimer la clé PGP associée au membre"} {/if} </dl> </fieldset> {/if} {if $session->canAccess('membres', Membres::DROIT_ADMIN) && $user.id != $membre.id} <fieldset> |
︙ | ︙ | |||
73 74 75 76 77 78 79 | </dd> </dl> </fieldset> {/if} <p class="submit"> {csrf_field key="edit_member_"|cat:$membre.id} | | | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | </dd> </dl> </fieldset> {/if} <p class="submit"> {csrf_field key="edit_member_"|cat:$membre.id} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> <script type="text/javascript"> {literal} g.script('scripts/password.js', () => { initPasswordField('pw_suggest', 'f_passe', 'f_repasse'); }); {/literal} </script> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/recherche.tpl from [f88de1f28b] to [3d87844fd5].
1 2 3 4 | {include file="admin/_head.tpl" title="Recherche de membre" current="membres" js=1 custom_js=['query_builder.min.js']} {include file="admin/membres/_nav.tpl" current="recherche"} | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | {include file="admin/_head.tpl" title="Recherche de membre" current="membres" js=1 custom_js=['query_builder.min.js']} {include file="admin/membres/_nav.tpl" current="recherche"} {include file="common/search/advanced.tpl" action_url=$self_url} {if !empty($result)} {if $session->canAccess('membres', Membres::DROIT_ECRITURE)} <form method="post" action="{$admin_url}membres/action.php" class="memberList"> {/if} <p class="help">{$result|count} membres trouvés pour cette recherche.</p> <table class="list search"> <thead> <tr> {if $session->canAccess('membres', Membres::DROIT_ADMIN)}<td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all" /><label for="f_all"></label></td>{/if} {foreach from=$result_header key="c" item="cfg"} <td>{$cfg.title}</td> {/foreach} <td></td> </tr> </thead> <tbody> {foreach from=$result item="row"} <tr> {if $session->canAccess('membres', Membres::DROIT_ADMIN)}<td class="check">{input type="checkbox" name="selected[]" value=$row.id}</td>{/if} {foreach from=$row key="key" item="value"} <?php $link = false; ?> {if isset($result_header[$key])} <td> {if !$link} <a href="{$admin_url}membres/fiche.php?id={$row.id}"> {/if} {$value|raw|display_champ_membre:$key} {if !$link} <?php $link = true; ?> </a> {/if} </td> {/if} {/foreach} <td class="actions"> {linkbutton shape="user" label="Fiche membre" href="!membres/fiche.php?id=%d"|args:$row.id} {if $session->canAccess('membres', Membres::DROIT_ECRITURE)} {linkbutton shape="edit" label="Modifier" href="!membres/modifier.php?id=%d"|args:$row.id} {/if} </td> </tr> {/foreach} </tbody> {if $session->canAccess('membres', Membres::DROIT_ADMIN)} {include file="admin/membres/_list_actions.tpl" colspan=count($result_header)+1} {/if} </table> {if $session->canAccess('membres', Membres::DROIT_ECRITURE)} </form> {/if} {elseif $result !== null} <p class="block alert"> Aucun membre trouvé. </p> </form> {/if} {include file="admin/_foot.tpl"} |
Deleted src/templates/admin/membres/recherche_sql.tpl version [eb6cda8094].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/templates/admin/membres/recherches.tpl version [3685bb7adf].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added src/templates/admin/membres/selector.tpl version [6df59fc8ca].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | {include file="admin/_head.tpl" title="Sélectionner un compte" body_id="popup" is_popup=true} <form method="get" action="{$self_url_no_qs}"> <h2 class="ruler"> <input type="text" placeholder="Recherche rapide de membre" value="{$query}" name="q" /> <input type="submit" value="Chercher →" /> </h2> </form> <table class="list"> <tbody> {foreach from=$list item="row"} <tr> <td class="num"> {$row.numero} </td> <th> {$row.identite} </th> <td class="actions"> <button class="icn-btn" value="{$row.id}" data-label="{$row.numero} — {$row.identite}" data-icon="→">Sélectionner</button> </td> </tr> {/foreach} </tbody> </table> {literal} <script type="text/javascript"> var buttons = document.querySelectorAll('button'); buttons.forEach((e) => { e.onclick = () => { window.parent.g.inputListSelected(e.value, e.getAttribute('data-label')); }; }); if (buttons.length) { buttons[0].focus(); } var rows = document.querySelectorAll('table tbody tr'); if (rows.length == 1) { rows[0].querySelector('button').click(); } rows.forEach((e) => { e.classList.add('clickable'); e.onclick = (evt) => { if (evt.target.tagName && evt.target.tagName == 'BUTTON') { return; } e.querySelector('button').click(); }; }); document.querySelector('input').focus(); </script> {/literal} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/supprimer.tpl from [06cf105473] to [82816cbfa7].
1 2 | {include file="admin/_head.tpl" title="Supprimer un membre" current="membres"} | | > | | | | | < | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | {include file="admin/_head.tpl" title="Supprimer un membre" current="membres"} <nav class="tabs"> <ul> <li><a href="{$admin_url}membres/fiche.php?id={$membre.id}">{$membre.identite}</a></li> <li><a href="{$admin_url}membres/modifier.php?id={$membre.id}">Modifier</a></li> {if $session->canAccess('membres', Membres::DROIT_ADMIN)} <li class="current"><a href="{$admin_url}membres/supprimer.php?id={$membre.id}">Supprimer</a></li> {/if} </ul> </nav> {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Supprimer ce membre ?</legend> <h3 class="warning"> Êtes-vous sûr de vouloir supprimer le membre « {$membre.identite} » ? </h3> <p class="block alert"> <strong>Attention</strong> : cette action est irréversible et effacera toutes les données personnelles et l'historique de ces membres. </p> <p class="help"> Alternativement, il est aussi possible de déplacer les membres qui ne font plus partie de l'association dans une catégorie « Anciens membres », plutôt que de les effacer complètement. </p> </fieldset> <p class="submit"> {csrf_field key="delete_membre_"|cat:$membre.id} {button type="submit" name="delete" label="Supprimer" shape="delete" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Deleted src/templates/admin/mes_cotisations.tpl version [2423b2fa48].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/templates/admin/mes_infos.tpl from [e0d2fe1382] to [763d2f19e4].
1 2 | {include file="admin/_head.tpl" title="Mes informations personnelles" current="mes_infos" js=1} | | > | | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | {include file="admin/_head.tpl" title="Mes informations personnelles" current="mes_infos" js=1} <nav class="tabs"> <ul> <li class="current"><a href="{$admin_url}mes_infos.php">Mes informations personnelles</a></li> <li><a href="{$admin_url}mes_infos_securite.php">Mot de passe et options de sécurité</a></li> </ul> </nav> {form_errors membre=1} <form method="post" action="{$self_url}"> <fieldset> <legend>Informations personnelles</legend> |
︙ | ︙ | |||
23 24 25 26 27 28 29 | <fieldset> <legend>Changer mon mot de passe</legend> <p><a href="{$admin_url}mes_infos_securite.php">Modifier mon mot de passe ou autres informations de sécurité.</a></p> </fieldset> <p class="submit"> {csrf_field key="edit_me"} | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 | <fieldset> <legend>Changer mon mot de passe</legend> <p><a href="{$admin_url}mes_infos_securite.php">Modifier mon mot de passe ou autres informations de sécurité.</a></p> </fieldset> <p class="submit"> {csrf_field key="edit_me"} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/mes_infos_securite.tpl from [6446fe3bc3] to [24feb0ef13].
1 2 | {include file="admin/_head.tpl" title="Mes informations de connexion et sécurité" current="mes_infos" js=1} | | > | | | > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | {include file="admin/_head.tpl" title="Mes informations de connexion et sécurité" current="mes_infos" js=1} <nav class="tabs"> <ul> <li><a href="{$admin_url}mes_infos.php">Mes informations personnelles</a></li> <li class="current"><a href="{$admin_url}mes_infos_securite.php">Mot de passe et options de sécurité</a></li> </ul> </nav> {if $ok} <p class="block confirm"> Changements enregistrés. </p> {/if} {form_errors} {if $confirm} <form method="post" action="{$self_url_no_qs}"> {if !empty($otp) && $otp == 'disable'} <p class="block alert"> Confirmez la désactivation de l'authentification à double facteur TOTP. </p> {elseif !empty($otp)} <p class="block alert"> Confirmez l'activation de l'authentification à double facteur TOTP en l'utilisant une première fois. </p> <fieldset> <legend>Confirmer l'activation de l'authentification à double facteur (2FA)</legend> <img class="qrcode" src="{$otp.qrcode}" alt="" /> <dl> |
︙ | ︙ | |||
53 54 55 56 57 58 59 | {csrf_field key="edit_me_security"} <input type="hidden" name="passe" value="{form_field name="passe"}" /> <input type="hidden" name="passe_confirmed" value="{form_field name="passe_confirmed"}" /> <input type="hidden" name="clef_pgp" value="{form_field name="clef_pgp"}" /> {if !empty($otp)} <input type="hidden" name="otp_secret" value="{$otp.secret}" /> {/if} | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | {csrf_field key="edit_me_security"} <input type="hidden" name="passe" value="{form_field name="passe"}" /> <input type="hidden" name="passe_confirmed" value="{form_field name="passe_confirmed"}" /> <input type="hidden" name="clef_pgp" value="{form_field name="clef_pgp"}" /> {if !empty($otp)} <input type="hidden" name="otp_secret" value="{$otp.secret}" /> {/if} {button type="submit" name="confirm" label="Confirmer" shape="right" class="main"} </p> </form> {else} <form method="post" action="{$self_url_no_qs}"> |
︙ | ︙ | |||
92 93 94 95 96 97 98 | <legend>Authentification à double facteur (2FA)</legend> <p class="help">Pour renforcer la sécurité de votre connexion en cas de vol de votre mot de passe, vous pouvez activer l'authentification à double facteur. Cela nécessite d'installer une application comme <a href="https://freeotp.github.io/">FreeOTP</a> sur votre téléphone.</p> <dl> <dt>Authentification à double facteur (TOTP)</dt> {if $membre.secret_otp} | | | | | | | | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | <legend>Authentification à double facteur (2FA)</legend> <p class="help">Pour renforcer la sécurité de votre connexion en cas de vol de votre mot de passe, vous pouvez activer l'authentification à double facteur. Cela nécessite d'installer une application comme <a href="https://freeotp.github.io/">FreeOTP</a> sur votre téléphone.</p> <dl> <dt>Authentification à double facteur (TOTP)</dt> {if $membre.secret_otp} {input type="radio" name="otp" value="" default="" label="Activée"} {input type="radio" name="otp" value="generate" label="Re-générer une nouvelle clé secrète" help="Si la clé a été compromise ou perdue"} {input type="radio" name="otp" value="disable" label="Désactiver l'authentification à double facteur"} {else} <dd><em>Désactivée</em></dd> {input type="checkbox" name="otp" value="generate" label="Activer"} {/if} </dl> </fieldset> {if $pgp_disponible} <fieldset> <legend>Protéger mes mails personnels par chiffrement PGP/GnuPG</legend> <dl> <dt><label for="f_clef_pgp">Ma clé publique PGP</label></dt> <dd class="help">En inscrivant ici votre clé publique, tous les emails personnels (non collectifs) qui vous sont envoyés seront chiffrés (cryptés) avec cette clé : messages envoyés par les membres, rappels de cotisation, procédure de récupération de mot de passe, etc.</dd> <dd><textarea name="clef_pgp" id="f_clef_pgp" cols="90" rows="5">{form_field name="clef_pgp" data=$user}</textarea></dd> {if $clef_pgp_fingerprint}<dd class="help">L'empreinte de la clé est : <code>{$clef_pgp_fingerprint}</code></dd>{/if} </dl> <p class="block alert"> Attention : en inscrivant ici votre clé PGP, les emails de récupération de mot de passe perdu vous seront envoyés chiffrés et ne pourront être lus sans utiliser le mot de passe protégeant votre clé privée correspondante. </p> </fieldset> {/if} <p class="submit"> {csrf_field key="edit_me_security"} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> <script type="text/javascript"> {literal} g.script('scripts/password.js', () => { initPasswordField('pw_suggest', 'f_passe', 'f_passe_confirmed'); }); {/literal} </script> {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/password.tpl from [d9cc01423e] to [c3884ccc30].
1 2 3 4 | {include file="admin/_head.tpl" title="Mot de passe oublié ou pas de mot de passe ?"} {if !empty($sent)} | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | {include file="admin/_head.tpl" title="Mot de passe oublié ou pas de mot de passe ?"} {if !empty($sent)} <p class="block confirm"> Un e-mail vous a été envoyé, cliquez sur le lien dans cet e-mail pour modifier votre mot de passe. </p> <p class="block alert"> Si le message n'apparaît pas dans les prochaines minutes, vérifiez le dossier Spam ou Indésirables. </p> {else} {form_errors} |
︙ | ︙ | |||
27 28 29 30 31 32 33 | <dt><label for="f_id">{$champ.title}</label></dt> <dd><input type="text" name="id" id="f_id" value="{form_field name=id}" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="recoverPassword"} | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <dt><label for="f_id">{$champ.title}</label></dt> <dd><input type="text" name="id" id="f_id" value="{form_field name=id}" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="recoverPassword"} {button type="submit" name="recover" label="Envoyer" shape="right" class="main"} </p> </form> {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/password_change.tpl from [bfd4bc96b0] to [fe8143958d].
︙ | ︙ | |||
13 14 15 16 17 18 19 | Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres. </dd> <dd class="help"> Pas d'idée ? Voici une suggestion choisie au hasard : <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" /> </dd> | | | | | | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | Astuce : un mot de passe de quatre mots choisis au hasard dans le dictionnaire est plus sûr et plus simple à retenir qu'un mot de passe composé de 10 lettres et chiffres. </dd> <dd class="help"> Pas d'idée ? Voici une suggestion choisie au hasard : <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" /> </dd> <dd><input type="password" name="passe" id="f_passe_membre" value="{form_field name=passe}" pattern="{$password_pattern}" required="required" autocomplete="new-password" /></dd> <dt><label for="f_repasse_membre">Encore le mot de passe</label> (vérification) <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="password" name="passe_confirmed" id="f_repasse_membre" value="{form_field name=passe_confirmed}" pattern="{$password_pattern}" required="required" autocomplete="new-password" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="changePassword"} {button type="submit" name="change" label="Modifier le mot de passe" shape="right" class="main"} </p> <script type="text/javascript"> {literal} g.script('scripts/password.js', () => { initPasswordField('pw_suggest', 'f_passe', 'f_repasse'); }); {/literal} </script> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/wiki/_fichiers.tpl from [7aaf5c2a52] to [f7f28ddc72].
︙ | ︙ | |||
8 9 10 11 12 13 14 | <input type="hidden" name="MAX_FILE_SIZE" value="{$max_size}" id="f_maxsize" /> <dl> <dd class="help">Taille maximale : {$max_size|format_bytes}</dd> <dd class="fileUpload"><input type="file" name="fichier" id="f_fichier" data-hash-check /></dd> </dl> <p class="submit"> {csrf_field key=$csrf_id} | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <input type="hidden" name="MAX_FILE_SIZE" value="{$max_size}" id="f_maxsize" /> <dl> <dd class="help">Taille maximale : {$max_size|format_bytes}</dd> <dd class="fileUpload"><input type="file" name="fichier" id="f_fichier" data-hash-check /></dd> </dl> <p class="submit"> {csrf_field key=$csrf_id} {button type="submit" name="upload" label="Envoyer le fichier" shape="upload" class="main" id="f_submit"} </p> </fieldset> </form> <form method="get" action="#" style="display: none;" id="insertImage"> <fieldset> <h3>Insérer une image dans le texte</h3> |
︙ | ︙ | |||
42 43 44 45 46 47 48 | {if !empty($images)} <ul class="gallery"> {foreach from=$images item="file"} <li> <figure> <a href="{$file.url}" data-id="{$file.id}"><img src="{$file.thumb}" alt="" title="{$file.nom}" /></a> <form class="actions" method="post" action="{$self_url}"> | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | {if !empty($images)} <ul class="gallery"> {foreach from=$images item="file"} <li> <figure> <a href="{$file.url}" data-id="{$file.id}"><img src="{$file.thumb}" alt="" title="{$file.nom}" /></a> <form class="actions" method="post" action="{$self_url}"> {linkbutton shape="download" label="Télécharger" href=$file.url target="_blank"} {csrf_field key=$csrf_id} <input type="hidden" name="delete" value="{$file.id}" /> <noscript><input type="submit" value="Supprimer" /></noscript> </form> </figure> </li> {/foreach} </ul> {/if} {if !empty($fichiers)} <table class="list"> <tbody> {foreach from=$fichiers item="file"} <tr> <th>{$file.nom}</th> <td>{if $file.type}{$file.type}{/if}</td> <td class="actions"> <form class="actions" method="post" action="{$self_url}"> {linkbutton shape="download" label="Télécharger" href=$file.url target="_blank"} {csrf_field key=$csrf_id} <input type="hidden" name="delete" value="{$file.id}" /> <noscript><input type="submit" value="Supprimer" /></noscript> </form> </td> </tr> {/foreach} </tbody> </table> {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/wiki/chercher.tpl from [779cd678e9] to [b5b27035db].
1 2 3 4 5 | {include file="admin/_head.tpl" title="Recherche" current="wiki/chercher"} <form method="get" action="{$admin_url}wiki/chercher.php" class="wikiSearch"> <fieldset> <legend>Rechercher une page</legend> | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | {include file="admin/_head.tpl" title="Recherche" current="wiki/chercher"} <form method="get" action="{$admin_url}wiki/chercher.php" class="wikiSearch"> <fieldset> <legend>Rechercher une page</legend> <p class="submit"> <input type="text" name="q" value="{$recherche}" size="25" /> {button type="submit" name="search" label="Chercher" shape="search" class="main"} </p> </fieldset> </form> {if !$recherche} <p class="block alert"> Aucun terme recherché. </p> {else} <p class="block alert"> <strong>{$nb_resultats}</strong> pages trouvées pour « {$recherche} » </p> <div class="wikiResults"> {foreach from=$resultats item="page"} <h3><a href="./?{$page.uri}">{$page.titre}</a></h3> <p>{$page.snippet|escape|clean_snippet}</p> {/foreach} </div> {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/wiki/creer.tpl from [f972f094f4] to [e927f05760].
︙ | ︙ | |||
10 11 12 13 14 15 16 | <dt><label for="f_titre">Titre</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="titre" id="f_titre" value="{form_field name=titre}" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="wiki_create"} | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <dt><label for="f_titre">Titre</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="titre" id="f_titre" value="{form_field name=titre}" /></dd> </dl> </fieldset> <p class="submit"> {csrf_field key="wiki_create"} {button type="submit" name="create" label="Créer cette page" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/wiki/editer.tpl from [8014427a9f] to [fd789cac99].
︙ | ︙ | |||
100 101 102 103 104 105 106 | </fieldset> <p class="submit"> {csrf_field key="wiki_edit_%d"|args:$page.id} <input type="hidden" name="revision_edition" value="{form_field name=revision_edition default=$page.revision}" /> <input type="hidden" name="debut_edition" value="{form_field name=debut_edition default=$time}" /> <input id="f_id" value="{$page.id}" type="hidden" /> | | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | </fieldset> <p class="submit"> {csrf_field key="wiki_edit_%d"|args:$page.id} <input type="hidden" name="revision_edition" value="{form_field name=revision_edition default=$page.revision}" /> <input type="hidden" name="debut_edition" value="{form_field name=debut_edition default=$time}" /> <input id="f_id" value="{$page.id}" type="hidden" /> {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> <script type="text/javascript"> var page_id = '{$page.id}'; {literal} |
︙ | ︙ |
Modified src/templates/admin/wiki/historique.tpl from [7c0d2ecc52] to [ad74fa04e5].
1 2 | {include file="admin/_head.tpl" title="Historique : %s"|args:$page.titre current="wiki"} | | > | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | {include file="admin/_head.tpl" title="Historique : %s"|args:$page.titre current="wiki"} <nav class="tabs"> <ul> <li><a href="{$admin_url}wiki/?{$page.uri}">Retour à la page</a></li> </ul> </nav> {if !empty($revisions)} <table class="list wikiRevisions"> {foreach from=$revisions item="rev"} <tr> <td> {if $rev.chiffrement} |
︙ | ︙ | |||
21 22 23 24 25 26 27 | {if $rev.revision == 1} diff {else} <a href="?id={$page.id}&diff={$rev.revision-1}.{$rev.revision}">diff</a> {/if} {/if} </td> | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | {if $rev.revision == 1} diff {else} <a href="?id={$page.id}&diff={$rev.revision-1}.{$rev.revision}">diff</a> {/if} {/if} </td> <th>{$rev.date|date_long}</th> <td> {if $session->canAccess('membres', Membres::DROIT_ACCES)} <a href="{$admin_url}membres/fiche.php?id={$rev.id_auteur}">{$rev.nom_auteur}</a> {/if} </td> <td class="length"> {$rev.taille} octets |
︙ | ︙ | |||
49 50 51 52 53 54 55 | {/if} </td> </tr> {/foreach} </table> {elseif !empty($diff)} <div class="wikiRevision revisionLeft"> | | | | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | {/if} </td> </tr> {/foreach} </table> {elseif !empty($diff)} <div class="wikiRevision revisionLeft"> <h3>Version du {$rev1.date|date_long}</h3> {if $session->canAccess('membres', Membres::DROIT_ACCES)} <h4>De <a href="{$admin_url}membres/fiche.php?id={$rev1.id_auteur}">{$rev1.nom_auteur}</a></h4> {/if} {if $rev1.modification} <p><em>{$rev1.modification}</em></p> {/if} </div> <div class="wikiRevision revisionRight"> <h3>Version {if $rev2.revision == $page.revision}actuelle en date{/if} du {$rev2.date|date_long}</h3> {if $session->canAccess('membres', Membres::DROIT_ACCES)} <h4>De <a href="{$admin_url}membres/fiche.php?id={$rev2.id_auteur}">{$rev2.nom_auteur}</a></h4> {/if} {if $rev2.modification} <p><em>{$rev2.modification}</em></p> {/if} </div> {diff old=$rev1.contenu new=$rev2.contenu} {else} <p class="block alert"> Cette page n'a pas d'historique. </p> {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/wiki/page.tpl from [29bcb6b0e7] to [3fdabd965d].
1 2 3 4 5 6 | {if !empty($page.titre) && $can_read} {include file="admin/_head.tpl" title=$page.titre current="wiki" js=1} {else} {include file="admin/_head.tpl" title="Wiki" current="wiki"} {/if} | | > | | | | | | | | | | | | | | | | > | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | {if !empty($page.titre) && $can_read} {include file="admin/_head.tpl" title=$page.titre current="wiki" js=1} {else} {include file="admin/_head.tpl" title="Wiki" current="wiki"} {/if} <nav class="tabs"> <ul> {if $session->canAccess('wiki', Membres::DROIT_ECRITURE)} <li><a href="{$admin_url}wiki/creer.php?parent={if $page && $config.accueil_wiki != $page.uri}{$page.id}{else}0{/if}"><strong>Créer une nouvelle page</strong></a></li> {/if} {if $can_edit} <li><a href="{$admin_url}wiki/editer.php?id={$page.id}">Éditer</a></li> {/if} {if $can_read && $page && $page.contenu} <li><a href="{$admin_url}wiki/historique.php?id={$page.id}">Historique</a></li> {if $page.droit_lecture == Wiki::LECTURE_PUBLIC} <li><a href="{$www_url}{$page.uri}{if $has_public_children}/{/if}">Voir sur le site</a></li> {/if} {/if} {if $can_edit && $session->canAccess('wiki', Membres::DROIT_ADMIN)} <li><a href="{$admin_url}wiki/supprimer.php?id={$page.id}">Supprimer</a></li> {/if} </ul> </nav> {if !$can_read} <p class="block alert">Vous n'avez pas le droit de lire cette page.</p> {else} <div class="breadCrumbs"> <ul> <li><a href="./">Wiki</a></li> {if !empty($breadcrumbs)} {foreach from=$breadcrumbs item="crumb"} <li><a href="?{$crumb.uri}">{$crumb.titre}</a></li> {/foreach} {/if} </ul> </div> {if !$page} <p class="block error"> Cette page n'existe pas. </p> {if $can_edit} <form method="post" action="{$admin_url}wiki/creer.php"> <p class="submit"> {csrf_field key="wiki_create"} <input type="hidden" name="titre" value="{$uri}" /> {button type="submit" name="create" label="Créer cette page" shape="right" class="main"} </p> </form> {/if} {else} {if !empty($children)} <div class="wikiChildren"> <h4>Dans cette rubrique</h4> <ul> {foreach from=$children item="child"} <li><a href="?{$child.uri}">{$child.titre}</a></li> {/foreach} </ul> </div> {/if} {if !$page.contenu} <p class="block alert">Cette page est vide, cliquez sur « Éditer » pour la modifier.</p> {else} {if $page.contenu.chiffrement} <noscript> <div class="error"> Vous dever activer javascript pour pouvoir déchiffrer cette page. </div> </noscript> <script type="text/javascript" src="{$admin_url}static/scripts/wiki-encryption.js"></script> <div id="wikiEncryptedMessage"> <p class="block alert">Cette page est chiffrée. <input type="button" onclick="return wikiDecrypt(false);" value="Entrer le mot de passe" /> </p> </div> <div class="wikiContent" style="display: none;" id="wikiEncryptedContent"> {$page.contenu.contenu} </div> {else} |
︙ | ︙ | |||
106 107 108 109 110 111 112 | {/if} {if !empty($fichiers)} <ul class="files"> {foreach from=$fichiers item="file"} <li> <aside class="fichier" class="internal-file"><a href="{$file.url}">{$file.nom}</a> | | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | {/if} {if !empty($fichiers)} <ul class="files"> {foreach from=$fichiers item="file"} <li> <aside class="fichier" class="internal-file"><a href="{$file.url}">{$file.nom}</a> <small>({$file.type}, {$file.taille|format_bytes})</small></aside> </li> {/foreach} </ul> {/if} </div> {/if} <p class="wikiFooter"> Dernière modification le {$page.date_modification|date_long} {if $session->canAccess('membres', Membres::DROIT_ACCES)} par <a href="{$admin_url}membres/fiche.php?id={$page.contenu.id_auteur}">{$auteur}</a> {/if} </p> {/if} {/if} {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/wiki/recent.tpl from [7d673143bc] to [b616432b4b].
1 2 3 4 5 6 7 8 | {include file="admin/_head.tpl" title="Pages modifiées récemment" current="wiki/recent"} {if !empty($list)} <table class="list"> <tbody> {foreach from=$list item="page"} <tr> <th><a href="{$admin_url}wiki/?{$page.uri}">{$page.titre}</a></th> | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | {include file="admin/_head.tpl" title="Pages modifiées récemment" current="wiki/recent"} {if !empty($list)} <table class="list"> <tbody> {foreach from=$list item="page"} <tr> <th><a href="{$admin_url}wiki/?{$page.uri}">{$page.titre}</a></th> <td>{$page.date_modification|date_long}</td> </tr> {/foreach} </tbody> </table> {pagination url="?p=[ID]" page=$current_page bypage=$bypage total=$total} {else} <p class="block alert">Pas de modification récente.</p> {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/wiki/supprimer.tpl from [dc6d537e13] to [0d139503af].
1 2 | {include file="admin/_head.tpl" title="Supprimer : %s"|args:$page.titre current="wiki"} | | > | | | | | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | {include file="admin/_head.tpl" title="Supprimer : %s"|args:$page.titre current="wiki"} <nav class="tabs"> <ul> <li><a href="{$admin_url}wiki/"><strong>Wiki</strong></a></li> <li><a href="{$admin_url}wiki/chercher.php">Rechercher</a></li> <li><a href="{$admin_url}wiki/?{$page.uri}">Voir la page</a></li> <li><a href="{$admin_url}wiki/editer.php?id={$page.id}">Éditer</a></li> </ul> </nav> {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Supprimer cette page du wiki ?</legend> <h3 class="warning"> Êtes-vous sûr de vouloir supprimer la page « {$page.titre} » ? </h3> <p class="help"> La page ne pourra pas être supprimée si d'autres pages l'utilisent comme rubrique parente. </p> </fieldset> <p class="submit"> {csrf_field key="delete_wiki_"|cat:$page.id} {button type="submit" name="delete" label="Supprimer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/common/_csv_help.tpl version [2cbd2ae88a].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | <dd class="help"> Règles à suivre pour créer le fichier CSV : <ul> <li>Il est recommandé d'utiliser LibreOffice pour créer le fichier CSV</li> <li>Le fichier doit être en UTF-8</li> <li>Le séparateur doit être le point-virgule ou la virgule</li> <li>Cocher l'option <em>"Mettre en guillemets toutes les cellules du texte"</em></li> <li>Le fichier doit comporter les colonnes suivantes : <em>{$csv->getColumnsString()}</em></li> <li>Le fichier peut également comporter les colonnes suivantes : <em>{$csv->getMandatoryColumnsString()}</em></li> </ul> </dd> |
Added src/templates/common/_csv_match_columns.tpl version [f8a953f97c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <fieldset> <legend>Importer depuis un fichier CSV générique</legend> <dl> <dd class="help">{$csv->count()} lignes trouvées dans le fichier</dd> <dt>{input type="checkbox" name="skip_first_line" value="1" label="Ne pas importer la première ligne" help="Décocher cette case si la première ligne ne contient pas l'intitulé des colonnes, mais des données" default=1} <dt><label>Correspondance des colonnes</label></dt> <dd> <table class="list auto"> <tbody> {foreach from=$csv->getFirstLine() key="index" item="csv_field"} <tr> <th>{$csv_field}</th> <td> <select name="translation_table[{$index}]"> <?php $selected = $csv->getSelectedTable(); ?> <option value="">-- Ne pas importer cette colonne</option> {foreach from=$csv->getColumns() item="label" key="key"} <option value="{$key}" {if $selected[$index] == $key}selected="selected"{/if}>{$label}</option> {/foreach} </select> </td> </tr> {/foreach} </tbody> </table> </dd> </dl> </fieldset> |
Added src/templates/common/delete_file.tpl version [42a5f97ba7].
> > > > > > > > | 1 2 3 4 5 6 7 8 | {include file="admin/_head.tpl" title="Supprimer un fichier" current=null} {include file="common/delete_form.tpl" legend="Supprimer ce fichier ?" warning="Êtes-vous sûr de vouloir supprimer le fichier « %s » ?"|args:$file.nom } {include file="admin/_foot.tpl"} |
Added src/templates/common/delete_form.tpl version [089a0cfbe1].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>{$legend}</legend> <h3 class="warning"> {$warning} </h3> {if isset($alert)} <p class="block alert"> {$alert} </p> {/if} {if isset($info)} <p class="help"> {$info} </p> {/if} {if isset($confirm)} <p> {input type="checkbox" name="confirm_delete" value=1 label=$confirm} </p> {/if} </fieldset> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="delete" label="Supprimer" shape="delete" class="main"} {if isset($extra)} {foreach from=$extra key="key" item="value"} {if is_array($value)} {foreach from=$value key="subkey" item="subvalue"} <input type="hidden" name="{$key}[{$subkey}]" value="{$subvalue}" /> {/foreach} {else} <input type="hidden" name="{$key}" value="{$value}" /> {/if} {/foreach} {/if} </p> </form> |
Added src/templates/common/dynamic_list_head.tpl version [0d6279460e].
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <table class="list"> <thead class="userOrder"> <tr> {if !empty($check)} <td class="check"><input type="checkbox" title="Tout cocher / décocher" id="f_all" /><label for="f_all"></label></td> {/if} {foreach from=$list->getHeaderColumns() key="key" item="column"} <td class="{if $list->order == $key}cur {if $list->desc}desc{else}asc{/if}{/if}"> {$column.label} {if !array_key_exists('select', $column) || !is_null($column['select'])} <a href="{$list->orderURL($key, false)}" class="icn up">↑</a> <a href="{$list->orderURL($key, true)}" class="icn dn">↓</a> {/if} </td> {/foreach} <td></td> </tr> </thead> <tbody> |
Added src/templates/common/search/advanced.tpl version [793be9f367].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | <?php assert(isset($columns)); assert(isset($action_url)); assert(isset($query)); assert(isset($is_admin)); $sql_disabled = !$is_admin; ?> {form_errors} <form method="post" action="{$action_url}" id="queryBuilderForm"> <fieldset> {if $sql_query} <legend>Schéma des tables SQL</legend> <pre class="sql_schema">{foreach from=$schema item="table"}{$table}<br />{/foreach}</pre> <dl> {input type="textarea" name="sql_query" cols="100" rows="7" required=1 label="Requête SQL" help="Si aucune limite n'est précisée, une limite de 100 résultats sera appliquée." default=$sql_query disabled=$sql_disabled} </dl> <p class="submit"> {button type="submit" name="run" label="Exécuter" shape="search" class="main"} <input type="hidden" name="id" value="{$search.id}" /> {if $search.id} {button name="save" value=1 type="submit" label="Enregistrer : %s"|args:$search.intitule|truncate:40:"…":true shape="upload"} {else} {button name="save" value=1 type="submit" label="Enregistrer cette recherche" shape="upload"} {/if} </p> {else} <legend>Rechercher</legend> <div class="queryBuilder" id="queryBuilder"></div> <p class="actions"> <label>Trier par <select name="order"> {foreach from=$columns key="column" item="properties"} <option value="{$column}"{if $query.order == $column} selected="selected"{/if}>{$properties.label}</option> {/foreach} </select> </label> <input type="checkbox" name="desc" value="1" {if $query.desc}checked="checked"{/if} id="f_desc" /> <label for="f_desc">Tri inversé</label> <label>Limiter à <input type="number" value="{$query.limit}" name="limit" size="5" /> résultats</label> </p> <p class="submit"> {button name="search" value=1 type="submit" label="Chercher" shape="search" id="send" class="main"} <input type="hidden" name="q" id="jsonQuery" /> <input type="hidden" name="id" value="{$search.id}" /> {if $search.id} {button name="save" value=1 type="submit" label="Enregistrer : %s"|args:$search.intitule|truncate:40:"…":true shape="upload"} {else} {button name="save" value=1 type="submit" label="Enregistrer cette recherche" shape="upload"} {/if} {if $is_admin} {button name="to_sql" value=1 type="submit" label="Recherche SQL" shape="edit"} {/if} </p> {/if} </fieldset> </form> <script type="text/javascript"> var columns = {$columns|escape:'json'}; {literal} var translations = { "after": "après", "before": "avant", "is equal to": "est égal à", "is equal to one of": "est égal à une des ces options", "is not equal to one of": "n'est pas égal à une des ces options", "is not equal to": "n'est pas égal à", "is greater than": "est supérieur à", "is greater than or equal to": "est supérieur ou égal à", "is less than": "est inférieur à", "is less than or equal to": "est inférieur ou égal à", "is between": "est situé entre", "is not between": "n'est pas situé entre", "is null": "est nul", "is not null": "n'est pas nul", "begins with": "commence par", "doesn't begin with": "ne commence pas par", "ends with": "se termine par", "doesn't end with": "ne se termine pas par", "contains": "contient", "doesn't contain": "ne contient pas", "matches one of": "correspond à", "is true": "oui", "is false": "non", "Matches ALL of the following conditions:": "Correspond à TOUS les critères suivants :", "Matches ANY of the following conditions:": "Correspond à UN des critères suivants :", "Add a new set of conditions below this one": "-- Ajouter un groupe de critères", "Remove this set of conditions": "-- Supprimer ce groupe de critères" }; var q = new SQLQueryBuilder(columns); q.__ = function (str) { return translations[str]; }; q.loadDefaultOperators(); q.buildInput = function (type, label, column) { if (label == '+') { label = '➕'; } else if (label == '-') { label = '➖'; } if (type == 'button') { var i = document.createElement('button'); i.className = 'icn-btn'; i.type = 'button'; i.setAttribute('data-icon', label); } else { var i = document.createElement('input'); i.type = type == 'integer' ? 'number' : type; i.value = label; } return i; }; q.init(document.getElementById('queryBuilder')); $('#queryBuilderForm').onsubmit = function () { $('#jsonQuery').value = JSON.stringify(q.export()); }; {/literal} q.import({$query.query|escape:'json'}); </script> |
Added src/templates/common/search/saved_searches.tpl version [22a975d3e5].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | {include file="admin/_head.tpl" title="Recherches enregistrées" current=$target} {if $target == 'membres'} {include file="admin/membres/_nav.tpl" current="recherches"} {else} <nav class="tabs"> <ul> <li><a href="search.php">Recherche</a></li> <li class="current"><a href="saved_searches.php">Recherches enregistrées</a></li> </ul> </nav> {/if} {if $mode == 'edit'} {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Modifier une recherche enregistrée</legend> <dl> <dt><label for="f_intitule">Intitulé</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="text" name="intitule" id="f_intitule" value="{form_field name="intitule" data=$recherche}" size="80" required="required" /></dd> <dt>Statut</dt> <dd><label><input type="radio" name="prive" value="1" {if $recherche.id_membre}checked="checked"{/if} /> Recherche privée</label> — Visible seulement par moi-même</dd> <dd><label><input type="radio" name="prive" value="0" {if !$recherche.id_membre}checked="checked"{/if} /> Recherche publique</label> — Visible et exécutable par tous les membres ayant accès à la gestion {$target}</dd> <dt>Type</dt> <dd>{if $recherche.type == Recherche::TYPE_JSON}Avancée{else}SQL{/if}</dd> <dt>Cible</dt> <dd>{$recherche.cible}</dd> </dl> </fieldset> <p class="submit"> {csrf_field key="edit_recherche_%s"|args:$recherche.id} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> {elseif $mode == 'delete'} {include file="common/delete_form.tpl" legend="Supprimer cette recherche enregistrée ?" warning="Êtes-vous sûr de vouloir supprimer la recherche enregistrée « %s » ?"|args:$recherche.intitule csrf_key="del_recherche_%s"|args:$recherche.id } {elseif count($liste) == 0} <p class="block alert">Aucune recherche enregistrée. <a href="{$search_url}">Faire une nouvelle recherche</a></p> {else} <table class="list"> <thead> <tr> <th>Recherche</th> <th>Type</th> <th>Statut</th> <th></th> </tr> </thead> <tbody> {foreach from=$liste item="recherche"} <tr> <th><a href="{$search_url}?id={$recherche.id}">{$recherche.intitule}</a></th> <td>{if $recherche.type == Recherche::TYPE_JSON}Avancée{else}SQL{/if}</td> <td>{if !$recherche.id_membre}Publique{else}Privée{/if}</td> <td class="actions"> {linkbutton href="%s?id=%d"|args:$search_url,$recherche.id shape="search" label="Rechercher"} {if $recherche.id_membre || $session->canAccess($target, Membres::DROIT_ADMIN)} {linkbutton href="?duplicate=%d"|args:$recherche.id shape="export" label="Dupliquer"} {linkbutton href="?edit=%d"|args:$recherche.id shape="edit" label="Modifier"} {linkbutton href="?delete=%d"|args:$recherche.id shape="delete" label="Supprimer"} {/if} </td> </tr> {/foreach} </tbody> </table> {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/error.tpl from [5457db8bcb] to [6a0842893f].
︙ | ︙ | |||
29 30 31 32 33 34 35 | </style> </head> <body> <h1>{if empty($title)}Erreur{else}{$title}{/if}</h1> | | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | </style> </head> <body> <h1>{if empty($title)}Erreur{else}{$title}{/if}</h1> <p class="block error"> {$error|escape|nl2br} </p> <p> <a href="{$admin_url}" onclick="history.back(); return false;">← Retour</a> </p> </body> </html> |
Added src/templates/my_services.tpl version [79bef75320].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | {include file="admin/_head.tpl" title="Mes activités & cotisations" current="my_services"} <dl class="cotisation"> <dt>Mes activités et cotisations</dt> {foreach from=$services item="service"} <dd> {$service.label} {if $service.status == -1 && $service.end_date} — terminée {elseif $service.status == -1} — <b class="error">en retard</b> {elseif $service.status == 1 && $service.end_date} — <b class="confirm">en cours</b> {elseif $service.status == 1} — <b class="confirm">à jour</b>{/if} {if $service.status.expiry_date} — expire le {$service.expiry_date|date_short}{/if} {if !$service.paid} — <b class="error">À payer !</b>{/if} </dd> {foreachelse} <dd> Vous n'êtes inscrit à aucune activité ou cotisation. </dd> {/foreach} </dl> {if $list->count()} <h2 class="ruler">Historique des inscriptions</h2> {include file="common/dynamic_list_head.tpl"} {foreach from=$list->iterate() item="row"} <tr> <th>{$row.label}</th> <td>{$row.date|date_short}</td> <td>{$row.expiry|date_short}</td> <td>{$row.fee}</td> <td>{if $row.paid}<b class="confirm">Oui</b>{else}<b class="error">Non</b>{/if}</td> <td>{$row.amount|raw|money_currency}</td> <td class="actions"> </td> </tr> {/foreach} </tbody> </table> {pagination url=$list->paginationURL() page=$list.page bypage=$list.per_page total=$list->count()} {/if} {include file="admin/_foot.tpl"} |
Added src/templates/services/_nav.tpl version [a7923367e8].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <nav class="tabs"> <ul> <li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}services/">Activités et cotisations</a></li> <li{if $current == 'save'} class="current"{/if}><a href="{$admin_url}services/save.php">Inscrire à une activité</a></li> {if $session->canAccess('membres', Membres::DROIT_ADMIN)} <li{if $current == 'reminders'} class="current"{/if}><a href="{$admin_url}services/reminders/">Gestion des rappels automatiques</a></li> {/if} </ul> {if isset($current_service)} <ul class="sub"> <li class="title"> {$current_service.label} — {if $current_service.duration} {$current_service.duration} jours {elseif $current_service.start_date} du {$current_service.start_date|date_short} au {$current_service.end_date|date_short} {else} ponctuelle {/if} </li> <li{if $service_page == 'index'} class="current"{/if}><a href="{$admin_url}services/fees/?id={$current_service.id}"><strong>Gestion des tarifs</strong></a></li> <li{if $service_page == 'paid'} class="current"{/if}><a href="{$admin_url}services/details.php?id={$current_service.id}">À jour et payés</a></li> <li{if $service_page == 'expired'} class="current"{/if}><a href="{$admin_url}services/details.php?id={$current_service.id}&type=expired">Inscription expirée</a></li> <li{if $service_page == 'unpaid'} class="current"{/if}><a href="{$admin_url}services/details.php?id={$current_service.id}&type=unpaid">En attente de règlement</a></li> </ul> {/if} {if isset($current_fee)} <ul class="sub"> <li class="title"> {$current_fee.label} {if $current_fee.amount} — {$current_fee.amount|money_currency|raw}{/if} </li> <li{if $fee_page == 'paid'} class="current"{/if}><a href="{$admin_url}services/fees/details.php?id={$current_fee.id}">À jour et payés</a></li> <li{if $fee_page == 'expired'} class="current"{/if}><a href="{$admin_url}services/fees/details.php?id={$current_fee.id}&type=expired">Inscription expirée</a></li> <li{if $fee_page == 'unpaid'} class="current"{/if}><a href="{$admin_url}services/fees/details.php?id={$current_fee.id}&type=unpaid">En attente de règlement</a></li> </ul> {/if} </nav> |
Added src/templates/services/_service_form.tpl version [00234cd4d6].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>{$legend}</legend> <dl> {input name="label" type="text" required=1 label="Libellé" source=$service} {input name="description" type="textarea" label="Description" source=$service} <dt><label for="f_periodicite_jours">Période de validité</label></dt> <dd class="help">Attention, une modification de la période renseignée ici ne modifie pas la date d'expiration des activités déjà enregistrées.</dd> {input name="period" type="radio" value="0" label="Pas de période (cotisation ponctuelle)" default=$period} {input name="period" type="radio" value="1" label="En nombre de jours" default=$period} <dd class="period_1"> <dl> {input name="duration" type="number" step="1" label="Durée de validité" size="5" source=$service} </dl> </dd> {input name="period" type="radio" value="2" label="Période définie (date à date)" default=$period} <dd class="period_2"> <dl class="periode_dates"> {input type="date" name="start_date" label="Date de début" source=$service} {input type="date" name="end_date" label="Date de fin" source=$service} </dl> </dd> </dl> </fieldset> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> <script type="text/javascript"> {literal} (function () { var hide = []; if (!$('#f_period_1').checked) hide.push('.period_1'); if (!$('#f_period_2').checked) hide.push('.period_2'); g.toggle(hide, false); function togglePeriod() { g.toggle(['.period_1', '.period_2'], false); if (this.checked && this.value == 1) g.toggle('.period_1', true); else if (this.checked && this.value == 2) g.toggle('.period_2', true); } $('#f_period_0').onchange = togglePeriod; $('#f_period_1').onchange = togglePeriod; $('#f_period_2').onchange = togglePeriod; })(); {/literal} </script> |
Added src/templates/services/delete.tpl version [e828c3fad7].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | {include file="admin/_head.tpl" title="Supprimer une activité" current="membres/services"} {include file="services/_nav.tpl" current="index"} {include file="common/delete_form.tpl" legend="Supprimer cette activité ?" warning="Êtes-vous sûr de vouloir supprimer l'activité « %s » ?"|args:$service.label alert="Attention, cela supprimera également l'historique des membres inscrits à cette activité, ainsi que les rappels associés." info="Les écritures comptables liées à l'historique des membres inscrits à cette activité ne seront pas supprimées, et la comptabilité demeurera inchangée."} {include file="admin/_foot.tpl"} |
Added src/templates/services/details.tpl version [3f202e10e4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | {include file="admin/_head.tpl" title="%s — Liste des membres inscrits"|args:$service.label current="membres/services"} {include file="services/_nav.tpl" current="index" current_service=$service service_page=$type} <dl class="cotisation"> <dt>Nombre de membres trouvés</dt> <dd> {$list->count()} <em class="help">(N'apparaît ici que l'inscription la plus récente de chaque membre.)</em> {if $session->canAccess('membres', Membres::DROIT_ADMIN)} {linkbutton href="%s&export=csv"|args:$self_url shape="export" label="Export CSV"} {linkbutton href="%s&export=ods"|args:$self_url shape="export" label="Export tableur"} {/if} </dd> </dl> {include file="common/dynamic_list_head.tpl"} {foreach from=$list->iterate() item="row"} <tr> <th><a href="../membres/fiche.php?id={$row.id_user}">{$row.identity}</a></th> <td> {if $row.status == 1 && $row.end_date} En cours {elseif $row.status == 1} <b class="confirm">À jour</b> {elseif $row.status == -1 && $row.end_date} Terminée {elseif $row.status == -1} <b class="error">En retard</b> {else} Pas d'expiration {/if} </td> <td>{if $row.paid}<b class="confirm">Oui</b>{else}<b class="error">Non</b>{/if}</td> <td>{$row.expiry|date_short}</td> <td>{$row.fee}</td> <td>{$row.date|date_short}</td> <td class="actions"> {linkbutton shape="user" label="Toutes les activités de ce membre" href="!services/user.php?id=%d"|args:$row.id_user} {linkbutton shape="alert" label="Rappels envoyés" href="!services/reminders/user.php?id=%d"|args:$row.id_user} </td> </tr> {/foreach} </tbody> </table> {pagination url=$list->paginationURL() page=$list.page bypage=$list.per_page total=$list->count()} {include file="admin/_foot.tpl"} |
Added src/templates/services/edit.tpl version [d94d0f31ac].
> > > > > > > | 1 2 3 4 5 6 7 | {include file="admin/_head.tpl" title="Modifier une activité" current="membres/services" js=1} {include file="services/_nav.tpl" current="index"} {include file="services/_service_form.tpl" legend="Modifier une activité"} {include file="admin/_foot.tpl"} |
Added src/templates/services/fees/_fee_form.tpl version [298d8730a9].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | <?php assert(isset($legend)); assert(isset($csrf_key)); assert(isset($submit_label)); $targets = Entities\Accounting\Account::TYPE_REVENUE; ?> {form_errors} <form method="post" action="{$self_url}" data-focus="1"> <fieldset> <legend>{$legend}</legend> <dl> {input name="label" type="text" required=1 label="Libellé" source=$fee} {input name="description" type="textarea" label="Description" source=$fee} <dt><label for="f_amount_type">Montant de la cotisation</label></dt> {input name="amount_type" type="radio" value="0" label="Gratuite ou prix libre" default=$amount_type} {input name="amount_type" type="radio" value="1" label="Montant fixe ou prix libre conseillé" default=$amount_type} <dd class="amount_type_1"> <dl> {input name="amount" type="money" label="Montant" source=$fee fake_required=1} </dl> </dd> {input name="amount_type" type="radio" value="2" label="Montant variable" default=$amount_type} <dd class="amount_type_2"> <dl> {input name="formula" type="textarea" label="Formule de calcul" source=$fee fake_required=1} <dd class="help"> <a href="https://fossil.kd2.org/garradin/wiki?name=Formule_calcul_activit%C3%A9">Aide sur les formules de calcul</a> </dd> </dl> </dd> <dt><strong>Enregistrement en comptabilité</strong></dt> {input name="accounting" type="checkbox" value="1" label="Enregistrer en comptabilité" default=$accounting_enabled} <dd class="help">Chaque nouvelle inscription de membre dans ce tarif sera enregistrée dans la comptabilité.</dd> </dl> </fieldset> <fieldset class="accounting"> <legend>Enregistrer en comptabilité</legend> {if !count($years)} <p class="error block">Il n'y a aucun exercice ouvert dans la comptabilité, il n'est donc pas possible d'enregistrer les activités dans la comptabilité. Merci de commencer par <a href="{$admin_url}acc/years/new.php">créer un exercice</a>.</p> {else} <dl> <dt><label for="f_id_year">Exercice</label> <b>(obligatoire)</b></dt> <dd> <select id="f_id_year" name="id_year"> {foreach from=$years item="year"} <option value="{$year.id}">{$year.label} — {$year.start_date|date_short} au {$year.end_date|date_short}</option> {/foreach} </select> </dd> {input type="list" target="acc/charts/accounts/selector.php?targets=%s&year=%d"|args:$targets,$fee.id_year name="account" label="Compte à utiliser" default=$account required=1} </dl> {/if} </fieldset> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> <script type="text/javascript"> {literal} (function () { var hide = []; if (!$('#f_amount_type_1').checked) hide.push('.amount_type_1'); if (!$('#f_amount_type_2').checked) hide.push('.amount_type_2'); g.toggle(hide, false); g.toggle('.accounting', $('#f_accounting_1').checked); function togglePeriod() { g.toggle(['.amount_type_1', '.amount_type_2'], false); if (this.checked && this.value == 1) g.toggle('.amount_type_1', true); else if (this.checked && this.value == 2) g.toggle('.amount_type_2', true); } $('#f_amount_type_0').onchange = togglePeriod; $('#f_amount_type_1').onchange = togglePeriod; $('#f_amount_type_2').onchange = togglePeriod; $('#f_accounting_1').onchange = () => { g.toggle('.accounting', $('#f_accounting_1').checked); }; function toggleYearForSelector() { var btn = document.querySelector('#f_account_container button'); btn.value = btn.value.replace(/year=\d+/, 'year=' + y.value); } var y = $('#f_id_year') y.onchange = toggleYearForSelector; toggleYearForSelector(); })(); {/literal} </script> |
Added src/templates/services/fees/delete.tpl version [ab39799ac0].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | {include file="admin/_head.tpl" title="Supprimer un tarif" current="membres/services"} {include file="services/_nav.tpl" current="index"} {include file="common/delete_form.tpl" legend="Supprimer ce tarif ?" warning="Êtes-vous sûr de vouloir supprimer le tarif « %s » ?"|args:$fee.label alert="Attention, cela supprimera également l'historique des membres ayant réglé ce tarif." info="Les écritures comptables liées à l'historique des membres ayant réglé ce tarif ne seront pas supprimées, et la comptabilité demeurera inchangée."} {include file="admin/_foot.tpl"} |
Added src/templates/services/fees/details.tpl version [0b08e607ec].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | {include file="admin/_head.tpl" title="Tarif : %s — Liste des membres inscrits"|args:$fee.label current="membres/services"} {include file="services/_nav.tpl" current="index" current_service=$service service_page="index" current_fee=$fee fee_page=$type} <dl class="cotisation"> <dt>Nombre de membres trouvés</dt> <dd> {$list->count()} <em class="help">(N'apparaît ici que l'inscription la plus récente de chaque membre.)</em> {if $session->canAccess('membres', Membres::DROIT_ADMIN)} {linkbutton href="%s&export=csv"|args:$self_url shape="export" label="Export CSV"} {linkbutton href="%s&export=ods"|args:$self_url shape="export" label="Export tableur"} {/if} </dd> </dl> {include file="common/dynamic_list_head.tpl"} {foreach from=$list->iterate() item="row"} <tr> <th><a href="../../membres/fiche.php?id={$row.id_user}">{$row.identity}</a></th> <td>{if $row.paid}<b class="confirm">Oui</b>{else}<b class="error">Non</b>{/if}</td> <td class="money">{$row.paid_amount|raw|money_currency}</td> <td>{$row.date|date_short}</td> <td class="actions"> {linkbutton shape="user" label="Toutes les activités de ce membre" href="!services/user.php?id=%d"|args:$row.id_user} {linkbutton shape="alert" label="Rappels envoyés" href="!services/reminders/user.php?id=%d"|args:$row.id_user} </td> </tr> {/foreach} </tbody> </table> {pagination url=$list->paginationURL() page=$list.page bypage=$list.per_page total=$list->count()} {include file="admin/_foot.tpl"} |
Added src/templates/services/fees/edit.tpl version [bb26a07f0e].
> > > > > > > | 1 2 3 4 5 6 7 | {include file="admin/_head.tpl" title="%s — Tarifs"|args:$service.label current="membres/services" js=1} {include file="services/_nav.tpl" current="index" current_service=$service service_page="index"} {include file="services/fees/_fee_form.tpl" legend="Modifier un tarif" submit_label="Enregistrer"} {include file="admin/_foot.tpl"} |
Added src/templates/services/fees/index.tpl version [b69a5d85cc].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | {include file="admin/_head.tpl" title="%s — Tarifs"|args:$service.label current="membres/services" js=1} {include file="services/_nav.tpl" current="index" current_service=$service service_page="index"} {if count($list)} <table class="list"> <thead> <th>Tarif</th> <td>Montant</td> <td>Membres à jour et ayant payé</td> <td>Membres expirés</td> <td>Membres en attente de règlement</td> <td></td> </thead> <tbody> {foreach from=$list item="row"} <tr> <th><a href="details.php?id={$row.id}">{$row.label}</a></th> <td> {if $row.formula} Formule {elseif $row.amount} {$row.amount|money_currency|raw} {else} - {/if} </td> <td class="num"><a href="details.php?id={$row.id}">{$row.nb_users_ok}</a></td> <td class="num"><a href="details.php?id={$row.id}&type=expired">{$row.nb_users_expired}</a></td> <td class="num"><a href="details.php?id={$row.id}&type=unpaid">{$row.nb_users_unpaid}</td> <td class="actions"> {linkbutton shape="users" label="Liste des inscrits" href="!services/fees/details.php?id=%d"|args:$row.id} {if $session->canAccess('membres', Membres::DROIT_ADMIN)} {linkbutton shape="edit" label="Modifier" href="!services/fees/edit.php?id=%d"|args:$row.id} {linkbutton shape="delete" label="Supprimer" href="!services/fees/delete.php?id=%d"|args:$row.id} {/if} </td> </tr> {/foreach} </tbody> </table> {else} <p class="block alert">Il n'y a aucun tarif enregistré.</p> {/if} {if $session->canAccess('membres', Membres::DROIT_ADMIN)} {include file="services/fees/_fee_form.tpl" legend="Ajouter un tarif" submit_label="Ajouter" csrf_key="fee_add" fee=null amount_type=0 account=null} {/if} {include file="admin/_foot.tpl"} |
Added src/templates/services/index.tpl version [5f8582b144].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | {include file="admin/_head.tpl" title="Activités et cotisations" current="membres/services" js=1} {include file="services/_nav.tpl" current="index" service=null fee=null} {if isset($_GET['CREATE'])} <p class="block error">Vous devez déjà créer une activité pour pouvoir utiliser cette fonction.</p> {/if} {if count($list)} <table class="list"> <thead> <th>Activité</th> <td>Période</td> <td>Membres à jour</td> <td>Membres expirés</td> <td>Membres en attente de règlement</td> <td></td> </thead> <tbody> {foreach from=$list item="row"} <tr> <th><a href="fees/?id={$row.id}">{$row.label}</a></th> <td> {if $row.duration} {$row.duration} jours {elseif $row.start_date} du {$row.start_date|date_short} au {$row.end_date|date_short} {else} ponctuelle {/if} </td> <td class="num"><a href="details.php?id={$row.id}">{$row.nb_users_ok}</a></td> <td class="num"><a href="details.php?id={$row.id}&type=expired">{$row.nb_users_expired}</a></td> <td class="num"><a href="details.php?id={$row.id}&type=unpaid">{$row.nb_users_unpaid}</a></td> <td class="actions"> {linkbutton shape="menu" label="Tarifs" href="!services/fees/?id=%d"|args:$row.id} {linkbutton shape="users" label="Liste des inscrits" href="!services/details.php?id=%d"|args:$row.id} {if $session->canAccess('membres', Membres::DROIT_ADMIN)} {linkbutton shape="edit" label="Modifier" href="!services/edit.php?id=%d"|args:$row.id} {linkbutton shape="delete" label="Supprimer" href="!services/delete.php?id=%d"|args:$row.id} {/if} </td> </tr> {/foreach} </tbody> </table> {else} <p class="block alert">Il n'y a aucune activité enregistrée.</p> {/if} {if $session->canAccess('membres', Membres::DROIT_ADMIN)} {include file="services/_service_form.tpl" legend="Ajouter une activité" service=null period=0} {/if} {include file="admin/_foot.tpl"} |
Added src/templates/services/payment.tpl version [932b0f801f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | {include file="admin/_head.tpl" title="Enregistrer un règlement" current="membres/services" js=1} {form_errors} <form method="post" action="{$self_url}" data-focus="1"> <fieldset> <legend>Enregistrer un règlement</legend> <dl> <dt>Membre sélectionné</dt> <dd><h3>{$user_name}</h3></dd> <dt><strong>Inscription</strong></dt> {input type="checkbox" name="paid" value="1" default=$su.paid label="Marquer cette inscription comme payée"} {input type="money" name="amount" label="Montant réglé par le membre" required=1} {input type="list" target="acc/charts/accounts/selector.php?targets=%s"|args:$account_targets name="account" label="Compte de règlement" required=1} {input type="text" name="payment_reference" label="Référence de paiement" help="Numéro de chèque, numéro de transaction CB, etc."} </dl> </fieldset> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} |
Added src/templates/services/reminders/_form.tpl version [eed395de27].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>{$legend}</legend> <dl> {input type="select" name="id_service" options=$services_list label="Activité associée au rappel" required=1 source=$reminder} {input type="text" name="subject" required=1 source=$reminder default=$default_subject label="Sujet du message envoyé"} <dt><label for="f_delay_type_0">Délai d'envoi</label> <b title="(Champ obligatoire)">obligatoire</b></dt> {input type="radio" name="delay_type" value=0 default=$delay_type label="Le jour de l'expiration de l'activité"} <dd> {input type="radio" name="delay_type" value=1 default=$delay_type} {input type="number" name="delay_before" min=1 max=999 default=$delay_before size=4} <label for="f_delay_type_1">jours <strong>avant</strong> expiration</label> </dd> <dd> {input type="radio" name="delay_type" value=2 default=$delay_type} {input type="number" name="delay_after" min=1 max=999 size=4 default=$delay_after} <label for="f_delay_type_2">jours <strong>après</strong> expiration</label> </dd> {input type="textarea" name="body" required=1 source=$reminder default=$default_body label="Texte du message envoyé" help="Pour inclure dans le contenu du mail le nom du membre, utilisez #IDENTITE, pour inclure le délai de l'envoi utilisez #NB_JOURS." cols="90" rows="15"} </dl> </fieldset> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> <script type="text/javascript"> {literal} (function () { $('#f_delay_before').onfocus = function () { $('#f_delay_type_1').checked = true; }; $('#f_delay_after').onfocus = function () { $('#f_delay_type_2').checked = true; }; })(); {/literal} </script> |
Added src/templates/services/reminders/delete.tpl version [93a3e36f8e].
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | {include file="admin/_head.tpl" title="Supprimer un rappel automatique" current="membres/services"} {include file="services/_nav.tpl" current="reminders"} {include file="common/delete_form.tpl" legend="Supprimer ce rappel automatique ?" warning="Êtes-vous sûr de vouloir supprimer le rappel « %s » ?"|args:$reminder.subject alert="Attention, cela supprimera également l'historique des emails envoyés par ce rappel."} {include file="admin/_foot.tpl"} |
Added src/templates/services/reminders/details.tpl version [c63967de23].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | {include file="admin/_head.tpl" title="Liste des rappels envoyés" current="membres/services"} {include file="services/_nav.tpl" current="reminders"} <dl class="cotisation"> <dt>Rappel : <em>{$reminder.subject}</em></dt> <dd>Activité : {$service.label}</dd> <dd>Délai d'envoi : {if $reminder.delay > 0}{$reminder.delay} jours après l'expiration{elseif $reminder.delay < 0}{$reminder.delay|abs} jours avant l'expiration{else}le jour de l'expiration{/if}</dd> <dt>Nombre de rappels envoyés</dt> <dd> {$list->count()} </dd> </dl> {include file="common/dynamic_list_head.tpl"} {foreach from=$list->iterate() item="row"} <tr> <th><a href="../../membres/fiche.php?id={$row.id_user}">{$row.identity}</a></th> <td>{$row.email}</td> <td>{$row.date|date_short}</td> <td></td> </tr> {/foreach} </tbody> </table> {pagination url=$list->paginationURL() page=$list.page bypage=$list.per_page total=$list->count()} {include file="admin/_foot.tpl"} |
Added src/templates/services/reminders/edit.tpl version [a097265048].
> > > > > > > | 1 2 3 4 5 6 7 | {include file="admin/_head.tpl" title="Modifier un rappel automatique" current="membres/services" js=1} {include file="services/_nav.tpl" current="reminders"} {include file="services/reminders/_form.tpl" legend="Modifier un rappel automatique" default_subject=null default_body=null} {include file="admin/_foot.tpl"} |
Added src/templates/services/reminders/index.tpl version [82d2df7485].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | {include file="admin/_head.tpl" title="Gestion des rappels automatiques" current="membres/services" js=1} {include file="services/_nav.tpl" current="reminders"} <p class="help"> Les rappels automatiques sont envoyés aux membres disposant d'une adresse e-mail selon le délai défini. Il est possible de définir plusieurs rappels pour une même activité. </p> {if empty($list)} <p class="alert block">Aucun rappel automatique n'est configuré.</p> {else} <table class="list"> <thead> <td>Activité</td> <td>Délai de rappel</td> <th>Sujet</th> <td></td> </thead> <tbody> {foreach from=$list item="reminder"} <tr> <td> {$reminder.service_label} </td> <td> {if $reminder.delay == 0}le jour de l'expiration {else} {$reminder.delay|abs} {if abs($reminder.delay) > 1}jours{else}jour{/if} {if $reminder.delay > 0}après{else}avant{/if} expiration {/if} </td> <th><a href="details.php?id={$reminder.id}">{$reminder.subject}</a></th> <td class="actions"> {linkbutton shape="mail" label="Liste des rappels envoyés" href="!services/reminders/details.php?id=%d"|args:$reminder.id} {linkbutton shape="edit" label="Modifier" href="!services/reminders/edit.php?id=%d"|args:$reminder.id} {linkbutton shape="delete" label="Supprimer" href="!services/reminders/delete.php?id=%d"|args:$reminder.id} </td> </tr> {/foreach} </tbody> </table> {/if} {include file="services/reminders/_form.tpl" legend="Ajouter un rappel automatique" reminder=null delay_type=0 delay_before=15 delay_after=5} {include file="admin/_foot.tpl"} |
Added src/templates/services/save.tpl version [7ba4b95586].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | {include file="admin/_head.tpl" title="Enregistrer un règlement" current="membres/services" js=1} {include file="services/_nav.tpl" current="save" fee=null service=null} {form_errors} <form method="post" action="{$self_url}" data-focus="1"> <fieldset> <legend>Inscrire un membre à une activité</legend> {if !$user_id} <dl> {input type="list" name="user" required=1 label="Sélectionner un membre" default=$selected_user target="membres/selector.php"} </dl> {else} <dl> <dt>Membre sélectionné</dt> <dd><h3>{$user_name}</h3><input type="hidden" name="id_user" value="{$user_id}" /></dd> <dt><label for="f_service_ID">Activité</label> <b>(obligatoire)</b></dt> {foreach from=$grouped_services item="service"} <dd class="radio-btn"> {input type="radio" name="id_service" value=$service.id data-expiry=$service.expiry_date|date_short label=null} <label for="f_id_service_{$service.id}"> <div> <h3>{$service.label}</h3> <p> {if $service.duration} {$service.duration} jours {elseif $service.start_date} du {$service.start_date|date_short} au {$service.end_date|date_short} {else} ponctuelle {/if} </p> {if $service.description} <p class="help"> {$service.description|escape|nl2br} </p> {/if} </div> </label> </dd> {/foreach} </dl> {foreach from=$grouped_services item="service"} <?php if (!count($service->fees)) { continue; } ?> <dl data-service="s{$service.id}"> <dt><label for="f_fee">Tarif</label> <b>(obligatoire)</b></dt> {foreach from=$service.fees key="service_id" item="fee"} <dd class="radio-btn"> {input type="radio" name="id_fee" value=$fee.id data-user-amount=$fee.user_amount data-account=$fee.id_account label=null} <label for="f_id_fee_{$fee.id}"> <div> <h3>{$fee.label}</h3> <p> {if !$fee.user_amount} prix libre ou gratuit {elseif $fee.user_amount && $fee.formula} <strong>{$fee.user_amount|raw|money_currency}</strong> (montant calculé) {elseif $fee.user_amount} <strong>{$fee.user_amount|raw|money_currency}</strong> {/if} </p> {if $fee.description} <p class="help"> {$fee.description|escape|nl2br} </p> {/if} </div> </label> </dd> {/foreach} </dl> {/foreach} </fieldset> <fieldset> <legend>Détails</legend> <dl> {input type="date" name="date" required=1 default=$today label="Date d'inscription"} {input type="date" name="expiry_date" default=$today label="Date d'expiration de l'inscription"} {input type="checkbox" name="paid" value="1" default="1" label="Marquer cette inscription comme payée"} <dd class="help">Décocher cette case pour pouvoir suivre les règlements de personnes qui payent en plusieurs fois. Il sera possible de cocher cette case lorsque le solde aura été réglé.</dd> </dl> </fieldset> <fieldset class="accounting"> <legend>Enregistrement en comptabilité</legend> <dl> {input type="money" name="amount" label="Montant réglé par le membre" fake_required=1 help="En cas de règlement en plusieurs fois il sera possible d'ajouter des règlements via la page de suivi des activités de ce membre."} {input type="list" target="acc/charts/accounts/selector.php?targets=%s"|args:$account_targets name="account" label="Compte de règlement" required=1} {input type="text" name="payment_reference" label="Référence de paiement" help="Numéro de chèque, numéro de transaction CB, etc."} </dl> {/if} </fieldset> <p class="submit"> {csrf_field key=$csrf_key} {if $user_id} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} {else} {button type="submit" name="next" label="Continuer" shape="right" class="main"} {/if} </p> </form> {literal} <script type="text/javascript"> function selectService(elm) { $('[data-service]').forEach((e) => { e.style.display = ('s' + elm.value == e.getAttribute('data-service')) ? 'block' : 'none'; }); $('#f_expiry_date').value = elm.dataset.expiry; var first = document.querySelector('[data-service="s' + elm.value + '"] input[name=id_fee]'); if (first) { first.checked = true; selectFee(first); } } function selectFee(elm) { var amount = parseInt(elm.getAttribute('data-user-amount'), 10); // Toggle accounting part of the form var accounting = elm.getAttribute('data-account') ? true : false; g.toggle('.accounting', accounting); $('#f_amount').required = accounting; // Fill the amount paid by the user if (amount) { $('#f_amount').value = g.formatMoney(amount); } } $('input[name=id_service]').forEach((e) => { e.onchange = () => { selectService(e); }; }); $('input[name=id_fee]').forEach((e) => { e.onchange = () => { selectFee(e); }; }); var selected = document.querySelector('input[name="id_service"]:checked, input[name="id_service"]'); selected.checked = true; g.toggle('.accounting', false); selectService(selected); </script> {/literal} {include file="admin/_foot.tpl"} |
Added src/templates/services/user.tpl version [dbd53507fd].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | {include file="admin/_head.tpl" title="%s — Inscriptions aux activités et cotisations"|args:$user.identite current="membres/services"} <p> {linkbutton href="!membres/fiche.php?id=%d"|args:$user.id label="Retour à la fiche membre" shape="user"} {linkbutton href="!services/save.php?user=%d"|args:$user.id label="Inscrire à une activité" shape="plus"} </p> {form_errors} <dl class="cotisation"> <dt>Statut des inscriptions</dt> {foreach from=$services item="service"} <dd> {$service.label} {if $service.status == -1 && $service.end_date} — terminée {elseif $service.status == -1} — <b class="error">en retard</b> {elseif $service.status == 1 && $service.end_date} — <b class="confirm">en cours</b> {elseif $service.status == 1} — <b class="confirm">à jour</b>{/if} {if $service.status.expiry_date} — expire le {$service.expiry_date|date_short}{/if} {if !$service.paid} — <b class="error">À payer !</b>{/if} </dd> {foreachelse} <dd> Aucune inscription. </dd> {/foreach} <dt>Nombre d'inscriptions pour ce membre</dt> <dd> {$list->count()} {if $session->canAccess('membres', Membres::DROIT_ADMIN)} {linkbutton href="?export=csv" shape="export" label="Export CSV"} {linkbutton href="?export=ods" shape="export" label="Export tableur"} {/if} </dd> </dl> {include file="common/dynamic_list_head.tpl"} {foreach from=$list->iterate() item="row"} <tr> <th>{$row.label}</th> <td>{$row.date|date_short}</td> <td>{$row.expiry|date_short}</td> <td>{$row.fee}</td> <td>{if $row.paid}<b class="confirm">Oui</b>{else}<b class="error">Non</b>{/if}</td> <td>{$row.amount|raw|money_currency}</td> <td class="actions"> {if $session->canAccess('membres', Membres::DROIT_ECRITURE)} {if $row.paid} {linkbutton shape="reset" label="Marquer comme non payé" href="?id=%d&su_id=%d&paid=0"|args:$user.id,$row.id} {else} {linkbutton shape="check" label="Marquer comme payé" href="?id=%d&su_id=%d&paid=1"|args:$user.id,$row.id} {/if} {linkbutton shape="delete" label="Supprimer" href="user_delete.php?id=%d"|args:$row.id} {/if} {if $session->canAccess('compta', Membres::DROIT_ACCES) && $row.id_account} {linkbutton shape="menu" label="Liste des écritures" href="!acc/transactions/service_user.php?id=%d&user=%d"|args:$row.id,$user.id} {/if} {if $session->canAccess('compta', Membres::DROIT_ECRITURE) && $row.id_account} {linkbutton shape="plus" label="Nouveau règlement" href="payment.php?id=%d"|args:$row.id} {/if} </td> </tr> {/foreach} </tbody> </table> {pagination url=$list->paginationURL() page=$list.page bypage=$list.per_page total=$list->count()} {include file="admin/_foot.tpl"} |
Added src/templates/services/user_delete.tpl version [e256118085].
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | {include file="admin/_head.tpl" title="Supprimer une inscription" current="membres/services"} {include file="services/_nav.tpl" current="index"} {include file="common/delete_form.tpl" legend="Supprimer cette inscription ?" warning="Êtes-vous sûr de vouloir supprimer cette inscription ?" info="Les écritures comptables liées à cette inscription ne seront pas supprimées, la comptabilité demeurera inchangée."} {include file="admin/_foot.tpl"} |
Modified src/www/_route.php from [c720a9392c] to [d7347d2841].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php namespace Garradin; if (empty($_SERVER['REQUEST_URI'])) { die('Appel non supporté'); } $uri = $_SERVER['REQUEST_URI']; if ('_route.php' === basename($uri)) { die('Appel interdit'); } if (($pos = strpos($uri, '?')) !== false) { $uri = substr($uri, 0, $pos); } if (file_exists(__DIR__ . $uri)) | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php namespace Garradin; if (empty($_SERVER['REQUEST_URI'])) { die('Appel non supporté'); } $uri = $_SERVER['REQUEST_URI']; if ('_route.php' === basename($uri)) { die('Appel interdit'); } if ('favicon.ico' === basename($uri)) { die(''); } if (($pos = strpos($uri, '?')) !== false) { $uri = substr($uri, 0, $pos); } if (file_exists(__DIR__ . $uri)) |
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 | } elseif (preg_match('!/f/([\d\w]+)/(.+)!', $uri, $match)) { $_GET['id'] = $match[1]; $_GET['file'] = $match[2]; require __DIR__ . '/file.php'; } else { require __DIR__ . '/index.php'; } | > > > > > > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | } elseif (preg_match('!/f/([\d\w]+)/(.+)!', $uri, $match)) { $_GET['id'] = $match[1]; $_GET['file'] = $match[2]; require __DIR__ . '/file.php'; } elseif (preg_match('!/admin/!', $uri, $match)) { require __DIR__ . '/_inc.php'; http_response_code(404); throw new UserException('Cette page n\'existe pas.'); } else { require __DIR__ . '/index.php'; } |
Added src/www/admin/acc/_inc.php version [734ee883db].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <?php namespace Garradin; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $current_year_id = $session->get('acc_year'); if ($current_year_id) { // Check that the year is still valid $current_year = Years::get($current_year_id); if (!$current_year || $current_year->closed) { $current_year_id = null; $session->set('acc_year', null); } } if (!$current_year_id) { $current_year = Years::getCurrentOpenYear(); if ($current_year) { $current_year_id = $current_year->id(); $session->set('acc_year', $current_year_id); } } define('Garradin\CURRENT_YEAR_ID', $current_year_id); $tpl->assign('current_year', $current_year); |
Added src/www/admin/acc/accounts/deposit.php version [aab2604a33].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <?php namespace Garradin; use Garradin\Accounting\Accounts; use Garradin\Accounting\Transactions; use Garradin\Entities\Accounting\Transaction; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); if (!CURRENT_YEAR_ID) { Utils::redirect(ADMIN_URL . 'acc/years/?msg=OPEN'); } $account = Accounts::get((int)qg('id')); if (!$account) { throw new UserException("Le compte demandé n'existe pas."); } $checked = f('deposit') ?: []; $journal = $account->getDepositJournal(CURRENT_YEAR_ID, $checked); $transaction = new Transaction; $transaction->id_year = CURRENT_YEAR_ID; $rules = [ 'deposit' => 'array|required', ]; // Enregistrement des cases cochées if (f('save') && $form->check('acc_deposit_' . $account->id, $rules)) { try { $transaction->importFromDepositForm(); Transactions::saveDeposit($transaction, $journal, f('deposit')); Utils::redirect(ADMIN_URL . 'acc/transactions/details.php?id=' . $transaction->id()); } catch (UserException $e) { $journal = $account->getDepositJournal(CURRENT_YEAR_ID); $form->addError($e->getMessage()); } } $date = new \DateTime; if ($date > $current_year->end_date) { $date = $current_year->end_date; } $target = $account::TYPE_BANK; $tpl->assign(compact( 'account', 'journal', 'date', 'target', 'checked' )); $tpl->display('acc/accounts/deposit.tpl'); |
Added src/www/admin/acc/accounts/index.php version [c826784eaa].
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php namespace Garradin; use Garradin\Accounting\Reports; require_once __DIR__ . '/../_inc.php'; if (!CURRENT_YEAR_ID) { Utils::redirect(ADMIN_URL . 'acc/years/?msg=OPEN'); } $tpl->assign('chart_id', $current_year->id_chart); $tpl->assign('grouped_accounts', Reports::getClosingSumsFavoriteAccounts(['year' => CURRENT_YEAR_ID])); $tpl->display('acc/accounts/index.tpl'); |
Added src/www/admin/acc/accounts/journal.php version [73088600e8].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <?php namespace Garradin; use Garradin\Accounting\Accounts; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $account = Accounts::get((int) qg('id')); if (!$account) { throw new UserException("Le compte demandé n'existe pas."); } $year_id = (int) qg('year') ?: CURRENT_YEAR_ID; if ($year_id === CURRENT_YEAR_ID) { $year = $current_year; } else { $year = Years::get($year_id); if (!$year) { throw new UserException("L'exercice demandé n'existe pas."); } $tpl->assign('year', $year); } $can_edit = $session->canAccess('compta', Membres::DROIT_ADMIN) && !$year->closed; $simple = qg('simple'); // Use simplified view for favourite accounts if (null === $simple) { $simple = (bool) $account->type; } $list = $account->listJournal($year_id, $simple); $list->setTitle(sprintf('Journal - %s - %s', $account->code, $account->label)); $list->loadFromQueryString(); $sum = $account->getSum($year_id, $simple); $tpl->assign(compact('simple', 'year', 'account', 'list', 'sum', 'can_edit')); $tpl->display('acc/accounts/journal.tpl'); |
Added src/www/admin/acc/accounts/reconcile.php version [23e1bbad96].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | <?php namespace Garradin; use Garradin\Accounting\Accounts; use Garradin\Accounting\Transactions; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); if (!CURRENT_YEAR_ID) { Utils::redirect(ADMIN_URL . 'acc/years/?msg=OPEN'); } $account = Accounts::get((int)qg('id')); if (!$account) { throw new UserException("Le compte demandé n'existe pas."); } $start = new \DateTime('first day of this month'); $end = new \DateTime('last day of this month'); $only = (bool) qg('only'); if (null !== qg('start') && null !== qg('end')) { $start = \DateTime::createFromFormat('!d/m/Y', qg('start')); $end = \DateTime::createFromFormat('!d/m/Y', qg('end')); if (!$start || !$end) { $form->addError('La date donnée est invalide.'); } } if ($start < $current_year->start_date || $start > $current_year->end_date || $end < $current_year->start_date || $end > $current_year->end_date) { $start = clone $current_year->start_date; $end = clone $start; $end->modify('last day of this month'); } $journal = $account->getReconcileJournal(CURRENT_YEAR_ID, $start, $end, $only); // Enregistrement des cases cochées $form->runIf(f('save') || f('save_next'), function () use ($journal, $start, $end, $account, $only) { Transactions::saveReconciled($journal, f('reconcile')); if (f('save')) { Utils::redirect(Utils::getSelfURL()); } else { $start->modify('+1 month'); $end->modify('+1 month'); $url = sprintf('%sacc/accounts/reconcile.php?id=%s&start=%s&end=%s&only=%d', ADMIN_URL, $account->id(), $start->format('d/m/Y'), $end->format('d/m/Y'), $only); Utils::redirect($url); } }, 'acc_reconcile_' . $account->id()); $prev = clone $start; $next = clone $start; $prev->modify('-1 month'); $next->modify('+1 month'); if ($next > $current_year->end_date) { $next = null; } if ($prev < $current_year->start_date) { $prev = null; } $self_uri = Utils::getSelfURI(false); if (null !== $prev) { $prev = [ 'date' => $prev, 'url' => sprintf($self_uri . '?id=%d&start=%s&end=%s&only=%d', $account->id, $prev->format('01/m/Y'), $prev->format('t/m/Y'), $only), ]; } if (null !== $next) { $next = [ 'date' => $next, 'url' => sprintf($self_uri . '?id=%d&start=%s&end=%s&only=%d', $account->id, $next->format('01/m/Y'), $next->format('t/m/Y'), $only), ]; } $tpl->assign(compact( 'account', 'start', 'end', 'prev', 'next', 'journal', 'only' )); $tpl->display('acc/accounts/reconcile.tpl'); |
Added src/www/admin/acc/accounts/reconcile_assist.php version [a96b3c063b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | <?php namespace Garradin; use Garradin\Accounting\Accounts; use Garradin\Accounting\Transactions; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); if (!CURRENT_YEAR_ID) { Utils::redirect(ADMIN_URL . 'acc/years/?msg=OPEN'); } $account = Accounts::get((int)qg('id')); if (!$account) { throw new UserException("Le compte demandé n'existe pas."); } $csrf_key = 'acc_reconcile_assist_' . $account->id(); $csv = new CSV_Custom($session, 'acc_reconcile_csv'); $csv->setColumns([ 'label' => 'Libellé', 'date' => 'Date', 'notes' => 'Notes', 'reference' => 'Numéro pièce comptable', 'p_reference' => 'Référence paiement', 'amount' => 'Montant', ]); $csv->setMandatoryColumns(['label', 'date', 'amount']); $form->runIf('cancel', function () use ($csv) { $csv->clear(); }, $csrf_key, Utils::getSelfURL()); $form->runIf(f('upload') && isset($_FILES['file']['name']), function () use ($csv) { $csv->load($_FILES['file']); }, $csrf_key, Utils::getSelfURL()); $form->runIf('assign', function () use ($csv) { $csv->setTranslationTable(f('translation_table')); $csv->skip((int)f('skip_first_line')); }, $csrf_key, Utils::getSelfURL()); $start = null; $end = null; $journal = null; if ($csv->ready()) { foreach ($csv->iterate() as $line => $row) { $date = \DateTime::createFromFormat('!d/m/Y', $row->date); if (!$date) { $form->addError(sprintf('Ligne %d : format de date invalide (%s)', $line, $row->date)); continue; } if ($date < $start) { $start = $date; } if ($date > $end) { $end = $date; } } if ($start < $current_year->start_date || $start > $current_year->end_date) { $start = clone $current_year->start_date; } if ($end < $current_year->start_date || $end > $current_year->end_date) { $end = clone $current_year->end_date; } } if ($start && $end) { $journal = $account->getReconcileJournal(CURRENT_YEAR_ID, $start, $end); } // Enregistrement des cases cochées $form->runIf('save', function () use ($journal, $csv) { Transactions::saveReconciled($journal, f('reconcile')); $csv->clear(); }, $csrf_key, Utils::getSelfURL()); $lines = null; if ($journal && $csv->ready()) { try { $lines = $account->mergeReconcileJournalAndCSV($journal, $csv); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign(compact( 'account', 'start', 'end', 'lines', 'csv', 'csrf_key' )); $tpl->display('acc/accounts/reconcile_assist.tpl'); |
Added src/www/admin/acc/accounts/simple.php version [50a686e3e9].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?php namespace Garradin; use Garradin\Accounting\Transactions; use Garradin\Entities\Accounting\Transaction; require_once __DIR__ . '/../_inc.php'; if (!CURRENT_YEAR_ID) { Utils::redirect(ADMIN_URL . 'acc/years/?msg=OPEN'); } $year = $current_year; $types = [ Transaction::TYPE_REVENUE => 'Recettes', Transaction::TYPE_EXPENSE => 'Dépenses', Transaction::TYPE_TRANSFER => 'Virements', Transaction::TYPE_DEBT => 'Dettes', Transaction::TYPE_CREDIT => 'Créances', Transaction::TYPE_ADVANCED => 'Saisies avancées', ]; $type = qg('type') ?? Transaction::TYPE_REVENUE; if (!array_key_exists($type, $types)) { $type = key($types); } $list = Transactions::listByType(CURRENT_YEAR_ID, $type); $list->setTitle(sprintf('Suivi - %s', $types[$type])); $list->loadFromQueryString(); $can_edit = $session->canAccess('compta', Membres::DROIT_ADMIN) && !$year->closed; $tpl->assign(compact('type', 'list', 'types', 'can_edit', 'year')); $tpl->display('acc/accounts/simple.tpl'); |
Added src/www/admin/acc/charts/accounts/all.php version [f7050bf620].
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php namespace Garradin; use Garradin\Accounting\Charts; require_once __DIR__ . '/../../_inc.php'; $chart = null; if ($id = (int)qg('id')) { $chart = Charts::get($id); } elseif (CURRENT_YEAR_ID) { $year = $current_year; $chart = $year->chart(); } if (!$chart) { throw new UserException('Aucun plan comptable spécifié'); } $accounts = $chart->accounts(); $tpl->assign('chart', $chart); $tpl->assign('accounts', $accounts->listAll()); $tpl->display('acc/charts/accounts/all.tpl'); |
Added src/www/admin/acc/charts/accounts/delete.php version [6c837a3adc].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <?php namespace Garradin; use Garradin\Accounting\Accounts; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $account = Accounts::get((int) qg('id')); if (!$account) { throw new UserException("Le compte demandé n'existe pas."); } $chart = $account->chart(); if ($chart->archived) { throw new UserException("Il n'est pas possible de modifier un compte d'un plan comptable archivé."); } if (($chart->code && !$account->user) || !$account->canDelete()) { throw new UserException("Ce compte ne peut être supprimé car des écritures y sont liées (peut-être sur l'exercice courant ou sur un exercice clôt).\nSi vous souhaitez faire du ménage dans la liste des comptes il est recommandé de créer un nouveau comptable."); } if (f('delete') && $form->check('acc_accounts_delete_' . $account->id())) { try { $page = ''; if (!$account->type) { $page = 'all.php'; } $account->delete(); Utils::redirect(sprintf('%sacc/charts/accounts/%s?id=%d', ADMIN_URL, $page, $account->id_chart)); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign(compact('account')); $tpl->display('acc/charts/accounts/delete.tpl'); |
Added src/www/admin/acc/charts/accounts/edit.php version [cd87e2dec4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | <?php namespace Garradin; use Garradin\Accounting\Accounts; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $account = Accounts::get((int) qg('id')); if (!$account) { throw new UserException("Le compte demandé n'existe pas."); } $chart = $account->chart(); if ($chart->archived) { throw new UserException("Il n'est pas possible de modifier un compte d'un plan comptable archivé."); } $edit_disabled = !$account->canEdit(); if (f('edit') && $form->check('acc_accounts_edit_' . $account->id())) { try { if ($edit_disabled) { $account->importLimitedForm(); } else { $account->importForm(); } $account->save(); $page = ''; if (!$account->type) { $page = 'all.php'; } Utils::redirect(sprintf('%sacc/charts/accounts/%s?id=%d', ADMIN_URL, $page, $account->id_chart)); } catch (UserException $e) { $form->addError($e->getMessage()); } } $types = $account::TYPES_NAMES; $types[0] = '-- Pas un compte favori'; $tpl->assign(compact('types', 'account', 'edit_disabled')); $tpl->display('acc/charts/accounts/edit.tpl'); |
Added src/www/admin/acc/charts/accounts/index.php version [5e00b51e32].
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php namespace Garradin; use Garradin\Accounting\Charts; require_once __DIR__ . '/../../_inc.php'; $chart = null; if ($id = (int)qg('id')) { $chart = Charts::get($id); } elseif (CURRENT_YEAR_ID) { $year = $current_year; $chart = $year->chart(); } if (!$chart) { throw new UserException('Aucun plan comptable spécifié'); } $accounts = $chart->accounts(); $tpl->assign('chart', $chart); $tpl->assign('accounts_grouped', $accounts->listCommonGrouped()); $tpl->display('acc/charts/accounts/index.tpl'); |
Added src/www/admin/acc/charts/accounts/new.php version [9b98b97dd0].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | <?php namespace Garradin; use Garradin\Entities\Accounting\Account; use Garradin\Accounting\Accounts; use Garradin\Accounting\Charts; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $chart = Charts::get((int)qg('id')); if (!$chart) { throw new UserException('Ce plan comptable n\'existe pas'); } if ($chart->archived) { throw new UserException("Il n'est pas possible de modifier un plan comptable archivé."); } $account = new Account; $account->position = Account::ASSET_OR_LIABILITY; $types = $account::TYPES_NAMES; $types[0] = '-- Pas un compte favori'; $translate_type_position = [ Account::TYPE_REVENUE => Account::REVENUE, Account::TYPE_EXPENSE => Account::EXPENSE, ]; $translate_type_codes = $chart->accounts()->getNextCodesForTypes(); $simple = false; // Simple creation with pre-determined account type if ($type = (int)qg('type')) { $account->type = $type; $simple = true; $types = array_slice($types, 1, null, true); if (isset($translate_type_codes[$type])) { $account->code = $translate_type_codes[$type]; } } if (f('save') && $form->check('acc_accounts_new')) { try { if ($simple) { $account->importSimpleForm($translate_type_position, $translate_type_codes); } else { $account->importForm(); } $account->id_chart = $chart->id(); $account->user = 1; $account->save(); $page = ''; if (!$account->type) { $page = 'all.php'; } Utils::redirect(sprintf('%sacc/charts/accounts/%s?id=%d', ADMIN_URL, $page, $account->id_chart)); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign(compact('simple', 'types', 'account', 'translate_type_position', 'translate_type_codes', 'chart')); $tpl->display('acc/charts/accounts/new.tpl'); |
Added src/www/admin/acc/charts/accounts/selector.php version [df203fcddd].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php namespace Garradin; use Garradin\Entities\Accounting\Account; use Garradin\Accounting\Charts; use Garradin\Accounting\Years; require_once __DIR__ . '/../../_inc.php'; header('X-Frame-Options: SAMEORIGIN', true); $targets = qg('targets'); $chart = qg('chart'); // Cache the page until the charts have changed $hash = sha1($targets . $chart); $expiry = Config::getInstance()->get('last_chart_change') ?: time(); Utils::HTTPCache($hash, $expiry); if ($chart) { $chart = Charts::get((int)qg('chart')); } elseif (qg('year')) { $year = Years::get((int)qg('year')); if ($year) { $chart = $year->chart(); } } elseif ($current_year) { $chart = $current_year->chart(); } if (!$chart) { throw new UserException('Aucun exercice ouvert disponible'); } $accounts = $chart->accounts(); $tpl->assign(compact('chart', 'targets')); if (!$targets) { $tpl->assign('accounts', $accounts->listAll()); } else { $tpl->assign('grouped_accounts', $accounts->listCommonGrouped(explode(':', $targets))); } $tpl->display('acc/charts/accounts/selector.tpl'); |
Added src/www/admin/acc/charts/delete.php version [35b792e76d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <?php namespace Garradin; use Garradin\Accounting\Charts; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $chart = Charts::get((int) qg('id')); if (!$chart) { throw new UserException("Le plan comptable demandé n'existe pas."); } if (!$chart->canDelete()) { throw new UserException("Ce plan comptable ne peut être supprimé car il est lié à des exercices"); } if (f('delete') && $form->check('acc_charts_delete_' . $chart->id())) { try { $chart->delete(); Utils::redirect(sprintf('%sacc/charts/', ADMIN_URL)); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign(compact('chart')); $tpl->display('acc/charts/delete.tpl'); |
Added src/www/admin/acc/charts/edit.php version [e0ba778302].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <?php namespace Garradin; use Garradin\Accounting\Charts; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $chart = Charts::get((int) qg('id')); if (!$chart) { throw new UserException("Le plan comptable demandé n'existe pas."); } if (f('save') && $form->check('acc_charts_edit_' . $chart->id())) { try { $chart->importForm(); $chart->save(); Utils::redirect(sprintf('%sacc/charts/', ADMIN_URL)); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign(compact('chart')); $tpl->assign('country_list', Utils::getCountryList()); $tpl->display('acc/charts/edit.tpl'); |
Added src/www/admin/acc/charts/export.php version [34dc474779].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php namespace Garradin; use Garradin\Accounting\Charts; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $chart = Charts::get((int) qg('id')); if (!$chart) { throw new UserException("Le plan comptable demandé n'existe pas."); } CSV::export( null !== qg('ods') ? 'ods' : 'csv', sprintf('Plan comptable - %s - %s', Config::getInstance()->get('nom_asso'), $chart->label), $chart->accounts()->export() ); |
Added src/www/admin/acc/charts/import.php version [db18f89e13].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?php namespace Garradin; use Garradin\Accounting\Accounts; use Garradin\Accounting\Charts; use Garradin\Entities\Accounting\Chart; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); if (f('import') && $form->check('acc_charts_import', ['file' => 'file|required'])) { try { $chart = new Chart; $chart->importForm(); $chart->save(); $chart->accounts()->importUpload($_FILES['file']); // This will save everything Utils::redirect(ADMIN_URL . 'acc/charts/'); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign('columns', implode(', ', Accounts::EXPECTED_CSV_COLUMNS)); $tpl->assign('country_list', Utils::getCountryList()); $tpl->display('acc/charts/import.tpl'); |
Added src/www/admin/acc/charts/index.php version [78edbd5354].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?php namespace Garradin; use Garradin\Entities\Accounting\Chart; use Garradin\Accounting\Charts; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $tpl->assign('list', Charts::list()); if ($session->canAccess('compta', Membres::DROIT_ADMIN)) { if (f('new') && $form->check('acc_charts_new')) { try { $chart = new Chart; $chart->importForm(); $chart->save(); if (f('copy')) { $chart->accounts()->copyFrom((int) f('copy')); } Utils::redirect(Utils::getSelfURI(false)); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign('from', (int)qg('from')); $tpl->assign('charts_groupped', Charts::listByCountry()); $tpl->assign('country_list', Utils::getCountryList()); } $tpl->display('acc/charts/index.tpl'); |
Added src/www/admin/acc/index.php version [f1d40ee231].
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php namespace Garradin; use Garradin\Accounting\Years; use Garradin\Accounting\Graph; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $tpl->assign('graphs', Graph::URL_LIST); $tpl->assign('years', Years::listOpen()); $tpl->display('acc/index.tpl'); |
Added src/www/admin/acc/reports/_inc.php version [461ecc0cc6].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <?php namespace Garradin; use Garradin\Accounting\Years; use Garradin\Accounting\Accounts; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $criterias = []; if (qg('analytical')) { $account = Accounts::get((int) qg('analytical')); if (!$account) { throw new UserException('Numéro de compte analytique inconnu.'); } $criterias['analytical'] = $account->id(); $tpl->assign('analytical', $account); } if (qg('year')) { $year = Years::get((int) qg('year')); if (!$year) { throw new UserException('Exercice inconnu.'); } $criterias['year'] = $year->id(); $tpl->assign('year', $year); $tpl->assign('close_date', $year->closed ? $year->end_date : time()); } if (!count($criterias)) { throw new UserException('Critère de rapport inconnu.'); } $tpl->assign('criterias_query', http_build_query($criterias)); |
Added src/www/admin/acc/reports/balance_sheet.php version [8ddee02813].
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php namespace Garradin; use Garradin\Accounting\Reports; use Garradin\Entities\Accounting\Account; require_once __DIR__ . '/_inc.php'; $balance = Reports::getBalanceSheet($criterias); $liability = $balance[Account::LIABILITY]; $asset = $balance[Account::ASSET]; $liability_sum = $balance['sums'][Account::LIABILITY]; $asset_sum = $balance['sums'][Account::ASSET]; $tpl->assign(compact('liability', 'asset', 'liability_sum', 'asset_sum')); $tpl->display('acc/reports/balance_sheet.tpl'); |
Added src/www/admin/acc/reports/graph_pie.php version [ca1e3741d3].
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | <?php namespace Garradin; use Garradin\Accounting\Graph; require_once __DIR__ . '/_inc.php'; header('Content-Type: image/svg+xml'); echo Graph::pie(qg('type'), $criterias); |
Added src/www/admin/acc/reports/graph_plot.php version [041f1bcddf].
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | <?php namespace Garradin; use Garradin\Accounting\Graph; require_once __DIR__ . '/_inc.php'; header('Content-Type: image/svg+xml'); echo Graph::plot(qg('type'), $criterias); |
Added src/www/admin/acc/reports/graph_plot_all.php version [d2282ca501].
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | <?php namespace Garradin; use Garradin\Accounting\Graph; require_once __DIR__ . '/../_inc.php'; qv(['type' => 'string|required']); header('Content-Type: image/svg+xml'); echo Graph::plot(qg('type'), [], Graph::MONTHLY_INTERVAL, 600); |
Added src/www/admin/acc/reports/graphs.php version [fc9df953bc].
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace Garradin; use Garradin\Accounting\Years; use Garradin\Accounting\Graph; require_once __DIR__ . '/_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $year = Years::get((int)qg('year')); $tpl->assign('graphs', Graph::URL_LIST); $tpl->assign('year', $year); $tpl->display('acc/reports/graphs.tpl'); |
Added src/www/admin/acc/reports/journal.php version [a5c36b7f16].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | <?php namespace Garradin; use Garradin\Accounting\Reports; require_once __DIR__ . '/_inc.php'; $tpl->assign('journal', Reports::getJournal($criterias)); $tpl->display('acc/reports/journal.tpl'); |
Added src/www/admin/acc/reports/ledger.php version [ea925577f6].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | <?php namespace Garradin; use Garradin\Accounting\Reports; require_once __DIR__ . '/_inc.php'; $tpl->assign('ledger', Reports::getGeneralLedger($criterias)); $tpl->display('acc/reports/ledger.tpl'); |
Added src/www/admin/acc/reports/projects.php version [ebc0bf8009].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php namespace Garradin; use Garradin\Accounting\Accounts; use Garradin\Accounting\Reports; use Garradin\Entities\Accounting\Account; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $by_year = (bool)qg('by_year'); $tpl->assign(compact('by_year')); $tpl->assign('list', Reports::getAnalyticalSums($by_year)); $tpl->assign('analytical_type', Account::TYPE_ANALYTICAL); $tpl->assign('analytical_accounts_count', CURRENT_YEAR_ID ? $current_year->accounts()->countByType(Account::TYPE_ANALYTICAL) : null); $tpl->display('acc/reports/projects.tpl'); |
Added src/www/admin/acc/reports/statement.php version [a66219b6ce].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?php namespace Garradin; use Garradin\Accounting\Reports; use Garradin\Entities\Accounting\Account; require_once __DIR__ . '/_inc.php'; $revenue = Reports::getClosingSumsWithAccounts($criterias + ['position' => Account::REVENUE]); $expense = Reports::getClosingSumsWithAccounts($criterias + ['position' => Account::EXPENSE], null, true); $get_sum = function (array $in): int { $sum = 0; foreach ($in as $row) { $sum += $row->sum; } return abs($sum); }; $revenue_sum = $get_sum($revenue); $expense_sum = $get_sum($expense); $result = $revenue_sum - $expense_sum; $tpl->assign(compact('revenue', 'expense', 'revenue_sum', 'expense_sum', 'result')); $tpl->display('acc/reports/statement.tpl'); |
Added src/www/admin/acc/reports/trial_balance.php version [a483e23c57].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | <?php namespace Garradin; use Garradin\Accounting\Reports; require_once __DIR__ . '/_inc.php'; $tpl->assign('balance', Reports::getClosingSumsWithAccounts($criterias)); $tpl->display('acc/reports/trial_balance.tpl'); |
Added src/www/admin/acc/saved_searches.php version [76dcbfceee].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $target = 'compta'; $search_url = ADMIN_URL . 'acc/search.php'; require __DIR__ . '/../common/saved_searches.php'; |
Added src/www/admin/acc/search.php version [1fddd71e5c].
> > > > > > > > | 1 2 3 4 5 6 7 8 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $target = 'compta'; require __DIR__ . '/../common/search.php'; |
Added src/www/admin/acc/transactions/actions.php version [0ea83417c0].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | <?php namespace Garradin; use Garradin\Accounting\Transactions; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $check = f('check'); if (!$check || !is_array($check)) { throw new UserException('Aucune écriture n\'a été sélectionnée.'); } $transactions = array_unique(array_values($check)); $lines = array_keys($check); $csrf_key = 'acc_actions'; // Delete transactions $form->runIf('delete', function () use ($transactions) { foreach ($transactions as $id) { $transaction = Transactions::get((int) $id); if (!$transaction) { throw new UserException('Cette écriture n\'existe pas'); } $transaction->delete(); } }, $csrf_key, f('from') ?: ADMIN_URL); // Add/remove lines to analytical $form->runIf('change_analytical', function () use ($lines) { $id = f('id_analytical') ?: null; Transactions::setAnalytical($id, $lines); }, $csrf_key, f('from') ?: ADMIN_URL); $from = f('from'); $count = count($check); $extra = compact('check', 'from'); $tpl->assign(compact('csrf_key', 'check', 'count', 'extra')); if (f('action') == 'delete') { $tpl->display('acc/transactions/actions_delete.tpl'); } else { // Get year to get analytical accounts $year = Years::get((int) f('year')); if (!$year) { throw new UserException("Aucun exercice sélectionné."); } $analytical = $year->chart()->accounts()->listAnalytical(); $tpl->assign('analytical_accounts', ['' => '-- Aucun projet'] + $analytical); $tpl->display('acc/transactions/actions_analytical.tpl'); } |
Added src/www/admin/acc/transactions/creator.php version [5ea9d63a0d].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php namespace Garradin; use Garradin\Accounting\Reports; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $u = (new Membres)->get((int)qg('id')); if (!$u) { throw new UserException('Ce membre n\'existe pas'); } $criterias = ['creator' => $u->id]; $tpl->assign('journal', Reports::getJournal($criterias)); $tpl->assign('transaction_creator', $u); $tpl->display('acc/transactions/creator.tpl'); |
Added src/www/admin/acc/transactions/delete.php version [f22c7ed0fd].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?php namespace Garradin; use Garradin\Accounting\Transactions; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $transaction = Transactions::get((int) qg('id')); if (!$transaction) { throw new UserException('Cette écriture n\'existe pas'); } if ($transaction->validated) { throw new UserException('Cette écriture est validée et ne peut être modifiée'); } if (f('delete') && $form->check('acc_delete_' . $transaction->id)) { try { $transaction->delete(); Utils::redirect(ADMIN_URL . 'acc/'); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign('transaction', $transaction); $tpl->display('acc/transactions/delete.tpl'); |
Added src/www/admin/acc/transactions/delete_file.php version [19275e53c5].
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php namespace Garradin; use Garradin\Accounting\Transactions; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $csrf_key = sprintf('acc_delete_file_%d', qg('id')); $redirect = sprintf(ADMIN_URL . 'acc/transactions/details.php?id=%d', qg('from')); require __DIR__ . '/../../common/delete_file.php'; |
Added src/www/admin/acc/transactions/details.php version [6884309cde].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php namespace Garradin; use Garradin\Accounting\Transactions; require_once __DIR__ . '/../_inc.php'; $transaction = Transactions::get((int) qg('id')); if (!$transaction) { throw new UserException('Cette écriture n\'existe pas'); } $tpl->assign('files', $transaction->listFiles()); $tpl->assign('transaction', $transaction); $tpl->assign('tr_year', $transaction->year()); $tpl->assign('creator_name', $transaction->id_creator ? (new Membres)->getNom($transaction->id_creator) : null); $tpl->assign('related_users', $transaction->listLinkedUsers()); $tpl->display('acc/transactions/details.tpl'); |
Added src/www/admin/acc/transactions/edit.php version [4ea18fe075].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | <?php namespace Garradin; use Garradin\Entities\Accounting\Transaction; use Garradin\Accounting\Transactions; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $transaction = Transactions::get((int) qg('id')); if (!$transaction) { throw new UserException('Cette écriture n\'existe pas'); } if ($transaction->validated) { throw new UserException('Cette écriture est validée et ne peut être modifiée'); } $year = Years::get($transaction->id_year); if ($year->closed) { throw new UserException('Cette écriture ne peut être modifiée car elle appartient à un exercice clôturé'); } $chart = $year->chart(); $accounts = $chart->accounts(); $tpl->assign('chart', $chart); $rules = [ 'lines' => 'array|required', ]; if (f('save') && $form->check('acc_edit_' . $transaction->id(), $rules)) { try { $transaction->importFromEditForm(); $transaction->save(); // Append file if (!empty($_FILES['file']['name'])) { $file = Fichiers::upload($_FILES['file']); $file->linkTo(Fichiers::LIEN_COMPTA, $transaction->id()); } // Link members if (null !== f('users') && is_array(f('users'))) { $transaction->updateLinkedUsers(array_keys(f('users'))); } else { // Remove all $transaction->updateLinkedUsers([]); } Utils::redirect(ADMIN_URL . 'acc/transactions/details.php?id=' . $transaction->id()); } catch (UserException $e) { $form->addError($e->getMessage()); } } $types_accounts = []; $lines = []; if (!empty($_POST['lines']) && is_array($_POST['lines'])) { $lines = Utils::array_transpose($_POST['lines']); foreach ($lines as &$line) { $line = (object) $line; $line->credit = Utils::moneyToInteger($line->credit); $line->debit = Utils::moneyToInteger($line->debit); } } else { $lines = $transaction->getLinesWithAccounts(); foreach ($lines as $k => &$line) { $line->account = [$line->id_account => sprintf('%s — %s', $line->account_code, $line->account_name)]; } } if ($transaction->type != Transaction::TYPE_ADVANCED) { $types_accounts = $transaction->getTypesAccounts(); } $amount = $transaction->getLinesCreditSum(); $tpl->assign(compact('transaction', 'lines', 'types_accounts', 'amount')); $tpl->assign('types_details', Transaction::getTypesDetails()); $tpl->assign('chart_id', $chart->id()); $tpl->assign('analytical_accounts', ['' => '-- Aucun'] + $accounts->listAnalytical()); $tpl->assign('linked_users', $transaction->listLinkedUsersAssoc()); $tpl->display('acc/transactions/edit.tpl'); |
Added src/www/admin/acc/transactions/new.php version [7173ab8670].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | <?php namespace Garradin; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Transaction; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ECRITURE); if (!CURRENT_YEAR_ID) { Utils::redirect(ADMIN_URL . 'acc/years/?msg=OPEN'); } $chart = $current_year->chart(); $accounts = $chart->accounts(); $transaction = new Transaction; $transaction->type = -1; $lines = [[], []]; $amount = 0; $payoff_for = qg('payoff_for') ?: f('payoff_for'); // Quick pay-off for debts and credits, directly from a debt/credit details page if ($id = $payoff_for) { $payoff_for = $transaction->payOffFrom($id); if (!$payoff_for) { throw new UserException('Écriture inconnue'); } $amount = $payoff_for->sum; } // Quick transaction from an account journal page if ($id = qg('account')) { $account = $accounts::get($id); if (!$account || $account->id_chart != $current_year->id_chart) { throw new UserException('Ce compte ne correspond pas à l\'exercice comptable ou n\'existe pas'); } $transaction->type = Transaction::getTypeFromAccountType($account->type); $key = sprintf('account_%d_%d', $transaction->type, 0); if (!isset($_POST[$key])) { $_POST[$key] = [$account->id => sprintf('%s — %s', $account->code, $account->label)]; } } elseif (!empty($_POST['lines']) && is_array($_POST['lines'])) { $lines = Utils::array_transpose($_POST['lines']); foreach ($lines as &$line) { $line['credit'] = Utils::moneyToInteger($line['credit']); $line['debit'] = Utils::moneyToInteger($line['debit']); } } if (f('save') && $form->check('acc_transaction_new')) { try { $transaction->id_year = $current_year->id(); $transaction->importFromNewForm(); $transaction->id_creator = $session->getUser()->id; $transaction->save(); // Append file if (!empty($_FILES['file']['name'])) { $file = Fichiers::upload($_FILES['file']); $file->linkTo(Fichiers::LIEN_COMPTA, $transaction->id()); } // Link members if (null !== f('users') && is_array(f('users'))) { $transaction->updateLinkedUsers(array_keys(f('users'))); } $session->set('acc_last_date', f('date')); Utils::redirect(Utils::getSelfURL(false) . '?ok=' . $transaction->id()); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign('date', $session->get('acc_last_date') ?: $current_year->start_date->format('d/m/Y')); $tpl->assign(compact('transaction', 'payoff_for', 'amount', 'lines')); $tpl->assign('payoff_targets', implode(':', [Account::TYPE_BANK, Account::TYPE_CASH, Account::TYPE_OUTSTANDING])); $tpl->assign('ok', (int) qg('ok')); $tpl->assign('types_details', Transaction::getTypesDetails()); $tpl->assign('chart_id', $chart->id()); $tpl->assign('analytical_accounts', ['' => '-- Aucun'] + $accounts->listAnalytical()); $tpl->display('acc/transactions/new.tpl'); |
Added src/www/admin/acc/transactions/service_user.php version [0473be53b7].
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php namespace Garradin; use Garradin\Accounting\Reports; use Garradin\Accounting\Years; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $criterias = ['service_user' => (int)qg('id')]; $tpl->assign('balance', Reports::getClosingSumsWithAccounts($criterias)); $tpl->assign('journal', Reports::getJournal($criterias)); $tpl->assign('user_id', qg('user')); $tpl->display('acc/transactions/service_user.tpl'); |
Added src/www/admin/acc/transactions/user.php version [698de7ba96].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?php namespace Garradin; use Garradin\Accounting\Reports; use Garradin\Accounting\Years; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $u = (new Membres)->get((int)qg('id')); if (!$u) { throw new UserException('Ce membre n\'existe pas'); } $years = Years::listAssoc(); end($years); $year = (int)qg('year') ?: key($years); $criterias = ['user' => $u->id]; $tpl->assign('balance', Reports::getClosingSumsWithAccounts($criterias + ['year' => $year])); $tpl->assign('journal', Reports::getJournal($criterias)); $tpl->assign(compact('years', 'year')); $tpl->assign('transaction_user', $u); $tpl->display('acc/transactions/user.tpl'); |
Added src/www/admin/acc/years/balance.php version [1c5fd61cf1].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | <?php namespace Garradin; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Transaction; use Garradin\Accounting\Reports; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $year = Years::get((int)qg('id')); if (!$year) { throw new UserException('Exercice inconnu.'); } if ($year->closed) { throw new UserException('Impossible de modifier un exercice clôturé.'); } if (f('next') && !f('from_year')) { Utils::redirect('/admin/acc/years/'); } if (f('save') && $form->check('acc_years_balance_' . $year->id())) { try { $transaction = new Transaction; $transaction->importFromBalanceForm($year); $transaction->save(); Utils::redirect(ADMIN_URL . 'acc/transactions/details.php?id=' . $transaction->id()); } catch (UserException $e) { $form->addError($e->getMessage()); } } $previous_year = null; $chart_change = false; $lines = [[]]; $lines_accounts = [[]]; $years = Years::listClosed(); if (!count($years)) { $previous_year = 0; } elseif (null !== f('from_year')) { $previous_year = (int)f('from_year'); $previous_year = Years::get($previous_year); if (!$previous_year) { throw new UserException('Année précédente invalide'); } } if ($previous_year) { $lines = Reports::getClosingSumsWithAccounts(['year' => $previous_year->id(), 'exclude_position' => [Account::EXPENSE, Account::REVENUE]]); if ($previous_year->id_chart != $year->id_chart) { $chart_change = true; $codes = []; foreach ($lines as $line) { $codes[] = $line->code; } $matching_accounts = $year->accounts()->listForCodes($codes); } // Append result $result = Reports::getResult(['year' => $previous_year->id()]); if ($result > 0) { $account = $year->accounts()->getSingleAccountForType(Account::TYPE_POSITIVE_RESULT); } else { $account = $year->accounts()->getSingleAccountForType(Account::TYPE_NEGATIVE_RESULT); } if (!$account) { $account = (object) [ 'id' => null, 'code' => null, 'label' => 'Résultat de l\'exercice', ]; } $lines[] = (object) [ 'sum' => $result, 'id' => $account->id, 'code' => $account->code, 'label' => $account->label, ]; foreach ($lines as $k => &$line) { $line->credit = $line->sum > 0 ? $line->sum : 0; $line->debit = $line->sum < 0 ? abs($line->sum) : 0; if ($chart_change) { if (array_key_exists($line->code, $matching_accounts)) { $acc = $matching_accounts[$line->code]; $line->account_selected = [$acc->id => sprintf('%s — %s', $acc->code, $acc->label)]; } else { $line->account_selected = null; } } else { $line->account_selected = [$line->id => sprintf('%s — %s', $line->code, $line->label)]; } } unset($line); } $tpl->assign(compact('lines', 'years', 'chart_change', 'previous_year', 'year')); $tpl->display('acc/years/balance.tpl'); |
Added src/www/admin/acc/years/close.php version [c2cd93158e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <?php namespace Garradin; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $year = Years::get((int)qg('id')); if (!$year) { throw new UserException('Exercice inconnu.'); } if ($year->closed) { throw new UserException('Impossible de modifier un exercice clôturé.'); } $rules = [ 'end_date' => 'date_format:d/m/Y|required', ]; if (f('close') && $form->check('acc_years_close_' . $year->id())) { try { $year->close($user->id); $year->save(); $session->set('acc_year', null); Utils::redirect(ADMIN_URL . 'acc/years/'); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign('year', $year); $tpl->display('acc/years/close.tpl'); |
Added src/www/admin/acc/years/delete.php version [1f309cbc2f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php namespace Garradin; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $year = Years::get((int)qg('id')); if (!$year) { throw new UserException('Exercice inconnu.'); } if ($year->closed) { throw new UserException('Impossible de supprimer un exercice clôturé.'); } $form->runIf(f('delete') && f('confirm_delete'), function () use ($year) { $year->delete(); }, 'acc_years_delete_' . $year->id(), ADMIN_URL . 'acc/years/'); $tpl->assign('nb_transactions', $year->countTransactions()); $tpl->assign('year', $year); $tpl->display('acc/years/delete.tpl'); |
Added src/www/admin/acc/years/edit.php version [43b8da34f3].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?php namespace Garradin; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $year = Years::get((int)qg('id')); if (!$year) { throw new UserException('Exercice inconnu.'); } if ($year->closed) { throw new UserException('Impossible de modifier un exercice clôturé.'); } if (f('edit') && $form->check('acc_years_edit_' . $year->id())) { try { $year->importForm(); $year->save(); Utils::redirect(ADMIN_URL . 'acc/years/'); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign('year', $year); $tpl->display('acc/years/edit.tpl'); |
Added src/www/admin/acc/years/import.php version [3baf406550].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | <?php namespace Garradin; use Garradin\Accounting\Transactions; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $year_id = (int) qg('id') ?: CURRENT_YEAR_ID; if ($year_id === CURRENT_YEAR_ID) { $year = $current_year; } else { $year = Years::get($year_id); if (!$year) { throw new UserException("L'exercice demandé n'existe pas."); } } if (qg('export')) { CSV::export( qg('export'), sprintf('Export comptable - %s - %s', Config::getInstance()->get('nom_asso'), $year->label), Transactions::export($year->id()) ); exit; } if ($year->closed) { throw new UserException('Impossible de modifier un exercice clôturé.'); } $csv = new CSV_Custom($session, 'acc_import_year'); $csv->setColumns(Transactions::POSSIBLE_CSV_COLUMNS); $csv->setMandatoryColumns(Transactions::MANDATORY_CSV_COLUMNS); if (f('cancel')) { $csv->clear(); Utils::redirect(Utils::getSelfURL()); } $csrf_key = 'acc_years_import_' . $year->id(); $form->runIf(f('assign') && $csv->loaded(), function () use ($csv, $year, $user) { $csv->skip(f('skip_first_line')); $csv->setTranslationTable(f('translation_table')); Transactions::importCustom($year, $csv, $user->id); $csv->clear(); }, $csrf_key, ADMIN_URL . 'acc/years/'); $form->runIf('load', function () use ($csv, $year, $user) { if (f('type') == 'garradin') { Transactions::importCSV($year, $_FILES['file'], $user->id); Utils::redirect(ADMIN_URL . 'acc/years/'); } elseif (isset($_FILES['file']['tmp_name'])) { $csv->load($_FILES['file']); Utils::redirect(Utils::getSelfURI()); } else { throw new UserException('Fichier invalide'); } }, $csrf_key, Utils::getSelfURI()); $tpl->assign(compact('csv', 'year', 'csrf_key')); $tpl->display('acc/years/import.tpl'); |
Added src/www/admin/acc/years/index.php version [7a17ddf96c].
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php namespace Garradin; use Garradin\Accounting\Years; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ACCES); $years = new Years; $tpl->assign('list', $years->list(true)); $tpl->display('acc/years/index.tpl'); |
Added src/www/admin/acc/years/new.php version [52e738c176].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?php namespace Garradin; use Garradin\Accounting\Years; use Garradin\Accounting\Charts; use Garradin\Entities\Accounting\Year; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); if (f('new') && $form->check('acc_years_new')) { try { $year = new Year; $year->importForm(); $year->save(); if (Years::countClosed()) { Utils::redirect(ADMIN_URL . 'acc/years/balance.php?id=' . $year->id()); } else { Utils::redirect(ADMIN_URL . 'acc/years/'); } } catch (UserException $e) { $form->addError($e->getMessage()); } } $new_dates = Years::getNewYearDates(); $tpl->assign('start_date', $new_dates[0]); $tpl->assign('end_date', $new_dates[1]); $tpl->assign('charts', Charts::listByCountry()); $tpl->display('acc/years/new.tpl'); |
Added src/www/admin/acc/years/select.php version [5863923d36].
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php namespace Garradin; use Garradin\Accounting\Years; require_once __DIR__ . '/../../_inc.php'; $years = new Years; if (f('change')) { $year = Years::get(f('year')); if (!$year) { throw new UserException('Exercice inconnu'); } $session->set('acc_year', $year->id()); Utils::redirect(f('from') ?: ADMIN_URL . 'acc/years/'); } $tpl->assign('list', $years->listOpen()); $tpl->assign('from', qg('from')); $tpl->display('acc/years/select.tpl'); |
Added src/www/admin/common/delete_file.php version [f9d6581182].
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php namespace Garradin; use Garradin\Services\Services; if (!defined('Garradin\ROOT')) { die('Access denied.'); } if (!isset($csrf_key, $redirect)) { throw new \InvalidArgumentException('Missing params'); } $file = new Fichiers(qg('id')); if (!$file->checkAccess($session)) { throw new UserException('Vous n\'avez pas accès à ce fichier.'); } $form->runIf('delete', function () use ($file) { $file->remove(); }, $csrf_key, $redirect); $tpl->assign(compact('file', 'csrf_key')); $tpl->display('common/delete_file.tpl'); |
Added src/www/admin/common/saved_searches.php version [e1f8499fe1].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; if (empty($target) || !in_array($target, Recherche::TARGETS)) { throw new UserException('Cible inconnue'); } $recherche = new Recherche; $mode = null; if (qg('edit') || qg('delete') || qg('duplicate')) { $r = $recherche->get(qg('edit') ?: (qg('delete') ?: qg('duplicate'))); if (!$r) { throw new UserException('Recherche non trouvée'); } if ($r->id_membre !== null && $r->id_membre != $user->id) { throw new UserException('Recherche privée appartenant à un autre membre.'); } if (qg('duplicate')) { $recherche->duplicate($r->id); Utils::redirect(Utils::getSelfURI(false)); } $tpl->assign('recherche', $r); $mode = qg('edit') ? 'edit' : 'delete'; } if ($mode == 'edit' && f('save') && $form->check('edit_recherche_' . $r->id)) { try { $recherche->edit($r->id, [ 'intitule' => f('intitule'), 'id_membre' => f('prive') ? $user->id : null, ]); Utils::redirect(Utils::getSelfURI(false)); } catch (UserException $e) { $form->addError($e->getMessage()); } } elseif ($mode == 'delete' && f('delete') && $form->check('del_recherche_' . $r->id)) { $recherche->remove($r->id); Utils::redirect(Utils::getSelfURI(false)); } if (!$mode) { $tpl->assign('liste', $recherche->getList($user->id, $target)); } $tpl->assign(compact('mode', 'target', 'search_url')); $tpl->display('common/search/saved_searches.tpl'); |
Added src/www/admin/common/search.php version [19bc74c76e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | <?php namespace Garradin; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; if (empty($target) || !in_array($target, Recherche::TARGETS)) { throw new UserException('Cible inconnue'); } $recherche = new Recherche; $query = (object) [ 'query' => f('q') ? json_decode(f('q'), true) : null, 'order' => f('order'), 'limit' => f('limit') ?: 100, 'desc' => (bool) f('desc'), ]; $text_query = trim(qg('qt')); $result = null; $sql_query = null; $search = null; $id = f('id') ?: qg('id'); // Recherche simple if ($text_query !== '' && $target === 'membres' && empty($query->query)) { $query = $recherche->buildSimpleMemberQuery($text_query); } // Recherche existante elseif ($id && empty($query->query)) { $search = $recherche->get($id); if (!$search) { throw new UserException('Recherche inconnue ou invalide'); } if ($search->type === Recherche::TYPE_SQL) { $sql_query = $search->contenu; } else { $query = $search->query; $query->limit = (int) f('limit') ?: $query->limit; } } // Recherche SQL if (f('sql_query')) { // Only admins can run custom queries, others can only run saved queries $session->requireAccess($target, Membres::DROIT_ADMIN); $sql_query = f('sql_query'); } // Execute search if ($query->query || $sql_query) { try { if ($sql_query) { $sql = $sql_query; } else { $sql = $recherche->buildQuery($target, $query->query, $query->order, $query->desc, $query->limit); } $result = $recherche->searchSQL($target, $sql); } catch (UserException $e) { $form->addError($e->getMessage()); } if (f('to_sql')) { $sql_query = $sql; } } if (null !== $result) { if (count($result) == 1 && $text_query !== '' && $target === 'membres') { Utils::redirect(ADMIN_URL . 'membres/fiche.php?id=' . (int)$result[0]->id); } if (f('save') && !$form->hasErrors()) { $type = $sql_query ? Recherche::TYPE_SQL : Recherche::TYPE_JSON; if ($id) { $recherche->edit($id, [ 'type' => $type, 'contenu' => $sql_query ?: $query, ]); } else { $label = $sql_query ? 'Recherche SQL du ' : 'Recherche avancée du '; $label .= date('d/m/Y à H:i:s'); $id = $recherche->add($label, $user->id, $type, $target, $sql_query ?: $query); } $url = $target == 'compta' ? '/admin/acc/saved_searches.php?id=' : '/admin/membres/recherches.php?id='; Utils::redirect($url . $id); } $tpl->assign('result_header', $recherche->getResultHeader($target, $result)); } elseif ($target === 'membres') { $query->query = [[ 'operator' => 'AND', 'conditions' => [ [ 'column' => $config->get('champ_identite'), 'operator' => '= ?', 'values' => [''], ], ], ]]; $result = null; } elseif ($target === 'compta') { $years = Years::list(); $query->query = [[ 'operator' => 'AND', 'conditions' => [ [ 'column' => 't.id_year', 'operator' => '= ?', 'values' => [qg('year')], ], [ 'column' => 't.reference', 'operator' => 'LIKE %?%', 'values' => '', ], ], ]]; $query->desc = true; $result = null; } $columns = $recherche->getColumns($target); $is_admin = $session->canAccess($target, Membres::DROIT_ADMIN); $schema = $recherche->schema($target); $tpl->assign(compact('query', 'sql_query', 'result', 'columns', 'is_admin', 'schema', 'search')); if ($target == 'compta') { $tpl->display('acc/search.tpl'); } else { $tpl->display('admin/membres/recherche.tpl'); } |
Deleted src/www/admin/compta/_inc.php version [da7b17d045].
|
| < < < < < < < < < < < < < |
Deleted src/www/admin/compta/banques/index.php version [9e1fc41443].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/banques/modifier.php version [580b266350].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/banques/rapprocher.php version [141e71f932].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/banques/supprimer.php version [a80679a404].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/categories/ajouter.php version [ccc6c6987b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/categories/index.php version [e2ecaf3c11].
|
| < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/categories/modifier.php version [12706d60d1].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/categories/supprimer.php version [db80f3760b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/comptes/ajouter.php version [7be03dc1f5].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/comptes/index.php version [7140f6c1ad].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/comptes/journal.php version [768483fe88].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/comptes/modifier.php version [61a3177e1f].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/comptes/supprimer.php version [6d0ff3b7ef].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/exercices/ajouter.php version [6ab96d643e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/exercices/cloturer.php version [27ad552537].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/exercices/index.php version [631399af3f].
|
| < < < < < < < < < < < |
Deleted src/www/admin/compta/exercices/modifier.php version [566d206828].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/exercices/supprimer.php version [47c6a4fb3d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/graph.php version [1c8c6790d6].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/import.php version [2c5e1fbc3f].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/index.php version [bb0c467a1d].
|
| < < < < < < < < |
Deleted src/www/admin/compta/operations/cotisation.php version [98e2b3f517].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/operations/index.php version [b00c4bb240].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/operations/membre.php version [2f74dbc0da].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/operations/modifier.php version [6e0e877ba5].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/operations/recherche_sql.php version [bece8f5704].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/operations/saisir.php version [20d760aa75].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/operations/supprimer.php version [0f0bd1e03f].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/operations/voir.php version [c847e11f88].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/pie.php version [502f5f0839].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/projets/index.php version [439392048d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/rapports/_inc.php version [73c58d8a9d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/compta/rapports/bilan.php version [a817281776].
|
| < < < < < < < < < |
Deleted src/www/admin/compta/rapports/compte_resultat.php version [4bb5da1833].
|
| < < < < < < < < < < |
Deleted src/www/admin/compta/rapports/grand_livre.php version [f6b332c56d].
|
| < < < < < < < < < |
Deleted src/www/admin/compta/rapports/journal.php version [d73a2c213c].
|
| < < < < < < < < < |
Modified src/www/admin/config/categories/modifier.php from [6a75b928b9] to [79f85734c9].
︙ | ︙ | |||
30 31 32 33 34 35 36 | 'droit_wiki' => 'in:' . $droits, 'droit_compta' => 'in:' . $droits, 'droit_membres' => 'in:' . $droits, 'droit_config' => sprintf('in:%s,%s', Membres::DROIT_ADMIN, Membres::DROIT_AUCUN), 'droit_connexion' => sprintf('in:%s,%s', Membres::DROIT_ACCES, Membres::DROIT_AUCUN), 'droit_inscription' => sprintf('in:%s,%s', Membres::DROIT_ACCES, Membres::DROIT_AUCUN), 'cacher' => 'boolean', | < < | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 'droit_wiki' => 'in:' . $droits, 'droit_compta' => 'in:' . $droits, 'droit_membres' => 'in:' . $droits, 'droit_config' => sprintf('in:%s,%s', Membres::DROIT_ADMIN, Membres::DROIT_AUCUN), 'droit_connexion' => sprintf('in:%s,%s', Membres::DROIT_ACCES, Membres::DROIT_AUCUN), 'droit_inscription' => sprintf('in:%s,%s', Membres::DROIT_ACCES, Membres::DROIT_AUCUN), 'cacher' => 'boolean', ]); if (!$form->hasErrors()) { $data = [ 'nom' => f('nom'), 'droit_wiki' => (int) f('droit_wiki'), 'droit_compta' => (int) f('droit_compta'), 'droit_config' => (int) f('droit_config'), 'droit_membres' => (int) f('droit_membres'), 'droit_connexion' => (int) f('droit_connexion'), 'droit_inscription' => (int) f('droit_inscription'), 'cacher' => (int) f('cacher'), ]; // Ne pas permettre de modifier la connexion, l'accès à la config et à la gestion des membres // pour la catégorie du membre qui édite les catégories, sinon il pourrait s'empêcher // de se connecter ou n'avoir aucune catégorie avec le droit de modifier les catégories ! if ($cat->id == $user->id_categorie) { |
︙ | ︙ | |||
78 79 80 81 82 83 84 | } } $tpl->assign('cat', $cat); $tpl->assign('readonly', $cat->id == $user->id_categorie ? 'disabled="disabled"' : ''); | < < < | 76 77 78 79 80 81 82 83 84 85 | } } $tpl->assign('cat', $cat); $tpl->assign('readonly', $cat->id == $user->id_categorie ? 'disabled="disabled"' : ''); $tpl->assign('membres', new Membres); $tpl->display('admin/config/categories/modifier.tpl'); |
Modified src/www/admin/config/index.php from [149f2778eb] to [1747e0dad6].
︙ | ︙ | |||
9 10 11 12 13 14 15 | $config->set('nom_asso', f('nom_asso')); $config->set('email_asso', f('email_asso')); $config->set('adresse_asso', f('adresse_asso')); $config->set('site_asso', f('site_asso')); $config->set('accueil_wiki', f('accueil_wiki')); $config->set('accueil_connexion', f('accueil_connexion')); $config->set('categorie_membres', f('categorie_membres')); | | < < < < < > > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | $config->set('nom_asso', f('nom_asso')); $config->set('email_asso', f('email_asso')); $config->set('adresse_asso', f('adresse_asso')); $config->set('site_asso', f('site_asso')); $config->set('accueil_wiki', f('accueil_wiki')); $config->set('accueil_connexion', f('accueil_connexion')); $config->set('categorie_membres', f('categorie_membres')); $config->set('champ_identite', f('champ_identite')); $config->set('champ_identifiant', f('champ_identifiant')); $config->set('pays', f('pays')); $config->set('monnaie', f('monnaie')); // N'enregistrer les couleurs que si ce ne sont pas les couleurs par défaut if (f('couleur1') != ADMIN_COLOR1 || f('couleur2') != ADMIN_COLOR2) { $config->set('couleur1', f('couleur1')); $config->set('couleur2', f('couleur2')); } else { $config->set('couleur1', null); $config->set('couleur2', null); } if (trim(f('image_fond')) != '') { $config->set('image_fond', f('image_fond')); } elseif (!f('image_fond') && !$config->get('couleur1') && !$config->get('couleur2')) { $config->set('image_fond', null); } $config->save(); Utils::redirect(ADMIN_URL . 'config/?ok'); } |
︙ | ︙ | |||
65 66 67 68 69 70 71 | $cats = new Membres\Categories; $tpl->assign('membres_cats', $cats->listSimple()); $tpl->assign('champs', $config->get('champs_membres')->getList()); $tpl->assign('couleur1', $config->get('couleur1') ?: ADMIN_COLOR1); $tpl->assign('couleur2', $config->get('couleur2') ?: ADMIN_COLOR2); | > > > > > > > > > > > > > > > | > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | $cats = new Membres\Categories; $tpl->assign('membres_cats', $cats->listSimple()); $tpl->assign('champs', $config->get('champs_membres')->getList()); $tpl->assign('couleur1', $config->get('couleur1') ?: ADMIN_COLOR1); $tpl->assign('couleur2', $config->get('couleur2') ?: ADMIN_COLOR2); $image_fond = ADMIN_BACKGROUND_IMAGE; if ($config->get('image_fond')) { try { $f = new Fichiers($config->get('image_fond')); $image_fond = $f->getURL(); } catch (\InvalidArgumentException $e) { // Fichier qui n'existe pas/plus } } $tpl->assign('background_image_source', $image_fond); $tpl->assign('background_image_default', ADMIN_BACKGROUND_IMAGE); $tpl->assign('couleurs_defaut', [ADMIN_COLOR1, ADMIN_COLOR2]); $tpl->assign('custom_js', ['color_helper.js']); $tpl->display('admin/config/index.tpl'); |
Modified src/www/admin/config/logs.php from [3641ab6b53] to [0375f9087c].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php namespace Garradin; use KD2\ErrorManager; require_once __DIR__ . '/_inc.php'; if (qg('type') == 'errors' && ERRORS_ENABLE_LOG_VIEW) { $reports = ErrorManager::getReportsFromLog(null, qg('id')); $reports = array_reverse($reports, true); foreach ($reports as &$report) { $report->context->date = strtotime($report->context->date); } unset($report); $errors = []; if (qg('id')) { $tpl->assign('id', qg('id')); | > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?php namespace Garradin; use KD2\ErrorManager; require_once __DIR__ . '/_inc.php'; if (qg('type') == 'errors' && ERRORS_ENABLE_LOG_VIEW) { $reports = ErrorManager::getReportsFromLog(null, qg('id')); $reports = array_reverse($reports, true); foreach ($reports as &$report) { $report->context->date = strtotime($report->context->date); } unset($report); $errors = []; if (qg('id')) { if (!count($reports)) { throw new UserException('Erreur inconnue'); } $tpl->assign('id', qg('id')); $tpl->assign('main', reset($reports)); $tpl->assign('reports', $reports); } else { foreach ($reports as $report) { if (!isset($errors[$report->context->id])) |
︙ | ︙ |
Modified src/www/admin/index.php from [5988e390c9] to [3aa5eb7127].
︙ | ︙ | |||
9 10 11 12 13 14 15 | $tpl->assign('categorie', $categorie); $wiki = new Wiki; $page = $wiki->getByURI($config->get('accueil_connexion')); $tpl->assign('page', $page); | < < < < < < < < < < < < < < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | $tpl->assign('categorie', $categorie); $wiki = new Wiki; $page = $wiki->getByURI($config->get('accueil_connexion')); $tpl->assign('page', $page); $tpl->assign('custom_css', ['wiki.css']); $tpl->assign('banniere', Plugin::fireSignal('accueil.banniere', ['user' => $user, 'session' => $session])); $tpl->display('admin/index.tpl'); flush(); // Si pas de cron on réalise les tâches automatisées à ce moment-là // c'est pas idéal mais mieux que rien if (!USE_CRON) { require_once ROOT . '/cron.php'; } |
Modified src/www/admin/install.php from [29602daaba] to [d0c2a835bd].
1 2 3 4 5 6 7 8 9 10 | <?php namespace Garradin; const INSTALL_PROCESS = true; require_once __DIR__ . '/../../include/test_required.php'; require_once __DIR__ . '/../../include/init.php'; Install::checkAndCreateDirectories(); | < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php namespace Garradin; const INSTALL_PROCESS = true; require_once __DIR__ . '/../../include/test_required.php'; require_once __DIR__ . '/../../include/init.php'; Install::checkAndCreateDirectories(); function f($key) { return \KD2\Form::get($key); } $tpl = Template::getInstance(); $tpl->assign('admin_url', ADMIN_URL); |
︙ | ︙ | |||
38 39 40 41 42 43 44 | else { $tpl->assign('disabled', false); if (f('save')) { $form->check('install', [ | < < < | < < | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | else { $tpl->assign('disabled', false); if (f('save')) { $form->check('install', [ 'nom_membre' => 'required', 'email_membre' => 'required|email', 'passe' => 'confirmed|required', ]); if (!$form->hasErrors()) { try { Install::install(f('nom_asso'), f('nom_membre'), f('email_membre'), f('passe')); Utils::redirect(ADMIN_URL . 'login.php'); } catch (UserException $e) { @unlink(DB_FILE); |
︙ | ︙ |
Modified src/www/admin/login.php from [3ef470efd1] to [939e98ed56].
︙ | ︙ | |||
21 22 23 24 25 26 27 | header('Content-Type: image/gif'); echo base64_decode("R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="); exit; } | | | | < | | | < < < > | < | < > > | | < | < | < > | < | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | header('Content-Type: image/gif'); echo base64_decode("R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="); exit; } $champs = $config->get('champs_membres'); $id_field = (object) $champs->get($config->get('champ_identifiant')); $id_field_name = $id_field->title; $form->runIf('login', function () use ($id_field_name, $session) { if (!trim(f('_id'))) { throw new UserException(sprintf('L\'identifiant (%s) n\'a pas été renseigné.', $id_field_name)); } if (!trim(f('password'))) { throw new UserException('Le mot de passe n\'a pas été renseigné.'); } if (!$session->login(f('_id'), f('password'), (bool) f('permanent'))) { throw new UserException(sprintf("Connexion impossible.\nVérifiez votre identifiant (%s) et votre mot de passe.", $id_field_name)); } }, 'login', ADMIN_URL); $tpl->assign('ssl_enabled', empty($_SERVER['HTTPS']) ? false : true); $tpl->assign('prefer_ssl', (bool)PREFER_HTTPS); $tpl->assign('own_https_url', str_replace('http://', 'https://', utils::getSelfURL())); $tpl->assign(compact('id_field_name')); $tpl->assign('changed', qg('changed') !== null); $tpl->display('admin/login.tpl'); |
Deleted src/www/admin/membres/cotisations.php version [d156e1e5bb].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/ajout.php version [b2cc2cef01].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/gestion/modifier.php version [c6ecbc69e3].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/gestion/rappel_modifier.php version [dfb1636402].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/gestion/rappel_supprimer.php version [91fa0c34f6].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/gestion/rappels.php version [d8c9502290].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/gestion/supprimer.php version [c3a9f9323c].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/index.php version [960a734ef2].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/rappels.php version [c3e2281ab7].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/supprimer.php version [298dee0445].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/membres/cotisations/voir.php version [8935c9e002].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/www/admin/membres/fiche.php from [890dac5864] to [1ec254fd3b].
1 2 3 4 5 6 7 8 9 10 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; qv(['id' => 'required|numeric']); $id = (int) qg('id'); $membre = $membres->get($id); | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; use Garradin\Accounting\Transactions; use Garradin\Services\Services_User; require_once __DIR__ . '/_inc.php'; qv(['id' => 'required|numeric']); $id = (int) qg('id'); $membre = $membres->get($id); |
︙ | ︙ | |||
18 19 20 21 22 23 24 | $tpl->assign('champs', $champs->getList()); $cats = new Membres\Categories; $categorie = $cats->get($membre->id_categorie); $tpl->assign('categorie', $categorie); | < | < | < < < < < < < < < | < < | > | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | $tpl->assign('champs', $champs->getList()); $cats = new Membres\Categories; $categorie = $cats->get($membre->id_categorie); $tpl->assign('categorie', $categorie); $tpl->assign('services', Services_User::listDistinctForUser($membre->id)); if ($session->canAccess('compta', Membres::DROIT_ACCES)) { $tpl->assign('transactions_linked', Transactions::countForUser($membre->id)); $tpl->assign('transactions_created', Transactions::countForCreator($membre->id)); } $tpl->assign('membre', $membre); $tpl->display('admin/membres/fiche.tpl'); |
Modified src/www/admin/membres/import.php from [bd11ab09aa] to [34b02fc73c].
︙ | ︙ | |||
16 17 18 19 20 21 22 23 | } elseif (qg('export') == 'ods') { $import->toODS(); exit; } $champs = $config->get('champs_membres')->getAll(); | > | < | | < < < < < | < | < < | < < < | < | < > | | < < < > | | < | > | < | > > > > | > | | < | | | | < | < < < | < < < < < < < < | < < < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | } elseif (qg('export') == 'ods') { $import->toODS(); exit; } $csv = new CSV_Custom($session, 'users_import'); $champs = $config->get('champs_membres')->getAll(); $csrf_key = 'membres_import'; $columns = []; foreach ($champs as $key => $config) { if (!isset($config->title)) { continue; } $columns[$key] = $config->title; } $csv->setColumns($columns); if (f('cancel')) { $csv->clear(); Utils::redirect(Utils::getSelfURL(false)); } $form->runIf(f('import') && $csv->loaded(), function () use ($csv, $import, $user) { $csv->setTranslationTable(f('translation_table')); $csv->skip((int)f('skip_first_line')); $import->fromCustomCSV($csv, $user->id); $csv->clear(); }, $csrf_key, ADMIN_URL . 'membres/import.php?ok'); $form->runIf(f('import') && f('type') == 'garradin' && !empty($_FILES['upload']['tmp_name']), function () use ($import, $user) { $import->fromGarradinCSV($_FILES['upload']['tmp_name'], $user->id); }, $csrf_key, ADMIN_URL . 'membres/import.php?ok'); $form->runIf(f('import') && f('type') == 'custom' && !empty($_FILES['upload']['tmp_name']), function () use ($csv) { $csv->load($_FILES['upload']); }, $csrf_key, ADMIN_URL . 'membres/import.php'); $tpl->assign('ok', null !== qg('ok') ? true : false); $tpl->assign(compact('csv', 'csrf_key')); $tpl->assign('max_upload_size', Utils::getMaxUploadSize()); $tpl->display('admin/membres/import.tpl'); |
Modified src/www/admin/membres/recherche.php from [ed8d36c24a] to [e65f5d600d].
1 2 3 4 5 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; | < | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $target = 'membres'; require __DIR__ . '/../common/search.php'; |
Deleted src/www/admin/membres/recherche_sql.php version [b02dad85af].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/www/admin/membres/recherches.php from [7efc82999d] to [f67fc4e789].
1 2 3 4 5 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < | < < < < < < < < | 1 2 3 4 5 6 7 8 9 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $target = 'membres'; $search_url = ADMIN_URL . 'membres/recherche.php'; require __DIR__ . '/../common/saved_searches.php'; |
Added src/www/admin/membres/selector.php version [88f3f59197].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; header('X-Frame-Options: SAMEORIGIN', true); $text_query = trim(qg('q')); $tpl->assign('list', []); // Recherche simple if ($text_query !== '') { $tpl->assign('list', (new Membres)->quickSearch($text_query)); } $tpl->assign('query', $text_query); $tpl->display('admin/membres/selector.tpl'); |
Deleted src/www/admin/mes_cotisations.php version [8944c5b1e8].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/www/admin/mes_infos_securite.php from [c7676c4b61] to [07c69221f1].
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $confirm = false; if (f('confirm')) { $form->check('edit_me_security', [ 'passe' => 'confirmed|min:6', 'passe_check' => 'required', | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $confirm = false; if (f('confirm')) { $form->check('edit_me_security', [ 'passe' => 'confirmed|min:6', 'passe_check' => 'required', ]); if (f('passe_check') && !$session->checkPassword(f('passe_check'), $user->passe)) { $form->addError('Le mot de passe fourni ne correspond pas au mot de passe actuel. Merci de bien vouloir renseigner votre mot de passe courant pour confirmer les changements.'); } elseif (f('otp_secret') && f('otp_secret') != 'disable' && !f('code')) { |
︙ | ︙ |
Added src/www/admin/my_services.php version [395c086295].
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php namespace Garradin; use Garradin\Services\Services_User; require_once __DIR__ . '/_inc.php'; $tpl->assign('membre', $user); $list = Services_User::perUserList($user->id); $list->loadFromQueryString(); $tpl->assign(compact('list')); $tpl->assign('services', Services_User::listDistinctForUser($user->id)); $tpl->display('my_services.tpl'); |
Added src/www/admin/services/_inc.php version [b575a08455].
> > > > > > > | 1 2 3 4 5 6 7 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('membres', Membres::DROIT_ACCES); |
Added src/www/admin/services/delete.php version [d664c15fa3].
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php namespace Garradin; use Garradin\Services\Services; require_once __DIR__ . '/_inc.php'; $session->requireAccess('membres', Membres::DROIT_ADMIN); $service = Services::get((int) qg('id')); if (!$service) { throw new UserException("Cette activité n'existe pas"); } $csrf_key = 'service_delete_' . $service->id(); $form->runIf('delete', function () use ($service) { $service->delete(); }, $csrf_key, ADMIN_URL . 'services/'); $tpl->assign(compact('service', 'csrf_key')); $tpl->display('services/delete.tpl'); |
Added src/www/admin/services/details.php version [c951b03a28].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?php namespace Garradin; use Garradin\Services\Services; require_once __DIR__ . '/_inc.php'; $session->requireAccess('membres', Membres::DROIT_ACCES); $service = Services::get((int) qg('id')); if (!$service) { throw new UserException("Cette activité n'existe pas"); } $type = qg('type'); if ('unpaid' == $type) { $list = $service->unpaidUsersList(); } elseif ('expired' == $type) { $list = $service->expiredUsersList(); } else { $type = 'paid'; $list = $service->paidUsersList(); } $list->loadFromQueryString(); $tpl->assign(compact('list', 'service', 'type')); $tpl->display('services/details.tpl'); |
Added src/www/admin/services/edit.php version [2bc2174d1a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <?php namespace Garradin; use Garradin\Services\Services; require_once __DIR__ . '/_inc.php'; $session->requireAccess('membres', Membres::DROIT_ADMIN); $service = Services::get((int) qg('id')); if (!$service) { throw new UserException("Cette activité n'existe pas"); } $csrf_key = 'service_edit_' . $service->id(); $form->runIf('save', function () use ($service) { $service->importForm(); $service->save(); }, $csrf_key, ADMIN_URL . 'services/'); if ($service->duration) { $period = 1; } elseif ($service->start_date) { $period = 2; } else { $period = 0; } $tpl->assign(compact('service', 'period', 'csrf_key')); $tpl->display('services/edit.tpl'); |
Added src/www/admin/services/fees/delete.php version [810abad666].
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php namespace Garradin; use Garradin\Services\Fees; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('membres', Membres::DROIT_ADMIN); $fee = Fees::get((int) qg('id')); if (!$fee) { throw new UserException("Ce tarif n'existe pas"); } $csrf_key = 'fee_delete_' . $fee->id(); $form->runIf('delete', function () use ($fee) { $fee->delete(); }, $csrf_key, ADMIN_URL . 'services/fees/?id=' . $fee->id_service); $tpl->assign(compact('fee', 'csrf_key')); $tpl->display('services/fees/delete.tpl'); |
Added src/www/admin/services/fees/details.php version [fb9b7b8df1].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <?php namespace Garradin; use Garradin\Services\Fees; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('membres', Membres::DROIT_ACCES); $fee = Fees::get((int) qg('id')); if (!$fee) { throw new UserException("Ce tarif n'existe pas"); } $type = qg('type'); if ('unpaid' == $type) { $list = $fee->unpaidUsersList(); } elseif ('expired' == $type) { $list = $fee->expiredUsersList(); } else { $type = 'paid'; $list = $fee->paidUsersList(); } $list->loadFromQueryString(); $service = $fee->service(); $tpl->assign(compact('list', 'fee', 'type', 'service')); $tpl->display('services/fees/details.tpl'); |
Added src/www/admin/services/fees/edit.php version [30c90681af].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <?php namespace Garradin; use Garradin\Services\Fees; use Garradin\Accounting\Accounts; use Garradin\Accounting\Years; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('membres', Membres::DROIT_ADMIN); $fee = Fees::get((int) qg('id')); if (!$fee) { throw new UserException("Ce tarif n'existe pas"); } $service = $fee->service(); $csrf_key = 'fee_edit_' . $fee->id(); $form->runIf('save', function () use ($fee) { $fee->importForm(); $fee->save(); }, $csrf_key, ADMIN_URL . 'services/fees/?id=' . $service->id()); if ($fee->amount) { $amount_type = 1; } elseif ($fee->formula) { $amount_type = 2; } else { $amount_type = 0; } $accounting_enabled = (bool) $fee->id_account; $years = Years::listOpen(); $account = $fee->id_account ? [$fee->id_account => Accounts::getSelectorLabel($fee->id_account)] : null; $tpl->assign(compact('service', 'amount_type', 'fee', 'csrf_key', 'account', 'accounting_enabled', 'years')); $tpl->display('services/fees/edit.tpl'); |
Added src/www/admin/services/fees/index.php version [85376d6574].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <?php namespace Garradin; use Garradin\Entities\Accounting\Account; use Garradin\Accounting\Years; use Garradin\Entities\Services\Fee; use Garradin\Services\Services; require_once __DIR__ . '/../_inc.php'; $service = Services::get((int)qg('id')); if (!$service) { throw new UserException("Cette activité n'existe pas"); } $fees = $service->fees(); $form->runIf($session->canAccess('membres', Membres::DROIT_ADMIN) && f('save'), function () use ($service) { $fee = new Fee; $fee->id_service = $service->id(); $fee->importForm(); $fee->save(); }, 'fee_add', ADMIN_URL . 'services/fees/?id=' . $service->id()); $targets = Account::TYPE_REVENUE; $accounting_enabled = false; $years = Years::listOpen(); $tpl->assign(compact('service', 'targets', 'accounting_enabled', 'years')); $tpl->assign('list', $fees->listWithStats()); $tpl->display('services/fees/index.tpl'); |
Added src/www/admin/services/index.php version [8524cc3af6].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php namespace Garradin; use Garradin\Entities\Services\Service; use Garradin\Services\Services; require_once __DIR__ . '/_inc.php'; $csrf_key = 'service_add'; $form->runIf($session->canAccess('membres', Membres::DROIT_ADMIN) && f('save'), function () { $service = new Service; $service->importForm(); $service->save(); Utils::redirect(ADMIN_URL . 'services/fees/?id=' . $service->id()); }, $csrf_key); $tpl->assign(compact('csrf_key')); $tpl->assign('list', Services::listWithStats()); $tpl->display('services/index.tpl'); |
Added src/www/admin/services/payment.php version [a8ad0d0fc0].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?php namespace Garradin; use Garradin\Services\Services_User; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Transaction; require_once __DIR__ . '/_inc.php'; $session->requireAccess('membres', Membres::DROIT_ECRITURE); $su = Services_User::get((int)qg('id')); if (!$su) { throw new UserException("Cette inscription n'existe pas"); } $user_name = (new Membres)->getNom($su->id_user); $csrf_key = 'service_pay'; $form->runIf('save', function () use ($su, $session) { $su->addPayment($session->getUser()->id); if ($su->paid != (bool) f('paid')) { $su->paid = (bool) f('paid'); $su->save(); } Utils::redirect(ADMIN_URL . 'services/user.php?id=' . $su->id_user); }, $csrf_key); $types_details = Transaction::getTypesDetails(); $account_targets = $types_details[Transaction::TYPE_REVENUE]->accounts[1]->targets_string; $tpl->assign(compact('csrf_key', 'account_targets', 'user_name', 'su')); $tpl->display('services/payment.tpl'); |
Added src/www/admin/services/reminders/delete.php version [6e29e0f367].
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php namespace Garradin; use Garradin\Entities\Services\Reminder; use Garradin\Services\Reminders; use Garradin\Services\Services; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('membres', Membres::DROIT_ADMIN); $reminder = Reminders::get((int) qg('id')); if (!$reminder) { throw new UserException("Ce rappel n'existe pas"); } $csrf_key = 'reminder_delete_' . $reminder->id(); $form->runIf('delete', function () use ($reminder) { $reminder->delete(); }, $csrf_key, ADMIN_URL . 'services/reminders/'); $tpl->assign(compact('reminder', 'csrf_key')); $tpl->display('services/reminders/delete.tpl'); |
Added src/www/admin/services/reminders/details.php version [160d90cac6].
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php namespace Garradin; use Garradin\Entities\Services\Reminder; use Garradin\Services\Reminders; use Garradin\Services\Services; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('membres', Membres::DROIT_ADMIN); $reminder = Reminders::get((int) qg('id')); if (!$reminder) { throw new UserException("Ce rappel n'existe pas"); } $list = $reminder->sentList(); $list->loadFromQueryString(); $service = $reminder->service(); $tpl->assign(compact('list', 'reminder', 'service')); $tpl->display('services/reminders/details.tpl'); |
Added src/www/admin/services/reminders/edit.php version [30e7c419dc].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?php namespace Garradin; use Garradin\Entities\Services\Reminder; use Garradin\Services\Reminders; use Garradin\Services\Services; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('membres', Membres::DROIT_ADMIN); $reminder = Reminders::get((int) qg('id')); if (!$reminder) { throw new UserException("Ce rappel n'existe pas"); } $csrf_key = 'reminder_edit_' . $reminder->id(); $form->runIf('save', function () use ($reminder) { $reminder->importForm(); $reminder->save(); }, $csrf_key, ADMIN_URL . 'services/reminders/'); $delay_before = $delay_after = ''; if ($reminder->delay < 0) { $delay_type = 1; $delay_before = abs($reminder->delay); } elseif ($reminder->delay > 0) { $delay_type = 2; $delay_after = abs($reminder->delay); } else { $delay_type = 0; } $services_list = Services::listAssoc(); $tpl->assign(compact('delay_type', 'delay_before', 'delay_after', 'reminder', 'csrf_key', 'services_list')); $tpl->display('services/reminders/edit.tpl'); |
Added src/www/admin/services/reminders/index.php version [98a8dbe0ad].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?php namespace Garradin; use Garradin\Entities\Services\Reminder; use Garradin\Services\Reminders; use Garradin\Services\Services; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('membres', Membres::DROIT_ADMIN); $services_list = Services::listAssoc(); if (!count($services_list)) { Utils::redirect(ADMIN_URL . 'services/?CREATE'); } $csrf_key = 'reminder_add'; $form->runIf('save', function () { $reminder = new Reminder; $reminder->importForm(); $reminder->save(); }, $csrf_key, Utils::getSelfURL()); $list = Reminders::list(); $services_list = Services::listAssoc(); $default_subject = '[#NOM_ASSO] Échéance de cotisation'; $default_body = "Bonjour #IDENTITE,\n\nVotre cotisation arrive à échéance dans #NB_JOURS jours.\n\n" . "Merci de nous contacter pour renouveler votre cotisation.\n\nCordialement.\n\n" . "--\n#NOM_ASSO\n#ADRESSE_ASSO\nE-Mail : #EMAIL_ASSO\nSite web : #SITE_ASSO"; $tpl->assign(compact('csrf_key', 'list', 'services_list', 'default_subject', 'default_body')); $tpl->display('services/reminders/index.tpl'); |
Added src/www/admin/services/save.php version [9b5a2bdf52].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <?php namespace Garradin; use Garradin\Services\Services; use Garradin\Entities\Services\Service_User; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Transaction; require_once __DIR__ . '/_inc.php'; $session->requireAccess('membres', Membres::DROIT_ECRITURE); $user_id = qg('user'); if (!$user_id && ($user_id = f('user'))) { $user_id = @key($user_id); } if (!$user_id) { $user_id = f('id_user'); } $user_id = (int) $user_id ?: null; $user_name = $user_id ? (new Membres)->getNom($user_id) : null; if (!$user_name) { $user_id = null; } $grouped_services = Services::listGroupedWithFees($user_id); if (!count($grouped_services)) { Utils::redirect(ADMIN_URL . 'services/?CREATE'); } $csrf_key = 'service_save'; $form->runIf('save', function () use ($session) { $su = Service_User::saveFromForm($session->getUser()->id); Utils::redirect(ADMIN_URL . 'services/user.php?id=' . $su->id_user); }, $csrf_key); $selected_user = $user_name ? [$user_id => $user_name] : null; $types_details = Transaction::getTypesDetails(); $account_targets = $types_details[Transaction::TYPE_REVENUE]->accounts[1]->targets_string; $today = new \DateTime; $tpl->assign(compact('today', 'grouped_services', 'csrf_key', 'selected_user', 'account_targets', 'user_name', 'user_id')); $tpl->display('services/save.tpl'); |
Added src/www/admin/services/user.php version [e3055067d1].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?php namespace Garradin; use Garradin\Services\Services_User; require_once __DIR__ . '/_inc.php'; $session->requireAccess('membres', Membres::DROIT_ACCES); $user = (new Membres)->get((int) qg('id')); if (!$user) { throw new UserException("Cet utilisateur est introuvable"); } $form->runIf($session->canAccess('membres', Membres::DROIT_ECRITURE) && null !== qg('paid') && qg('su_id'), function () use ($user) { $su = Services_User::get((int) qg('su_id')); if (!$su) { throw new UserException("Cette inscription est introuvable"); } $su->paid = (bool)qg('paid'); $su->save(); }, null, ADMIN_URL . 'services/user.php?id=' . $user->id); $list = Services_User::perUserList($user->id); $list->setTitle(sprintf('Inscriptions — %s', $user->identite)); $list->loadFromQueryString(); $tpl->assign('services', Services_User::listDistinctForUser($user->id)); $tpl->assign(compact('list', 'user')); $tpl->display('services/user.tpl'); |
Added src/www/admin/services/user_delete.php version [c5d8584c97].
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php namespace Garradin; use Garradin\Services\Services_User; require_once __DIR__ . '/_inc.php'; $session->requireAccess('membres', Membres::DROIT_ECRITURE); $su = Services_User::get((int) qg('id')); if (!$su) { throw new UserException("Cette inscription n'existe pas"); } $csrf_key = 'su_delete_' . $su->id(); $user_id = $su->id_user; $form->runIf('delete', function () use ($su) { $su->delete(); }, $csrf_key, ADMIN_URL . 'services/user.php?id=' . $user_id); $tpl->assign(compact('csrf_key')); $tpl->display('services/user_delete.tpl'); |
Modified src/www/admin/static/admin.css from [4d61ee3dc8] to [18c59b252b].
|
| < | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 | @import url("styles/00-reset.css"); @import url("styles/01-layout.css"); @import url("styles/02-common.css"); @import url("styles/03-forms.css"); @import url("styles/04-dialogs.css"); @import url("styles/05-navigation.css"); @import url("styles/06-tables.css"); @import url("styles/10-accounting.css"); |
Added src/www/admin/static/font/config.json version [cec9b888ae].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | { "name": "garradin", "css_prefix_text": "icn-", "css_use_suffix": false, "hinting": true, "units_per_em": 1000, "ascent": 850, "glyphs": [ { "uid": "e45a3da2ebde8bc8e30a873f3bd51f30", "css": "eye", "code": 128065, "src": "elusive" }, { "uid": "d218294e6f9f7191f6b0b3d1ff6239ff", "css": "eye-off", "code": 10539, "src": "elusive" }, { "uid": "484363b699ea1b5c2f827fc0f62f4dca", "css": "search", "code": 128269, "src": "custom_icons", "selected": true, "svg": { "path": "M643 464Q643 361 569 288T393 214 216 288 143 464 216 641 393 714 569 641 643 464ZM929 929Q929 958 907 979T857 1000Q827 1000 807 979L616 788Q516 857 393 857 313 857 240 826T115 742 31 617 0 464 31 312 115 186 240 102 393 71 545 102 671 186 755 312 786 464Q786 587 717 687L908 878Q929 899 929 929Z", "width": 928.6 }, "search": [ "search" ] }, { "uid": "d9d608c26fff5d1d75dc959f185f034d", "css": "check", "code": 9745, "src": "custom_icons", "selected": true, "svg": { "path": "M786 519V696Q786 763 739 810T625 857H161Q94 857 47 810T0 696V232Q0 166 47 119T161 71H625Q660 71 690 85 699 89 700 98 702 108 695 114L668 142Q662 147 655 147 653 147 650 146 637 143 625 143H161Q124 143 98 169T71 232V696Q71 733 98 759T161 786H625Q662 786 688 759T714 696V555Q714 547 719 542L755 507Q761 501 768 501 771 501 775 503 786 507 786 519ZM915 246L460 700Q447 714 429 714T397 700L157 460Q143 447 143 429T157 397L218 335Q232 322 250 322T282 335L429 482 790 121Q803 108 821 108T853 121L915 182Q928 196 928 214T915 246Z", "width": 928.6 }, "search": [ "check" ] }, { "uid": "67dabb31f430a26bd27c25db8daa105b", "css": "user", "code": 128100, "src": "custom_icons", "selected": true, "svg": { "path": "M786 784Q786 851 745 890T637 929H149Q82 929 41 890T0 784Q0 754 2 726T10 665 25 605 49 550 83 505 131 475 193 464Q198 464 217 476T258 503 318 530 393 542 467 530 528 503 569 476 593 464Q627 464 655 475T703 505 737 550 761 605 776 665 784 726 786 784ZM607 286Q607 374 544 437T393 500 241 437 179 286 241 134 393 71 544 134 607 286Z", "width": 785.7 }, "search": [ "user" ] }, { "uid": "9f9457b7ef8733c515e852b738277774", "css": "users", "code": 128106, "src": "custom_icons", "selected": true, "svg": { "path": "M331 500Q241 503 183 571H108Q63 571 31 549T0 483Q0 286 69 286 73 286 94 297T148 321 214 333Q252 333 289 320 286 341 286 357 286 435 331 500ZM929 856Q929 922 888 961T780 1000H292Q224 1000 184 961T143 856Q143 826 145 798T153 737 167 676 191 622 226 577 274 547 336 536Q342 536 360 548T401 574 460 601 536 613 611 601 671 574 712 548 735 536Q770 536 798 547T845 577 880 622 904 676 919 737 927 798 929 856ZM357 143Q357 202 315 244T214 286 113 244 71 143 113 42 214 0 315 42 357 143ZM750 357Q750 446 687 509T536 571 384 509 321 357 384 206 536 143 687 206 750 357ZM1071 483Q1071 526 1040 549T963 571H888Q831 503 741 500 786 435 786 357 786 341 783 320 820 333 857 333 890 333 924 321T978 297 1002 286Q1071 286 1071 483ZM1000 143Q1000 202 958 244T857 286 756 244 714 143 756 42 857 0 958 42 1000 143Z", "width": 1071.4 }, "search": [ "users" ] }, { "uid": "13e9b9898958bd06a926490ec4c78b18", "css": "delete", "code": 10008, "src": "custom_icons", "selected": true, "svg": { "path": "M724 738Q724 760 709 776L633 852Q617 867 595 867T557 852L393 687 229 852Q213 867 191 867T153 852L77 776Q61 760 61 738T77 700L241 536 77 372Q61 356 61 334T77 296L153 220Q169 204 191 204T229 220L393 384 557 220Q573 204 595 204T633 220L709 296Q724 311 724 334T709 372L545 536 709 700Q724 715 724 738Z", "width": 785.7 }, "search": [ "delete" ] }, { "uid": "9856e9f63a26ab792b90c46148459ad7", "css": "plus", "code": 10133, "src": "custom_icons", "selected": true, "svg": { "path": "M786 411V518Q786 540 770 556T732 571H500V804Q500 826 484 841T446 857H339Q317 857 301 841T286 804V571H54Q31 571 16 556T0 518V411Q0 388 16 373T54 357H286V125Q286 103 301 87T339 71H446Q469 71 484 87T500 125V357H732Q754 357 770 373T786 411Z", "width": 785.7 }, "search": [ "plus" ] }, { "uid": "564500b6ab771051a66101066706e552", "css": "minus", "code": 10134, "src": "custom_icons", "selected": true, "svg": { "path": "M786 411V518Q786 540 770 556T732 571H54Q31 571 16 556T0 518V411Q0 388 16 373T54 357H732Q754 357 770 373T786 411Z", "width": 785.7 }, "search": [ "minus" ] }, { "uid": "ef59059d1776e2b5df2cdb61ad02a5c2", "css": "help", "code": 10067, "src": "custom_icons", "selected": true, "svg": { "path": "M393 701V835Q393 844 386 851T371 857H237Q228 857 221 851T214 835V701Q214 692 221 685T237 679H371Q379 679 386 685T393 701ZM569 366Q569 396 561 422T541 465 510 498 478 523 444 542Q421 555 406 579T391 616Q391 626 384 634T368 643H234Q226 643 220 633T214 612V586Q214 540 251 499T330 439Q363 424 377 407T391 365Q391 342 365 324T305 306Q269 306 245 322 225 336 185 386 178 395 168 395 161 395 154 391L63 321Q55 315 54 307T57 291Q146 143 316 143 361 143 406 160T487 206 546 278 569 366Z", "width": 571.4 }, "search": [ "help" ] }, { "uid": "e03a3396ad9ce1b09a85c28955799d92", "css": "home", "code": 8962, "src": "custom_icons", "selected": true, "svg": { "path": "M786 554V821Q786 836 775 847T750 857H536V643H393V857H179Q164 857 154 847T143 821V554Q143 553 143 552T143 550L464 286 785 550Q786 551 786 554ZM910 515L876 556Q871 561 864 562H862Q855 562 850 559L464 237 78 559Q71 563 65 563 58 561 53 556L18 515Q14 510 15 502T21 490L422 156Q440 141 464 141T507 156L643 270V161Q643 153 648 148T661 143H768Q776 143 781 148T786 161V388L908 490Q913 495 914 502T910 515Z", "width": 928.6 }, "search": [ "home" ] }, { "uid": "496e662a65eb5759e19b1c5d2e58a060", "css": "attach", "code": 128206, "src": "custom_icons", "selected": true, "svg": { "path": "M783 773Q783 838 739 882T630 926Q555 926 499 871L65 437Q2 373 2 286 2 198 64 136T214 74Q302 74 366 137L704 475Q709 480 709 487 709 496 692 513T666 530Q659 530 653 525L315 186Q271 143 214 143 155 143 114 185T74 286Q74 344 116 387L549 820Q584 855 630 855 666 855 689 832T713 773Q713 727 677 692L353 368Q339 354 320 354 304 354 293 365T282 392Q282 410 296 425L525 653Q531 659 531 666 531 675 513 692T487 709Q480 709 475 704L246 475Q211 441 211 392 211 346 243 314T320 282Q369 282 403 318L728 642Q783 696 783 773Z", "width": 785.7 }, "search": [ "attach" ] }, { "uid": "e5c7ed71e800e995ddfc3a195924913b", "css": "lock", "code": 128274, "src": "custom_icons", "selected": true, "svg": { "path": "M179 429H464V321Q464 262 422 220T321 179 220 220 179 321V429ZM643 482V804Q643 826 627 841T589 857H54Q31 857 16 841T0 804V482Q0 460 16 444T54 429H71V321Q71 219 145 145T321 71 498 145 571 321V429H589Q612 429 627 444T643 482Z", "width": 642.9 }, "search": [ "lock" ] }, { "uid": "f2a84f66f2d360b9c559376a275261ae", "css": "mail", "code": 9993, "src": "custom_icons", "selected": true, "svg": { "path": "M1000 396V839Q1000 876 974 902T911 929H89Q53 929 26 902T0 839V396Q25 424 56 445 258 582 334 637 366 661 385 674T438 701 499 714H501Q529 714 562 701T615 674 666 637Q761 569 944 445 976 423 1000 396ZM1000 232Q1000 276 973 316T905 385Q695 531 643 566 638 570 620 583T590 605 561 623 528 638 501 643H499Q487 643 472 638T439 623 410 605 380 583 357 566Q306 531 210 465T96 385Q61 362 31 321T0 244Q0 201 23 172T89 143H911Q947 143 973 169T1000 232Z", "width": 1000 }, "search": [ "mail" ] }, { "uid": "49aab36ecf027cc8608f81597c83d2d4", "css": "download", "code": 8659, "src": "custom_icons", "selected": true, "svg": { "path": "M714 750Q714 735 704 725T679 714 653 725 643 750 653 775 679 786 704 775 714 750ZM857 750Q857 735 847 725T821 714 796 725 786 750 796 775 821 786 847 775 857 750ZM929 625V804Q929 826 913 841T875 857H54Q31 857 16 841T0 804V625Q0 603 16 587T54 571H313L388 647Q421 679 464 679T540 647L616 571H875Q897 571 913 587T929 625ZM747 307Q757 330 739 347L489 597Q479 607 464 607T439 597L189 347Q172 330 181 307 191 286 214 286H357V36Q357 21 368 11T393 0H536Q550 0 561 11T571 36V286H714Q738 286 747 307Z", "width": 928.6 }, "search": [ "download" ] }, { "uid": "1ab77fb1c37bad79af7268c79a11b14f", "css": "edit", "code": 9998, "src": "custom_icons", "selected": true, "svg": { "path": "M203 857L253 806 122 675 71 726V786H143V857H203ZM494 339Q494 327 482 327 477 327 473 331L170 633Q166 637 166 643 166 655 179 655 184 655 188 651L491 349Q494 345 494 339ZM464 232L696 464 232 929H0V696ZM845 286Q845 315 825 336L732 429 500 196 593 104Q613 83 643 83 672 83 694 104L825 235Q845 257 845 286Z", "width": 857.1 }, "search": [ "edit" ] }, { "uid": "bf3c88e1a2208a0cf26001e0793ff403", "css": "print", "code": 9113, "src": "custom_icons", "selected": true, "svg": { "path": "M214 857H714V714H214V857ZM214 500H714V286H625Q603 286 587 270T571 232V143H214V500ZM857 536Q857 521 847 511T821 500 796 511 786 536 796 561 821 571 847 561 857 536ZM929 536V768Q929 775 923 780T911 786H786V875Q786 897 770 913T732 929H196Q174 929 159 913T143 875V786H18Q11 786 5 780T0 768V536Q0 492 32 460T107 429H143V125Q143 103 159 87T196 71H571Q594 71 621 83T663 109L748 194Q763 210 775 237T786 286V429H821Q866 429 897 460T929 536Z", "width": 928.6 }, "search": [ "print" ] }, { "uid": "4d879892b0e3a0da5d871e3df8d105e2", "css": "alert", "code": 9888, "src": "custom_icons", "selected": true, "svg": { "path": "M571 767V661Q571 653 566 648T554 643H446Q439 643 434 648T429 661V767Q429 775 434 780T446 786H554Q561 786 566 780T571 767ZM570 559L580 302Q580 296 575 292 568 286 561 286H439Q432 286 425 292 420 296 420 304L429 559Q429 564 435 568T448 571H551Q559 571 564 568T570 559ZM563 37L991 823Q1011 858 990 893 980 910 964 919T929 929H71Q53 929 36 919T10 893Q-11 858 9 823L438 37Q447 20 464 10T500 0 536 10 563 37Z", "width": 1000 }, "search": [ "alert" ] }, { "uid": "7091435c31f7a593060b9782a234db80", "css": "menu", "code": 119650, "src": "custom_icons", "selected": true, "svg": { "path": "M857 750V821Q857 836 847 846T821 857H36Q21 857 11 846T0 821V750Q0 735 11 725T36 714H821Q836 714 847 725T857 750ZM857 464V536Q857 550 847 561T821 571H36Q21 571 11 561T0 536V464Q0 450 11 439T36 429H821Q836 429 847 439T857 464ZM857 179V250Q857 265 847 275T821 286H36Q21 286 11 275T0 250V179Q0 164 11 153T36 143H821Q836 143 847 153T857 179Z", "width": 857.1 }, "search": [ "menu" ] }, { "uid": "08d8ae2e00462d737ce43e77738eee17", "css": "settings", "code": 9784, "src": "custom_icons", "selected": true, "svg": { "path": "M571 500Q571 441 530 399T429 357 328 399 286 500 328 601 429 643 530 601 571 500ZM857 439V563Q857 570 853 576T842 583L738 599Q728 629 717 650 736 677 776 727 782 733 782 740T777 753Q762 774 722 814T669 853Q662 853 655 848L578 788Q553 801 527 809 518 885 511 913 507 929 491 929H367Q359 929 353 924T347 912L331 809Q304 800 281 788L202 848Q196 853 188 853 180 853 174 847 104 783 82 753 78 748 78 740 78 734 83 728 91 716 111 691T141 651Q126 623 118 596L16 581Q9 580 5 574T0 561V437Q0 430 5 424T15 417L119 401Q127 376 141 350 118 318 81 273 75 266 75 259 75 254 80 247 95 227 135 187T188 147Q195 147 203 152L280 212Q304 199 330 191 339 115 347 87 350 72 367 72H491Q498 72 504 76T511 88L526 191Q554 200 576 212L656 152Q661 147 669 147 676 147 683 152 755 219 775 247 779 252 779 260 779 266 775 272 766 284 746 310T716 349Q730 377 739 404L841 419Q848 420 853 426T857 439Z", "width": 857.1 }, "search": [ "settings" ] }, { "uid": "b2af04a5076126cde5606aed07cfd647", "css": "down", "code": 8595, "src": "custom_icons", "selected": true, "svg": { "path": "M571 393Q571 407 561 418L311 668Q300 679 286 679T261 668L11 418Q0 407 0 393T11 368 36 357H536Q550 357 561 368T571 393Z", "width": 571.4 }, "search": [ "down" ] }, { "uid": "9a8f85e9fc8643b2587509f0e4b6cd1e", "css": "up", "code": 8593, "src": "custom_icons", "selected": true, "svg": { "path": "M571 679Q571 693 561 704T536 714H36Q21 714 11 704T0 679 11 653L261 403Q271 393 286 393T311 403L561 653Q571 664 571 679Z", "width": 571.4 }, "search": [ "up" ] }, { "uid": "fe71ca02f0de1b3624d28043ddb30c85", "css": "unlock", "code": 128275, "src": "custom_icons", "selected": true, "svg": { "path": "M929 321V464Q929 479 918 489T893 500H857Q843 500 832 489T821 464V321Q821 262 780 220T679 179 578 220 536 321V429H589Q612 429 627 444T643 482V804Q643 826 627 841T589 857H54Q31 857 16 841T0 804V482Q0 460 16 444T54 429H429V321Q429 218 502 145T679 71 855 145 929 321Z", "width": 928.6 }, "search": [ "unlock" ] }, { "uid": "56000699168af06774cd3f1646acbd5f", "css": "logout", "code": 10525, "src": "custom_icons", "selected": true, "svg": { "path": "M857 500Q857 587 823 666T732 803 595 895 429 929 262 895 126 803 34 666 0 500Q0 398 45 309T171 158Q195 140 225 144T271 172Q289 195 285 225T257 272Q203 313 173 373T143 500Q143 558 165 611T227 702 318 763 429 786 539 763 631 702 692 611 714 500Q714 432 684 373T600 272Q576 254 572 225T586 172Q603 148 633 144T686 158Q767 219 812 309T857 500ZM500 71V429Q500 458 479 479T429 500 378 479 357 429V71Q357 42 378 21T429 0 479 21 500 71Z", "width": 857.1 }, "search": [ "logout" ] }, { "uid": "474656633f79ea2f1dad59ff63f6bf07", "css": "star", "code": 9733, "src": "fontawesome" }, { "uid": "f8aa663c489bcbd6e68ec8147dca841e", "css": "folder", "code": 128448, "src": "fontawesome" }, { "uid": "178053298e3e5b03551d754d4b9acd8b", "css": "document", "code": 128453, "src": "fontawesome" }, { "uid": "f9c3205df26e7778abac86183aefdc99", "css": "reset", "code": 8634, "src": "fontawesome" }, { "uid": "eeec3208c90b7b48e804919d0d2d4a41", "css": "upload", "code": 8657, "src": "fontawesome" }, { "uid": "390d6d13398cbf8c8c3c5493f7d34088", "css": "export", "code": 8631, "src": "entypo" }, { "uid": "531bc468eecbb8867d822f1c11f1e039", "css": "calendar", "code": 128197, "src": "fontawesome" }, { "uid": "4b900d04e8ab8c82f080c1cfbac5772c", "css": "uncheck", "code": 9744, "src": "fontawesome" }, { "uid": "422e07e5afb80258a9c4ed1706498f8a", "css": "radio-unchecked", "code": 9711, "src": "fontawesome" }, { "uid": "81bb68665e8e595505272a746db07c7a", "css": "radio-checked", "code": 11044, "src": "fontawesome" }, { "uid": "c5845105a87df2ee1999826d90622f6a", "css": "paragraph", "code": 167, "src": "fontawesome" }, { "uid": "a2a74f5e7b7d9ba054897d8c795a326a", "css": "list-ul", "code": 8226, "src": "fontawesome" }, { "uid": "f6766a8b042c2453a4e153af03294383", "css": "list-ol", "code": 291, "src": "fontawesome" }, { "uid": "0c708edd8fae2376b3370aa56d40cf9e", "css": "header", "code": 72, "src": "fontawesome" }, { "uid": "a8cb1c217f02b073db3670c061cc54d2", "css": "italic", "code": 73, "src": "fontawesome" }, { "uid": "8fb55fd696d9a0f58f3b27c1d8633750", "css": "table", "code": 9707, "src": "fontawesome" }, { "uid": "cc1de8eafc95f6faffcd8683aa8e9aa1", "css": "bold", "code": 66, "src": "elusive" }, { "uid": "381da2c2f7fd51f8de877c044d7f439d", "css": "image", "code": 128443, "src": "fontawesome" }, { "uid": "d870630ff8f81e6de3958ecaeac532f2", "css": "left", "code": 8592, "src": "fontawesome" }, { "uid": "399ef63b1e23ab1b761dfbb5591fa4da", "css": "right", "code": 8594, "src": "fontawesome" } ] } |
Modified src/www/admin/static/font/garradin.css from [d980f71e5b] to [1274bb9a83].
1 2 3 4 | @charset "UTF-8"; @font-face { font-family: 'garradin'; | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | @charset "UTF-8"; @font-face { font-family: 'garradin'; src: url('../font/garradin.eot?36244460'); src: url('../font/garradin.eot?36244460#iefix') format('embedded-opentype'), url('../font/garradin.woff2?36244460') format('woff2'), url('../font/garradin.woff?36244460') format('woff'), url('../font/garradin.ttf?36244460') format('truetype'), url('../font/garradin.svg?36244460#garradin') format('svg'); font-weight: normal; font-style: normal; } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ /* @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'garradin'; src: url('../font/garradin.svg?36244460#garradin') format('svg'); } } */ [class^="icn-"]:before, [class*=" icn-"]:before { font-family: "garradin"; font-style: normal; font-weight: normal; speak: never; display: inline-block; text-decoration: inherit; width: 1em; margin-right: .2em; text-align: center; /* opacity: .8; */ |
︙ | ︙ | |||
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* Uncomment for 3D effect */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } .icn-up:before { content: '\2191'; } /* '↑' */ .icn-down:before { content: '\2193'; } /* '↓' */ .icn-download:before { content: '\21d3'; } /* '⇓' */ .icn-home:before { content: '\2302'; } /* '⌂' */ .icn-print:before { content: '\2399'; } /* '⎙' */ .icn-check:before { content: '\2611'; } /* '☑' */ .icn-settings:before { content: '\2638'; } /* '☸' */ .icn-alert:before { content: '\26a0'; } /* '⚠' */ .icn-mail:before { content: '\2709'; } /* '✉' */ .icn-edit:before { content: '\270e'; } /* '✎' */ .icn-delete:before { content: '\2718'; } /* '✘' */ .icn-help:before { content: '\2753'; } /* '❓' */ .icn-plus:before { content: '\2795'; } /* '➕' */ .icn-minus:before { content: '\2796'; } /* '➖' */ .icn-logout:before { content: '\291d'; } /* '⤝' */ .icn-eye-off:before { content: '\292b'; } /* '⤫' */ .icn-menu:before { content: '𝍢'; } /* '\1d362' */ .icn-eye:before { content: '👁'; } /* '\1f441' */ .icn-user:before { content: '👤'; } /* '\1f464' */ .icn-users:before { content: '👪'; } /* '\1f46a' */ .icn-attach:before { content: '📎'; } /* '\1f4ce' */ .icn-search:before { content: '🔍'; } /* '\1f50d' */ .icn-lock:before { content: '🔒'; } /* '\1f512' */ .icn-unlock:before { content: '🔓'; } /* '\1f513' */ | > > > > > > > > > > > > > > > > > > > > | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* Uncomment for 3D effect */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } .icn-bold:before { content: '\42'; } /* 'B' */ .icn-header:before { content: '\48'; } /* 'H' */ .icn-italic:before { content: '\49'; } /* 'I' */ .icn-paragraph:before { content: '\a7'; } /* '§' */ .icn-list-ol:before { content: '\0123'; } /* 'ģ' */ .icn-list-ul:before { content: '\2022'; } /* '•' */ .icn-left:before { content: '\2190'; } /* '←' */ .icn-up:before { content: '\2191'; } /* '↑' */ .icn-right:before { content: '\2192'; } /* '→' */ .icn-down:before { content: '\2193'; } /* '↓' */ .icn-export:before { content: '\21b7'; } /* '↷' */ .icn-reset:before { content: '\21ba'; } /* '↺' */ .icn-upload:before { content: '\21d1'; } /* '⇑' */ .icn-download:before { content: '\21d3'; } /* '⇓' */ .icn-home:before { content: '\2302'; } /* '⌂' */ .icn-print:before { content: '\2399'; } /* '⎙' */ .icn-table:before { content: '\25eb'; } /* '◫' */ .icn-radio-unchecked:before { content: '\25ef'; } /* '◯' */ .icn-star:before { content: '\2605'; } /* '★' */ .icn-uncheck:before { content: '\2610'; } /* '☐' */ .icn-check:before { content: '\2611'; } /* '☑' */ .icn-settings:before { content: '\2638'; } /* '☸' */ .icn-alert:before { content: '\26a0'; } /* '⚠' */ .icn-mail:before { content: '\2709'; } /* '✉' */ .icn-edit:before { content: '\270e'; } /* '✎' */ .icn-delete:before { content: '\2718'; } /* '✘' */ .icn-help:before { content: '\2753'; } /* '❓' */ .icn-plus:before { content: '\2795'; } /* '➕' */ .icn-minus:before { content: '\2796'; } /* '➖' */ .icn-logout:before { content: '\291d'; } /* '⤝' */ .icn-eye-off:before { content: '\292b'; } /* '⤫' */ .icn-radio-checked:before { content: '\2b24'; } /* '⬤' */ .icn-menu:before { content: '𝍢'; } /* '\1d362' */ .icn-eye:before { content: '👁'; } /* '\1f441' */ .icn-user:before { content: '👤'; } /* '\1f464' */ .icn-users:before { content: '👪'; } /* '\1f46a' */ .icn-calendar:before { content: '📅'; } /* '\1f4c5' */ .icn-attach:before { content: '📎'; } /* '\1f4ce' */ .icn-search:before { content: '🔍'; } /* '\1f50d' */ .icn-lock:before { content: '🔒'; } /* '\1f512' */ .icn-unlock:before { content: '🔓'; } /* '\1f513' */ .icn-image:before { content: '🖻'; } /* '\1f5bb' */ .icn-folder:before { content: '🗀'; } /* '\1f5c0' */ .icn-document:before { content: '🗅'; } /* '\1f5c5' */ |
Modified src/www/admin/static/font/garradin.eot from [4de801b16e] to [6d9991856c].
cannot compute difference between binary files
Modified src/www/admin/static/font/garradin.svg from [5bcfb6f494] to [91f74fefc9].
1 2 3 | <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg"> | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg"> <metadata>Copyright (C) 2020 by original authors @ fontello.com</metadata> <defs> <font id="garradin" horiz-adv-x="1000" > <font-face font-family="garradin" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" /> <missing-glyph horiz-adv-x="1000" /> <glyph glyph-name="bold" unicode="B" d="M0-60l125 0 0 820-125 0 0 80 582 0q180 0 270-60t89-182q0-88-62-139t-184-64q147-14 226-79t79-173q0-145-111-215-110-68-344-68l-545 0 0 80z m379 0l94 0q125 0 185 49t61 154q0 105-62 157t-184 52l-94 0 0-412z m0 492l86 0q113 0 168 39 55 43 55 127 0 86-55 125-53 37-168 37l-86 0 0-328z" horiz-adv-x="1000" /> <glyph glyph-name="header" unicode="H" d="M939-79q-25 0-74 2t-75 2q-24 0-73-2t-74-2q-13 0-21 12t-7 25q0 18 9 26t22 9 29 4 25 9q18 11 18 78l0 218q0 12-1 17-7 3-28 3h-376q-22 0-29-3 0-5 0-17l-1-207q0-79 21-91 9-6 26-8t32-2 25-8 11-26q0-14-6-26t-21-13q-26 0-78 2t-77 2q-24 0-71-2t-71-2q-13 0-20 12t-7 25q0 17 9 25t20 10 26 4 24 9q18 13 18 80l-1 31v454q0 2 1 15t0 20-1 21-2 24-4 20-6 18-9 10q-8 5-25 7t-29 1-23 7-10 26q0 14 6 26t20 13q26 0 78-2t77-2q23 0 71 2t70 2q14 0 21-13t7-26q0-17-9-25t-22-8-27-2-24-7q-20-12-20-90l1-178q0-12 0-18 7-2 22-2h390q14 0 21 2 1 6 1 18l0 178q0 78-19 90-10 6-33 7t-37 7-14 28q0 14 7 26t21 13q24 0 74-2t73-2q24 0 72 2t72 2q14 0 21-13t7-26q0-17-10-25t-22-8-29-2-24-7q-20-13-20-90l1-526q0-66 19-78 9-6 25-8t30-2 23-9 10-25q0-14-6-26t-20-13z" horiz-adv-x="1000" /> <glyph glyph-name="italic" unicode="I" d="M0-78l10 48q12 4 34 9t40 11 33 13q16 19 23 56 1 4 35 162t63 303 29 165v14q-13 8-30 11t-39 4-32 3l10 58q19-1 67-4t84-4 67-1q27 0 55 1t68 4 54 4q-2-22-10-50-17-6-57-16t-60-19q-5-10-8-23t-5-23-4-25-4-24q-15-82-49-234t-43-198q-1-5-7-32t-11-51-9-46-4-32l1-10q9-3 103-18-2-24-9-55-6 0-18-1t-18-1q-16 0-49 6t-48 6q-77 1-115 1-28 0-79-5t-68-7z" horiz-adv-x="571.4" /> <glyph glyph-name="paragraph" unicode="§" d="M713 745v-41q0-16-10-34t-24-18q-28 0-30-1-14-3-18-17-1-6-1-36v-643q0-14-11-24t-24-10h-60q-14 0-24 10t-10 24v680h-80v-680q0-14-9-24t-25-10h-60q-14 0-24 10t-10 24v277q-82 7-137 33-70 33-107 100-36 65-36 145 0 92 50 159 49 66 116 89 62 21 233 21h267q14 0 24-10t10-24z" horiz-adv-x="714.3" /> <glyph glyph-name="list-ol" unicode="ģ" d="M213-54q0-45-31-70t-75-26q-60 0-96 37l31 49q28-25 60-25 16 0 28 8t12 24q0 35-59 31l-14 31q4 6 18 24t24 31 20 21v1q-9 0-27-1t-27 0v-30h-59v85h186v-49l-53-65q28-6 45-27t17-49z m1 350v-89h-202q-4 20-4 30 0 29 14 52t31 38 37 27 31 24 14 25q0 14-9 22t-22 7q-25 0-45-32l-47 33q13 28 40 44t59 16q40 0 68-23t28-63q0-28-19-51t-42-36-42-28-20-30h71v34h59z m786-178v-107q0-7-5-13t-13-5h-678q-8 0-13 5t-5 13v107q0 8 5 13t13 5h678q7 0 13-6t5-12z m-786 502v-56h-187v56h60q0 22 0 67t1 68v7h-1q-5-10-28-30l-40 42 76 71h59v-225h60z m786-216v-108q0-7-5-12t-13-5h-678q-8 0-13 5t-5 12v108q0 7 5 12t13 5h678q7 0 13-5t5-12z m0 285v-107q0-7-5-12t-13-6h-678q-8 0-13 6t-5 12v107q0 8 5 13t13 5h678q7 0 13-5t5-13z" horiz-adv-x="1000" /> <glyph glyph-name="list-ul" unicode="•" d="M214 64q0-44-31-76t-76-31-76 31-31 76 31 76 76 31 76-31 31-76z m0 286q0-45-31-76t-76-31-76 31-31 76 31 76 76 31 76-31 31-76z m786-232v-107q0-7-5-13t-13-5h-678q-8 0-13 5t-5 13v107q0 7 5 12t13 6h678q7 0 13-6t5-12z m-786 518q0-45-31-76t-76-31-76 31-31 76 31 76 76 31 76-31 31-76z m786-232v-108q0-7-5-12t-13-5h-678q-8 0-13 5t-5 12v108q0 7 5 12t13 5h678q7 0 13-5t5-12z m0 285v-107q0-7-5-12t-13-6h-678q-8 0-13 6t-5 12v107q0 8 5 13t13 5h678q7 0 13-5t5-13z" horiz-adv-x="1000" /> <glyph glyph-name="left" unicode="←" d="M654 682l-297-296 297-297q10-10 10-25t-10-25l-93-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 11 25 11t25-11l93-93q10-10 10-25t-10-25z" horiz-adv-x="714.3" /> <glyph glyph-name="up" unicode="↑" d="M571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" /> <glyph glyph-name="right" unicode="→" d="M618 361l-414-415q-11-10-25-10t-25 10l-93 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l93 93q10 11 25 11t25-11l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" /> <glyph glyph-name="down" unicode="↓" d="M571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" /> <glyph glyph-name="export" unicode="↷" d="M750 60l0 56 100 82 0-188q0-20-15-35t-35-15l-750 0q-20 0-35 15t-15 35l0 550q0 22 14 36t36 14l288 0q-32-24-59-49t-39-39l-10-12-130 0 0-450 650 0z m-82 348q-166 0-242-41t-160-181q0 8 1 22t9 56 22 79 44 83 70 79 107 56 149 23l0 156 332-250-332-260 0 178z" horiz-adv-x="1000" /> <glyph glyph-name="reset" unicode="↺" d="M857 350q0-87-34-166t-91-137-137-92-166-34q-96 0-183 41t-147 114q-4 6-4 13t5 11l76 77q6 5 14 5 9-1 13-7 41-53 100-82t126-29q58 0 110 23t92 61 61 91 22 111-22 111-61 91-92 61-110 23q-55 0-105-20t-90-57l77-77q17-16 8-38-10-23-33-23h-250q-15 0-25 11t-11 25v250q0 24 22 33 22 10 39-8l72-72q60 57 137 88t159 31q87 0 166-34t137-92 91-137 34-166z" horiz-adv-x="857.1" /> <glyph glyph-name="upload" unicode="⇑" d="M714 29q0 14-10 25t-25 10-25-10-11-25 11-25 25-11 25 11 10 25z m143 0q0 14-10 25t-26 10-25-10-10-25 10-25 25-11 26 11 10 25z m72 125v-179q0-22-16-38t-38-16h-821q-23 0-38 16t-16 38v179q0 22 16 38t38 15h238q12-31 39-51t62-20h143q34 0 61 20t40 51h238q22 0 38-15t16-38z m-182 361q-9-22-33-22h-143v-250q0-15-10-25t-25-11h-143q-15 0-25 11t-11 25v250h-143q-23 0-33 22-9 22 8 39l250 250q10 10 25 10t25-10l250-250q18-17 8-39z" horiz-adv-x="928.6" /> <glyph glyph-name="download" unicode="⇓" d="M714 100q0 15-10 25t-25 11-26-11-10-25 10-25 26-11 25 11 10 25z m143 0q0 15-10 25t-26 11-25-11-10-25 10-25 25-11 26 11 10 25z m72 125v-179q0-22-16-37t-38-16h-821q-23 0-38 16t-16 37v179q0 22 16 38t38 16h259l75-76q33-32 76-32t76 32l76 76h259q22 0 38-16t16-38z m-182 318q10-23-8-40l-250-250q-10-10-25-10t-25 10l-250 250q-17 17-8 40 10 21 33 21h143v250q0 15 11 25t25 11h143q14 0 25-11t10-25v-250h143q24 0 33-21z" horiz-adv-x="928.6" /> <glyph glyph-name="home" unicode="⌂" d="M786 296v-267q0-15-11-26t-25-10h-214v214h-143v-214h-214q-15 0-25 10t-11 26v267q0 1 0 2t0 2l321 264 321-264q1-1 1-4z m124 39l-34-41q-5-5-12-6h-2q-7 0-12 3l-386 322-386-322q-7-4-13-4-7 2-12 7l-35 41q-4 5-3 13t6 12l401 334q18 15 42 15t43-15l136-114v109q0 8 5 13t13 5h107q8 0 13-5t5-13v-227l122-102q5-5 6-12t-4-13z" horiz-adv-x="928.6" /> <glyph glyph-name="print" unicode="⎙" d="M214-7h500v143h-500v-143z m0 357h500v214h-89q-22 0-38 16t-16 38v89h-357v-357z m643-36q0 15-10 25t-26 11-25-11-10-25 10-25 25-10 26 10 10 25z m72 0v-232q0-7-6-12t-12-6h-125v-89q0-22-16-38t-38-16h-536q-22 0-37 16t-16 38v89h-125q-7 0-13 6t-5 12v232q0 44 32 76t75 31h36v304q0 22 16 38t37 16h375q23 0 50-12t42-26l85-85q15-16 27-43t11-49v-143h35q45 0 76-31t32-76z" horiz-adv-x="928.6" /> <glyph glyph-name="table" unicode="◫" d="M286 82v107q0 8-5 13t-13 5h-179q-7 0-12-5t-6-13v-107q0-8 6-13t12-5h179q8 0 13 5t5 13z m0 214v108q0 7-5 12t-13 5h-179q-7 0-12-5t-6-12v-108q0-7 6-12t12-5h179q8 0 13 5t5 12z m285-214v107q0 8-5 13t-12 5h-179q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h179q7 0 12 5t5 13z m-285 429v107q0 8-5 13t-13 5h-179q-7 0-12-5t-6-13v-107q0-8 6-13t12-5h179q8 0 13 5t5 13z m285-215v108q0 7-5 12t-12 5h-179q-8 0-13-5t-5-12v-108q0-7 5-12t13-5h179q7 0 12 5t5 12z m286-214v107q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h178q8 0 13 5t5 13z m-286 429v107q0 8-5 13t-12 5h-179q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h179q7 0 12 5t5 13z m286-215v108q0 7-5 12t-13 5h-178q-8 0-13-5t-5-12v-108q0-7 5-12t13-5h178q8 0 13 5t5 12z m0 215v107q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h178q8 0 13 5t5 13z m72 178v-607q0-37-27-63t-63-26h-750q-36 0-63 26t-26 63v607q0 37 26 63t63 27h750q37 0 63-27t27-63z" horiz-adv-x="928.6" /> <glyph glyph-name="radio-unchecked" unicode="◯" d="M429 654q-83 0-153-41t-110-111-41-152 41-152 110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41z m428-304q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" /> <glyph glyph-name="star" unicode="★" d="M929 489q0-12-15-27l-202-197 48-279q0-4 0-12 0-11-6-19t-17-9q-10 0-22 7l-251 132-250-132q-12-7-23-7-11 0-17 9t-6 19q0 4 1 12l48 279-203 197q-14 15-14 27 0 21 31 26l280 40 126 254q11 23 27 23t28-23l125-254 280-40q32-5 32-26z" horiz-adv-x="928.6" /> <glyph glyph-name="uncheck" unicode="☐" d="M625 707h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v464q0 37-26 63t-63 26z m161-89v-464q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q66 0 114-48t47-113z" horiz-adv-x="785.7" /> <glyph glyph-name="check" unicode="☑" d="M786 331v-177q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q35 0 65-14 9-4 10-13 2-10-5-16l-27-28q-6-5-13-5-2 0-5 1-13 3-25 3h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v141q0 8 5 13l36 35q6 6 13 6 3 0 7-2 11-4 11-16z m129 273l-455-454q-13-14-31-14t-32 14l-240 240q-14 13-14 31t14 32l61 62q14 13 32 13t32-13l147-147 361 361q13 13 31 13t32-13l62-61q13-14 13-32t-13-32z" horiz-adv-x="928.6" /> <glyph glyph-name="settings" unicode="☸" d="M571 350q0 59-41 101t-101 42-101-42-42-101 42-101 101-42 101 42 41 101z m286 61v-124q0-7-4-13t-11-7l-104-16q-10-30-21-51 19-27 59-77 6-6 6-13t-5-13q-15-21-55-61t-53-39q-7 0-14 5l-77 60q-25-13-51-21-9-76-16-104-4-16-20-16h-124q-8 0-14 5t-6 12l-16 103q-27 9-50 21l-79-60q-6-5-14-5-8 0-14 6-70 64-92 94-4 5-4 13 0 6 5 12 8 12 28 37t30 40q-15 28-23 55l-102 15q-7 1-11 7t-5 13v124q0 7 5 13t10 7l104 16q8 25 22 51-23 32-60 77-6 7-6 14 0 5 5 12 15 20 55 60t53 40q7 0 15-5l77-60q24 13 50 21 9 76 17 104 3 15 20 15h124q7 0 13-4t7-12l15-103q28-9 50-21l80 60q5 5 13 5 7 0 14-5 72-67 92-95 4-5 4-13 0-6-4-12-9-12-29-38t-30-39q14-28 23-55l102-15q7-1 12-7t4-13z" horiz-adv-x="857.1" /> <glyph glyph-name="alert" unicode="⚠" d="M571 83v106q0 8-5 13t-12 5h-108q-7 0-12-5t-5-13v-106q0-8 5-13t12-6h108q7 0 12 6t5 13z m-1 208l10 257q0 6-5 10-7 6-14 6h-122q-7 0-14-6-5-4-5-12l9-255q0-5 6-9t13-3h103q8 0 13 3t6 9z m-7 522l428-786q20-35-1-70-10-17-26-26t-35-10h-858q-18 0-35 10t-26 26q-21 35-1 70l429 786q9 17 26 27t36 10 36-10 27-27z" horiz-adv-x="1000" /> |
︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <glyph glyph-name="minus" unicode="➖" d="M786 439v-107q0-22-16-38t-38-15h-678q-23 0-38 15t-16 38v107q0 23 16 38t38 16h678q22 0 38-16t16-38z" horiz-adv-x="785.7" /> <glyph glyph-name="logout" unicode="⤝" d="M857 350q0-87-34-166t-91-137-137-92-166-34-167 34-136 92-92 137-34 166q0 102 45 191t126 151q24 18 54 14t46-28q18-23 14-53t-28-47q-54-41-84-101t-30-127q0-58 22-111t62-91 91-61 111-23 110 23 92 61 61 91 22 111q0 68-30 127t-84 101q-24 18-28 47t14 53q17 24 47 28t53-14q81-61 126-151t45-191z m-357 429v-358q0-29-21-50t-50-21-51 21-21 50v358q0 29 21 50t51 21 50-21 21-50z" horiz-adv-x="857.1" /> <glyph glyph-name="eye-off" unicode="⤫" d="M0 326q6 49 64 110 79 80 176 128 129 61 260 61 29 0 59-2l74 129q10 16 23 18 4 0 8-2l51-32q17-7 2-33l-57-101-47-79-41-72-144-250-41-72-47-80-57-100q-15-25-31-15l-53 31q-15 8 0 33l49 86-8 4q-103 53-176 129-64 72-64 109z m264 0q0-74 47-133l48 84q-9 24-9 49 0 51 34 91t85 50l49 84-18 0q-98 0-167-66t-69-159z m177-295l41 71 18 0q98 0 167 65t69 159q0 74-47 133l63 109q2-2 4-3t4-1q103-52 176-128 64-73 64-110-6-49-64-109-79-80-176-129-129-61-260-61-25 0-59 4z m90 155l110 189q9-25 9-49 0-51-34-90t-85-50z" horiz-adv-x="1000" /> <glyph glyph-name="menu" unicode="𝍢" d="M857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" /> <glyph glyph-name="eye" unicode="👁" d="M0 350q6 49 64 110 79 80 176 129 129 60 260 60 137-2 260-60 103-53 176-129 64-73 64-110-6-49-64-109-79-80-176-129-129-61-260-61-137 2-260 61-103 53-176 129-64 72-64 109z m264 0q0-94 69-159t167-65 167 65 69 159-69 159-167 66-167-66-69-159z m86 1q0 60 44 102t106 42 106-42 44-102-44-102-106-43-106 43-44 102z" horiz-adv-x="1000" /> <glyph glyph-name="user" unicode="👤" d="M786 66q0-67-41-106t-108-39h-488q-67 0-108 39t-41 106q0 30 2 58t8 61 15 60 24 55 34 45 48 30 62 11q5 0 24-12t41-27 60-27 75-12 74 12 61 27 41 27 24 12q34 0 62-11t48-30 34-45 24-55 15-60 8-61 2-58z m-179 498q0-88-63-151t-151-63-152 63-62 151 62 152 152 63 151-63 63-152z" horiz-adv-x="785.7" /> <glyph glyph-name="users" unicode="👪" d="M331 350q-90-3-148-71h-75q-45 0-77 22t-31 66q0 197 69 197 4 0 25-11t54-24 66-12q38 0 75 13-3-21-3-37 0-78 45-143z m598-356q0-66-41-105t-108-39h-488q-68 0-108 39t-41 105q0 30 2 58t8 61 14 61 24 54 35 45 48 30 62 11q6 0 24-12t41-26 59-27 76-12 75 12 60 27 41 26 23 12q35 0 63-11t47-30 35-45 24-54 15-61 8-61 2-58z m-572 713q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z m393-214q0-89-63-152t-151-62-152 62-63 152 63 151 152 63 151-63 63-151z m321-126q0-43-31-66t-77-22h-75q-57 68-147 71 45 65 45 143 0 16-3 37 37-13 74-13 33 0 67 12t54 24 24 11q69 0 69-197z m-71 340q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z" horiz-adv-x="1071.4" /> <glyph glyph-name="attach" unicode="📎" d="M783 77q0-65-44-109t-109-44q-75 0-131 55l-434 434q-63 64-63 151 0 88 62 150t150 62q88 0 152-63l338-338q5-5 5-12 0-9-17-26t-26-17q-7 0-13 5l-338 339q-44 43-101 43-59 0-100-42t-40-101q0-58 42-101l433-433q35-35 81-35 36 0 59 23t24 59q0 46-36 81l-324 324q-14 14-33 14-16 0-27-11t-11-27q0-18 14-33l229-228q6-6 6-13 0-9-18-26t-26-17q-7 0-12 5l-229 229q-35 34-35 83 0 46 32 78t77 32q49 0 83-36l325-324q55-54 55-131z" horiz-adv-x="785.7" /> <glyph glyph-name="search" unicode="🔍" d="M643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" /> <glyph glyph-name="lock" unicode="🔒" d="M179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" /> <glyph glyph-name="unlock" unicode="🔓" d="M929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" /> </font> </defs> </svg> | > > > > > > > > > > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | <glyph glyph-name="minus" unicode="➖" d="M786 439v-107q0-22-16-38t-38-15h-678q-23 0-38 15t-16 38v107q0 23 16 38t38 16h678q22 0 38-16t16-38z" horiz-adv-x="785.7" /> <glyph glyph-name="logout" unicode="⤝" d="M857 350q0-87-34-166t-91-137-137-92-166-34-167 34-136 92-92 137-34 166q0 102 45 191t126 151q24 18 54 14t46-28q18-23 14-53t-28-47q-54-41-84-101t-30-127q0-58 22-111t62-91 91-61 111-23 110 23 92 61 61 91 22 111q0 68-30 127t-84 101q-24 18-28 47t14 53q17 24 47 28t53-14q81-61 126-151t45-191z m-357 429v-358q0-29-21-50t-50-21-51 21-21 50v358q0 29 21 50t51 21 50-21 21-50z" horiz-adv-x="857.1" /> <glyph glyph-name="eye-off" unicode="⤫" d="M0 326q6 49 64 110 79 80 176 128 129 61 260 61 29 0 59-2l74 129q10 16 23 18 4 0 8-2l51-32q17-7 2-33l-57-101-47-79-41-72-144-250-41-72-47-80-57-100q-15-25-31-15l-53 31q-15 8 0 33l49 86-8 4q-103 53-176 129-64 72-64 109z m264 0q0-74 47-133l48 84q-9 24-9 49 0 51 34 91t85 50l49 84-18 0q-98 0-167-66t-69-159z m177-295l41 71 18 0q98 0 167 65t69 159q0 74-47 133l63 109q2-2 4-3t4-1q103-52 176-128 64-73 64-110-6-49-64-109-79-80-176-129-129-61-260-61-25 0-59 4z m90 155l110 189q9-25 9-49 0-51-34-90t-85-50z" horiz-adv-x="1000" /> <glyph glyph-name="radio-checked" unicode="⬤" d="M571 350q0-59-41-101t-101-42-101 42-42 101 42 101 101 42 101-42 41-101z m-142 304q-83 0-153-41t-110-111-41-152 41-152 110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41z m428-304q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" /> <glyph glyph-name="menu" unicode="𝍢" d="M857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" /> <glyph glyph-name="eye" unicode="👁" d="M0 350q6 49 64 110 79 80 176 129 129 60 260 60 137-2 260-60 103-53 176-129 64-73 64-110-6-49-64-109-79-80-176-129-129-61-260-61-137 2-260 61-103 53-176 129-64 72-64 109z m264 0q0-94 69-159t167-65 167 65 69 159-69 159-167 66-167-66-69-159z m86 1q0 60 44 102t106 42 106-42 44-102-44-102-106-43-106 43-44 102z" horiz-adv-x="1000" /> <glyph glyph-name="user" unicode="👤" d="M786 66q0-67-41-106t-108-39h-488q-67 0-108 39t-41 106q0 30 2 58t8 61 15 60 24 55 34 45 48 30 62 11q5 0 24-12t41-27 60-27 75-12 74 12 61 27 41 27 24 12q34 0 62-11t48-30 34-45 24-55 15-60 8-61 2-58z m-179 498q0-88-63-151t-151-63-152 63-62 151 62 152 152 63 151-63 63-152z" horiz-adv-x="785.7" /> <glyph glyph-name="users" unicode="👪" d="M331 350q-90-3-148-71h-75q-45 0-77 22t-31 66q0 197 69 197 4 0 25-11t54-24 66-12q38 0 75 13-3-21-3-37 0-78 45-143z m598-356q0-66-41-105t-108-39h-488q-68 0-108 39t-41 105q0 30 2 58t8 61 14 61 24 54 35 45 48 30 62 11q6 0 24-12t41-26 59-27 76-12 75 12 60 27 41 26 23 12q35 0 63-11t47-30 35-45 24-54 15-61 8-61 2-58z m-572 713q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z m393-214q0-89-63-152t-151-62-152 62-63 152 63 151 152 63 151-63 63-151z m321-126q0-43-31-66t-77-22h-75q-57 68-147 71 45 65 45 143 0 16-3 37 37-13 74-13 33 0 67 12t54 24 24 11q69 0 69-197z m-71 340q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z" horiz-adv-x="1071.4" /> <glyph glyph-name="calendar" unicode="📅" d="M71-79h161v161h-161v-161z m197 0h178v161h-178v-161z m-197 197h161v178h-161v-178z m197 0h178v178h-178v-178z m-197 214h161v161h-161v-161z m411-411h179v161h-179v-161z m-214 411h178v161h-178v-161z m428-411h161v161h-161v-161z m-214 197h179v178h-179v-178z m-196 482v161q0 7-6 12t-12 6h-36q-7 0-12-6t-6-12v-161q0-7 6-13t12-5h36q7 0 12 5t6 13z m410-482h161v178h-161v-178z m-214 214h179v161h-179v-161z m214 0h161v161h-161v-161z m18 268v161q0 7-5 12t-13 6h-35q-7 0-13-6t-5-12v-161q0-7 5-13t13-5h35q8 0 13 5t5 13z m215 36v-715q0-29-22-50t-50-21h-786q-29 0-50 21t-21 50v715q0 29 21 50t50 21h72v54q0 37 26 63t63 26h36q37 0 63-26t26-63v-54h214v54q0 37 27 63t63 26h35q37 0 64-26t26-63v-54h71q29 0 50-21t22-50z" horiz-adv-x="928.6" /> <glyph glyph-name="attach" unicode="📎" d="M783 77q0-65-44-109t-109-44q-75 0-131 55l-434 434q-63 64-63 151 0 88 62 150t150 62q88 0 152-63l338-338q5-5 5-12 0-9-17-26t-26-17q-7 0-13 5l-338 339q-44 43-101 43-59 0-100-42t-40-101q0-58 42-101l433-433q35-35 81-35 36 0 59 23t24 59q0 46-36 81l-324 324q-14 14-33 14-16 0-27-11t-11-27q0-18 14-33l229-228q6-6 6-13 0-9-18-26t-26-17q-7 0-12 5l-229 229q-35 34-35 83 0 46 32 78t77 32q49 0 83-36l325-324q55-54 55-131z" horiz-adv-x="785.7" /> <glyph glyph-name="search" unicode="🔍" d="M643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" /> <glyph glyph-name="lock" unicode="🔒" d="M179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" /> <glyph glyph-name="unlock" unicode="🔓" d="M929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" /> <glyph glyph-name="image" unicode="🖻" d="M357 529q0-45-31-76t-76-32-76 32-31 76 31 76 76 31 76-31 31-76z m572-215v-250h-786v107l178 179 90-89 285 285z m53 393h-893q-7 0-12-5t-6-13v-678q0-7 6-13t12-5h893q7 0 13 5t5 13v678q0 8-5 13t-13 5z m89-18v-678q0-37-26-63t-63-27h-893q-36 0-63 27t-26 63v678q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" /> <glyph glyph-name="folder" unicode="🗀" d="M929 511v-393q0-51-37-88t-88-37h-679q-51 0-88 37t-37 88v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h375q51 0 88-37t37-88z" horiz-adv-x="928.6" /> <glyph glyph-name="document" unicode="🗅" d="M571 564v264q13-8 21-16l227-228q8-7 16-20h-264z m-71-18q0-22 16-37t38-16h303v-589q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h446v-304z" horiz-adv-x="857.1" /> </font> </defs> </svg> |
Modified src/www/admin/static/font/garradin.ttf from [2aa8a2bf32] to [4beed9ef00].
cannot compute difference between binary files
Modified src/www/admin/static/font/garradin.woff from [ccddd0b63a] to [c61f50249f].
cannot compute difference between binary files
Added src/www/admin/static/font/garradin.woff2 version [a65634acfa].
cannot compute difference between binary files
Deleted src/www/admin/static/garradin.png version [e27a36efbf].
cannot compute difference between binary files
Modified src/www/admin/static/handheld.css from [2785cac0a7] to [b035449fe2].
1 2 3 4 5 6 7 8 9 10 | body { background-position: -180px 0px; background-attachment: scroll; font-size: 11pt; } .header h1 { margin: 0; text-align: center; font-size: 1.2em; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | body { background-position: -180px 0px; background-attachment: scroll; font-size: 11pt; } .header h1 { margin: 0; text-align: center; font-size: 1.2em; margin: 6em 0 .3em 0; } .header .menu { background: none !important; position: fixed; bottom: inherit; overflow: visible; |
︙ | ︙ | |||
77 78 79 80 81 82 83 84 85 86 87 | .header .menu > ul > li.current_parent b { color: rgb(var(--gMainColor)); } .header .menu > ul > li.current > ul, .header .menu > ul > li.current_parent > ul { display: flex; position: absolute; top: 30pt; left: 0; right: 0; | > > < > < > > | | | | > | > | < > | > > > > > > | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | .header .menu > ul > li.current_parent b { color: rgb(var(--gMainColor)); } .header .menu > ul > li.current > ul, .header .menu > ul > li.current_parent > ul { display: flex; flex-wrap: wrap; justify-content: center; position: absolute; top: 30pt; left: 0; right: 0; background: rgba(255, 255, 255, 0.75); border-bottom: .2rem solid rgba(var(--gMainColor), 0.5); } .header .menu > ul > li.current > ul li, .header .menu > ul > li.current_parent > ul li { text-align: center; display: block; } .header .menu > ul > li.current > ul a, .header .menu > ul > li.current_parent > ul a { background: rgb(var(--gSecondColor), 0.3); border-radius: .5em; margin: .2rem; color: rgb(var(--gMainColor)); padding: .3em .5em; font-size: .9em; font-weight: normal; } .header .menu > ul > li > ul li.current a { background: rgb(var(--gSecondColor)); color: #fff; } main { margin: 0; padding: .1em; } nav.tabs ul { border: none; padding: 0; margin: .3em 0; justify-content: center; } nav.tabs ul li a, nav.tabs ul li label { margin: .1em; border-radius: .5em; } nav.tabs .sub { margin: 1em 0; border: none; border-top: .2rem dashed rgb(var(--gSecondColor)); } .filterCategory, .searchMember { width: auto; float: none; } pre.sql_schema, .wikiChildren, fieldset.wikiMain, fieldset.wikiRights, fieldset.wikiEncrypt { |
︙ | ︙ | |||
161 162 163 164 165 166 167 168 169 | width: auto; margin-left: 0; margin-right: 0; } /* Petits écrans (smartphones) */ @media screen and (max-width:600px) { table.list td, table.list th { display: inline-block; | > > > > | > > > > > > > > > > > > > > > > | > > > | > > > > > > > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | width: auto; margin-left: 0; margin-right: 0; } /* Petits écrans (smartphones) */ @media screen and (max-width:600px) { table.list tr { display: block; } table.list td, table.list th { display: inline-block; border-left: 2px dashed #999; width: auto !important; } colgroup { /* Hack pour désactiver les largeurs de colonnes */ display: none; } .print-btn { display: none; } .radio-btn input { position: absolute; right: 1em; } table.list td:first-child, table.list th:first-child { border-left: none; } .infos_asso { float: none; width: auto; } nav.acc-year { flex-direction: column; border: none; border-radius: 0; background: rgba(var(--gMainColor), 0.2); font-size: .8em; } .actions, table.list .actions { text-align: center; } .actions a { margin: .2em; font-size: .9em; } nav.tabs aside { float: none; text-align: center; } #dialog { background: black; } #dialog > iframe { width: 100%; height: 100%; margin: 0; } #dialog > button { border: none; background: none; } body#popup main { margin: .2em; } dl.list { text-align: center; } table.statement td, table.statement tr { display: block; } dl.describe { grid-template: auto / 30% 1fr; } } |
Modified src/www/admin/static/print.css from [55c05d913f] to [5d6f8ad8c8].
1 | @page { | | | > > > > > > > > > | | > > > > > | | | > > > > > > > > > > > > | | > > > > > > | > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | @page { size: A4 landscape; margin: 0; } body { background: #fff; padding: 0; margin: 1cm; font-size: 10pt; } header.header { display: none; } main { margin: 0; } .header h1 { margin: 0; text-align: center; } table.list thead { border-bottom: solid .3rem #000; } table.list thead td, table.list thead th { background: #ccc !important; color: #000 !important; border-right: 1px solid #999; } table.list tfoot { border-top: double .3rem #000; } table.list tfoot tr td, table.list tfoot th { background: #fff; color: #000; } table.list tr { border: 1px solid #666; } table.list tr:nth-child(even) { background: #ddd; } table.list.multi tr:nth-child(even) { background: inherit; } table.list.multi tr:nth-child(4n+1), table.list.multi tr:nth-child(4n+2) { background: #ddd; } table.list td { border: 1px solid #999; } #rapport tr { color: #000 !important; } #rapport table .parent { border-top: 1px dashed #666; } #rapport table table { border: 1px solid #666; } #rapport .parent { background: #ccc; } .noprint { display: none; } td.actions *, nav.tabs, .icn-btn, .pagination, a.icn { display: none !important; } td.num a { border: none; padding: 0; background: none; } a { color: black !important; text-decoration: none; } /* Don't repeat the table footer on every printed page */ table tfoot{ display:table-row-group; } |
Added src/www/admin/static/scripts/accounting.js version [0e2e45cbde].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | function initTransactionForm(is_new) { // Advanced transaction: line management var lines = $('.transaction-lines tbody tr'); function initLine(row) { var removeBtn = row.querySelector('button[name="remove_line"]'); removeBtn.onclick = () => { var count = $('.transaction-lines tbody tr').length; var min = removeBtn.getAttribute('min'); if (count <= min) { alert("Il n'est pas possible d'avoir moins de " + min + " lignes dans une écriture."); return false; } row.parentNode.removeChild(row); updateTotals(); }; // To be able to change input just by pressing up/down var inputs = row.querySelectorAll('input, select, button'); inputs.forEach((i, k) => { i.onkeydown = (e) => { if (e.key == 'ArrowUp' && (p = row.previousElementSibling)) { p.querySelectorAll('input, select, button')[k].focus(); return false; } else if (e.key == 'ArrowDown' && (n = row.nextElementSibling)) { n.querySelectorAll('input, select, button')[k].focus(); return false; } }; }); // Update totals and disable other amount input var inputs = row.querySelectorAll('input.money'); inputs.forEach((i, k) => { i.onkeyup = (e) => { var v = i.value.replace(/[^0-9,.]/); if (v.length && v != 0) { i.classList.remove('disabled'); inputs[+!k].classList.add('disabled'); inputs[+!k].value = '0'; updateTotals(); } }; if (+i.value == 0 && +inputs[+!k].value != 0) { i.classList.add('disabled'); i.value = '0'; } }); } lines.forEach(initLine); function updateTotals() { var amounts = $('.transaction-lines tbody input.money'); var debit = credit = 0; amounts.forEach((i) => { if (!i.value) { return; } var v = g.getMoneyAsInt(i.value); if (i.name.match(/debit/)) { debit += v; } else { credit += v; } }); if (m = $('#lines_message')) { var diff = credit - debit; m.innerHTML = (!diff) ? '' : '<span class="alert">Écriture non équilibrée (' + g.formatMoney(diff) + ')</span>'; } debit = debit ? debit + '' : '000'; credit = credit ? credit + '' : '000'; $('#f_debit_total').value = g.formatMoney(debit); $('#f_credit_total').value = g.formatMoney(credit); } // Add row button $('.transaction-lines tfoot button')[0].onclick = () => { var line = $('.transaction-lines tbody tr')[0]; var n = line.cloneNode(true); n.querySelectorAll('input').forEach((e) => { e.value = e.className.match(/money/) ? '0' : ''; }); if (l = n.querySelector('.input-list .label')) { l.parentNode.removeChild(l); } var b = n.querySelector('.input-list button'); b.onclick = () => { g.current_list_input = b.parentNode; g.openFrameDialog(b.value); return false; }; line.parentNode.appendChild(n); initLine(n); }; updateTotals(); // Hide type specific parts of the form function hideAllTypes() { g.toggle('[data-types]', false); } // Toggle parts of the form when a type is selected function selectType(v) { hideAllTypes(); g.toggle('[data-types~=t' + v + ']', true); g.toggle('[data-types=all-but-advanced]', v != 0); // Disable required form elements, or the form won't be able to be submitted $('[data-types=all-but-advanced] input[required]').forEach((e) => { e.disabled = v == 'advanced' ? true : false; }); } var radios = $('fieldset input[type=radio][name=type]'); radios.forEach((e) => { e.onchange = () => { document.querySelectorAll('fieldset').forEach((e, k) => { if (!is_new || k == 0 || e.dataset.types) return; g.toggle(e, true); g.toggle('p.submit', true); }); selectType(e.value); }; }); hideAllTypes(); // In case of a pre-filled form: show the correct part of the form var current = document.querySelector('input[name=type]:checked'); if (current) { selectType(current.value); } if (is_new) { document.querySelectorAll('fieldset').forEach((e, k) => { if (k == 0) return; g.toggle(e, false); g.toggle('p.submit', false); }); } } |
Modified src/www/admin/static/scripts/color_helper.js from [e3dcda260f] to [97e321468f].
1 2 3 4 5 6 7 8 9 10 | (function () { if (!document.documentElement.style.setProperty || !window.CSS || !window.CSS.supports || !window.CSS.supports('--var', 0)) { return; } var logo_limit_x = 170; | | | > > > > > > > | | > | > | | | < | | | > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | (function () { if (!document.documentElement.style.setProperty || !window.CSS || !window.CSS.supports || !window.CSS.supports('--var', 0)) { return; } var logo_limit_x = 170; function colorToRGB(color, type) { // Conversion vers décimal RGB return color.replace(/^#/, '').match(/.{1,2}/g).map(function (el) { // On limite la luminosité comme ça, c'est pas parfait mais ça marche return Math.min(parseInt(el, 16), type == 'gMainColor' ? 180 : 220); }); } function RGBToHex(color) { // Conversion vers décimal RGB return '#' + color.split(/,/).map(function (el) { return ('0' + parseInt(el, 10).toString(16)).substr(-2); }).join(''); } function changeColor(element, color) { var new_color = colorToRGB(color, element).join(','); // Mise à jour variable CSS document.documentElement.style.setProperty('--' + element, new_color); applyColors(); return new_color; } function applyColors() { let input = $('#f_couleur2'); var color = colorToRGB(input.value, 'gSecondColor'); var img = new Image; img.crossOrigin = "Anonymous"; img.onload = function() { var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height); var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); var data = imgData.data; for (var i = 0; i < data.length; i += 4) { // Re-colorier l'image avec la couleur choisie data[i] = color[0]; data[i+1] = color[1]; data[i+2] = color[2]; // i+3 = alpha channel, mais on n'y touche pas } ctx.putImageData(imgData, 0, 0); var i = canvas.toDataURL('image/png'); // Prévisualisation document.documentElement.style.setProperty('--gBgImage', 'url("' + i + '")'); $('#f_image_fond').value = i.substr(i.indexOf(',')+1); delete canvas2; delete canvas; delete ctx; delete img; }; var bg = $('#f_image_fond'); if (bg.value) { img.src = 'data:image/png;base64,' + bg.value; } else if (bg.dataset.source) { img.src = 'data:image/png;base64,' + bg.dataset.source; } else { img.src = bg.dataset.default; } } /** * Imports a new image and makes it black and white */ function importBackgroundImage(data, callback) { var max_w = 380, max_h = 300; var img = new Image; img.crossOrigin = "Anonymous"; img.onload = function() { var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var w = img.width, h = img.height; if (w > max_w) { w = max_w; h = (w / img.width) * img.height; } if (h > max_h) { h = max_h; w = (h / img.height) * img.width; } canvas.width = w; canvas.height = h; ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, w, h); var imgData = ctx.getImageData(0, 0, w, h); var data = imgData.data; var i = 0; for(var y = 0; y < imgData.height; y++) { for(var x = 0; x < imgData.width; x++) { var avg = (data[i] * 0.3 + data[i+1] * 0.59 + data[i+2] * 0.11); var b = avg < 127 && (data[i+3] > 127); data[i] = b ? avg : 255; // red data[i+1] = b ? avg : 255; // green data[i+2] = b ? avg : 255; // blue data[i+3] = b ? (x > 170 ? 50 : 150) : 0; i += 4; } } ctx.putImageData(imgData, 0, 0); var i = canvas.toDataURL('image/png'); $('#f_image_fond').value = i.substr(i.indexOf(',')+1); delete canvas2; delete canvas; delete ctx; delete img; callback(); }; img.src = data; } garradin.onload(function () { var couleurs = {'couleur1': 'gMainColor', 'couleur2': 'gSecondColor'}; for (var couleur in couleurs) { if (!couleurs.hasOwnProperty(couleur)) continue; var input = document.getElementById('f_' + couleur); input.oninput = function () { var c = changeColor(couleurs[this.name], this.value); this.value = RGBToHex(c); }; // Ajout bouton remise à zéro de la couleur var reset_btn = document.createElement('button'); reset_btn.className = 'resetButton icn-btn'; reset_btn.type = 'button'; reset_btn.innerHTML = 'RàZ'; reset_btn.onclick = function() { var input = this.previousSibling; input.value = input.getAttribute('placeholder'); changeColor(couleurs[input.name], input.value); return false; }; input.parentNode.insertBefore(reset_btn, input.nextSibling); } var bg = $('#f_background'); bg.onchange = () => { if (!bg.files.length) return; var reader = new FileReader; reader.onload = (e) => { importBackgroundImage(e.target.result, applyColors); bg.disabled = true; bg.value = ''; }; reader.readAsDataURL(bg.files[0]); }; var reset_btn = document.createElement('button'); reset_btn.className = 'resetButton icn-btn'; reset_btn.type = 'button'; reset_btn.innerHTML = 'RàZ'; reset_btn.onclick = () => { $('#f_image_fond').dataset.source = ''; $('#f_image_fond').value = ''; bg.disabled = false; applyColors(); }; bg.parentNode.insertBefore(reset_btn, bg.nextSibling); }); })(); |
Added src/www/admin/static/scripts/datepicker2.js version [180ac8cc87].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | (function () { DATEPICKER_L10N = {}; DATEPICKER_L10N.en = { weekdays: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] }; DATEPICKER_L10N.fr = { weekdays: ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'], months: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'] }; window.DatePicker = class { constructor(button, input, config) { this.button = button; this.input = input; this.date = null; Object.assign(this, { format: 0, // 0 = Y-m-d, 1 = d/m/Y lang: 'fr', class: 'datepicker' }, config); var c = document.createElement('dialog'); c.className = this.class; this.container = button.parentNode.insertBefore(c, button.nextSibling); button.onclick = () => { this.container.hasAttribute('open') ? this.close() : this.open() }; } open() { var d = this.input.value; if (d == '') { d = new CalendarDate; } else if (this.format == 1) { d = d.split('/'); d = new CalendarDate(d[2], d[1] - 1, d[0]); } else { d = new CalendarDate(d); } this.date = d; this.refresh(); this.focus(); this.container.setAttribute('open', 'open'); this.keyEvent = (e) => { var r = this.key(e.key); if (!r) { e.preventDefault(); } return r; }; document.addEventListener('keydown', this.keyEvent); } key(key) { switch (key) { case 'Enter': return !!this.select(); case 'Escape': return !!this.close(); case 'ArrowLeft': return !!this.day(-1); case 'ArrowRight': return !!this.day(1); case 'ArrowUp': return !!this.day(-7); case 'ArrowDown': return !!this.day(7); case 'PageDown': return !!this.month(1); case 'PageUp': return !!this.month(-1); } return true; } close() { this.container.innerHTML = ''; this.container.removeAttribute('open'); document.removeEventListener('keydown', this.keyEvent); } generateTable() { var c = (e) => { return document.createElement(e); } var table = c('table'), head = c('thead'), headRow = c('tr'), body = c('tbody'); DATEPICKER_L10N[this.lang].weekdays.forEach((d) => { var cell = c('td'); cell.innerHTML = d; headRow.appendChild(cell); }); head.appendChild(headRow); table.appendChild(head); var weeks = this.date.getCalendarArray(); weeks.forEach((week) => { var row = c('tr'); week.forEach((day) => { var cell = c('td'); cell.innerHTML = day ? day.getDate() : ''; cell.onclick = (e) => { this.select(e); }; row.appendChild(cell); }); body.appendChild(row); }); table.appendChild(body); return table; } refresh() { this.container.innerHTML = ''; var header = document.createElement('nav'); var p = document.createElement('input'); p.type = 'button'; p.value = '←'; p.onclick = () => { this.month(-1); return false; }; header.appendChild(p); var t = document.createElement('h3'); t.innerHTML = DATEPICKER_L10N[this.lang].months[this.date.getMonth()] + ' ' + this.date.getFullYear(); header.appendChild(t); var n = p.cloneNode(true); n.value = '→'; n.onclick = () => { this.month(1); return false; }; header.appendChild(n); this.container.appendChild(header); this.container.appendChild(this.generateTable()); } month(change) { this.date.setMonth(this.date.getMonth() + change); this.refresh(); this.focus(); } day(change) { var old = new CalendarDate(this.date); this.date.setDate(this.date.getDate() + change); if (this.date.getMonth() != old.getMonth()) { this.refresh(); } this.focus(); } select(e) { if (e && e.target.textContent.match(/\d+/)) { this.date.setDate(parseInt(e.target.textContent, 10)); } var y = this.date.getFullYear(), m = ('0' + (this.date.getMonth() + 1)).substr(-2), d = ('0' + this.date.getDate()).substr(-2); this.input.value = this.format == 1 ? d + '/' + m + '/' + y : y + '-' + m + '-' + d; this.close(); } focus() { this.container.querySelectorAll('tbody td').forEach((cell) => { var v = parseInt(cell.innerHTML, 10); if (v === this.date.getDate()) { cell.className = 'focus'; } else { cell.className = ''; } }); this.container.focus(); } } class CalendarDate extends Date { getCalendarArray() { var date = new CalendarDate(this.getFullYear(), this.getMonth(), 1); var days = []; var day = date.getDayOfWeek(); for (var i = 0; i < day - 1; i++) { days.push(null); } while (date.getMonth() === this.getMonth()) { days.push(new CalendarDate(date)); date.setDate(date.getDate() + 1); } day = date.getDayOfWeek(); for (var i = 0; i <= 7 - day; i++) { days.push(null); } var weeks = []; while (days.length) { weeks.push(days.splice(0, 7)); } return weeks; } getDayOfWeek() { var day = this.getDay(); if (day == 0) return 7; return day; } } }()); |
Deleted src/www/admin/static/scripts/datepickr.css version [6ff0b57283].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/www/admin/static/scripts/datepickr.js version [491ae371e7].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/www/admin/static/scripts/global.js from [cba439a7f0] to [66723d9008].
1 2 3 4 5 | (function () { window.g = window.garradin = { url: window.location.href.replace(/\/admin\/.*?$/, ''), admin_url: window.location.href.replace(/\/admin\/.*?$/, '/admin/'), static_url: window.location.href.replace(/\/admin\/.*?$/, '/admin/static/'), | | > > > > > > < < | < < < < < > > | > | > | > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | | > > | < > < < < < | < > > > > > > > > > > > > > > > > > > > > > > | | | | | < < < < < < | | | | | > | > > > > > > > > > > > > > > > > > > | | | < < < > | | < < < | < | > | | > > > > > > > > > > | > | > > > > | > > | > > | | | < | < | > | > | > > > > > > | > > > > > | > > > > | > > > > > > > > | > > | > > > > > > > > > > > > > | < < < < < | < < < < < < | < < | < < < < < | < | < < < | < < < < < | < < < < | | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | (function () { window.g = window.garradin = { url: window.location.href.replace(/\/admin\/.*?$/, ''), admin_url: window.location.href.replace(/\/admin\/.*?$/, '/admin/'), static_url: window.location.href.replace(/\/admin\/.*?$/, '/admin/static/'), version: document.head.querySelector('script').src.match(/\?(.*)$/)[1], loaded: {} }; window.$ = function(selector) { if (!selector.match(/^[.#]?[a-z0-9_-]+$/i)) { return document.querySelectorAll(selector); } else if (selector.substr(0, 1) == '.') { return document.getElementsByClassName(selector.substr(1)); } else if (selector.substr(0, 1) == '#') { return document.getElementById(selector.substr(1)); } else { return document.getElementsByTagName(selector); } }; if (!document.querySelectorAll) { return; } g.onload = function(callback, dom) { if (typeof dom == 'undefined') dom = true; var eventName = dom ? 'DOMContentLoaded' : 'load'; document.addEventListener(eventName, callback, false); }; g.toggle = function(selector, visibility) { if (!('classList' in document.documentElement)) return false; if (selector instanceof Array) { for (var i = 0; i < selector.length; i++) { g.toggle(selector[i], visibility); } return true; } else if (selector instanceof HTMLElement) { var elements = [selector]; } else { var elements = document.querySelectorAll(selector); } for (var i = 0; i < elements.length; i++) { if (!visibility) elements[i].classList.add('hidden'); else elements[i].classList.remove('hidden'); } return true; }; g.script = function (file, callback) { if (file in g.loaded) { callback(); return; } var script = g.loaded[file] = document.createElement('script'); script.type = 'text/javascript'; script.src = this.static_url + file + '?' + this.version; script.onload = callback; document.head.appendChild(script); }; g.style = function (file) { var link = document.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; link.href = this.static_url + file + '?' + this.version; return document.head.appendChild(link); }; g.dialog = null; g.openDialog = function (content) { if (null !== g.dialog) { g.closeDialog(); } g.dialog = document.createElement('dialog'); g.dialog.id = 'dialog'; g.dialog.open = true; var btn = document.createElement('button'); btn.className = 'icn-btn'; btn.setAttribute('data-icon', '✘'); btn.type = 'button'; btn.innerHTML = 'Fermer'; btn.onclick = g.closeDialog; g.dialog.appendChild(btn); content.style.opacity = g.dialog.style.opacity = 0; g.dialog.appendChild(content); g.dialog.onclick = (e) => { if (e.target == g.dialog) g.closeDialog(); }; window.onkeyup = (e) => { if (e.key == 'Escape') g.closeDialog(); }; document.body.appendChild(g.dialog); // Restore CSS defaults window.setTimeout(() => { g.dialog.style.opacity = ''; }, 50); window.setTimeout(() => { content.style.opacity = ''; }, 100); } g.openFrameDialog = function (url) { var iframe = document.createElement('iframe'); iframe.src = url; iframe.name = 'dialog'; iframe.frameborder = '0'; iframe.scrolling = 'yes'; iframe.width = iframe.height = 0; iframe.onload = () => { iframe.contentWindow.onkeyup = (e) => { if (e.key == 'Escape') g.closeDialog(); };} g.openDialog(iframe); }; g.closeDialog = function () { if (null === g.dialog) { return; } var d = g.dialog; d.style.opacity = 0; window.onkeyup = g.dialog = null; window.setTimeout(() => { d.parentNode.removeChild(d); }, 500); } // From KD2fw/js/xhr.js g.load = function(b,d,f,e){var a=new XMLHttpRequest();if(!a||!b)return false;if(a.overrideMimeType)a.overrideMimeType('text/xml');b+=(b.indexOf('?')+1?'&':'?')+(+(new Date));a.onreadystatechange=function(){if(a.readyState!=4)return;if((s=a.status)==200){if(!d)return true;var c=a.responseText;if(f=='json'){return((j=window.JSON)&&j.parse)?j.parse(c):eval('('+c.replace(/[\n\r]/g,'')+')')}d(c)}else if(e){e(s)}};a.open('GET',b,true);a.send(null)}; g.checkUncheck = function() { var checked = this.checked; this.form.querySelectorAll('tbody input[type=checkbox]').forEach((elm) => { elm.checked = checked; elm.dispatchEvent(new Event("change")); }); this.form.querySelectorAll('thead input[type=checkbox], tfoot input[type=checkbox]').forEach((elm) => { elm.checked = checked; }); return true; }; g.togglePasswordVisibility = (field, repeat, show) => { if (typeof show == 'undefined') { show = field.type.toLowerCase() == 'password'; } var btn = field.nextSibling; if (!btn) { throw Error('button not found'); } field.type = show ? 'text' : 'password'; btn.dataset.icon = !show ? '👁' : '⤫'; btn.innerHTML = !show ? 'Voir le mot de passe' : 'Cacher le mot de passe'; field.classList.toggle('clearTextPassword', !show); if (repeat) { repeat.type = field.type; repeat.classList.toggle('clearTextPassword', !show); } }; g.enhancePasswordField = function (field, repeat_field) { var show_password = document.createElement('button'); show_password.type = 'button'; show_password.className = 'icn-btn'; field.parentNode.insertBefore(show_password, field.nextSibling); g.togglePasswordVisibility(field, repeat_field, false); show_password.onclick = function (e) { var pos = field.selectionStart; g.togglePasswordVisibility(field, repeat_field); // Remettre le focus sur le champ mot de passe // on ne peut pas vraiment remettre le focus sur le champ // précis qui était utilisé avant de cliquer sur le bouton // car il faudrait enregistrer les actions onfocus de tous // les champs de la page field.focus(); field.selectionStart = field.selectionEnd = pos; }; }; g.enhanceDateField = (input) => { var span = document.createElement('span'); span.className = 'datepicker-parent'; var btn = document.createElement('button'); var cal = null; btn.className = 'icn-btn'; btn.setAttribute('data-icon', '📅'); btn.type = 'button'; btn.onclick = () => { g.script('scripts/datepicker2.js', () => { if (null == cal) { cal = new DatePicker(btn, input, {lang: 'fr', format: 1}); cal.open(); } }); }; span.appendChild(btn); input.parentNode.insertBefore(span, input.nextSibling); }; g.current_list_input = null; g.inputListSelected = function(value, label) { var i = g.current_list_input; var multiple = i.firstChild.getAttribute('data-multiple'); var name = i.firstChild.getAttribute('data-name'); var span = document.createElement('span'); span.className = 'label'; span.innerHTML = '<input type="hidden" name="' + name + '[' + value + ']" value="' + label + '" />' + label; // Add delete button if (parseInt(multiple, 10) == 1) { var btn = document.createElement('button'); btn.className = 'icn-btn'; btn.type = 'button'; btn.setAttribute('data-icon', '✘'); btn.onclick = () => span.parentNode.removeChild(span); span.appendChild(btn); } else if (old = i.querySelector('span')) { i.removeChild(old); } i.appendChild(span); g.closeDialog(); i.firstChild.focus(); }; g.formatMoney = (v) => { if (!v) { return '0,00'; } var s = v < 0 ? '-' : ''; v = '' + Math.abs(v); return s + (v.substr(0, v.length-2) || '0') + ',' + ('00' + v).substr(-2); }; g.getMoneyAsInt = (v) => { v = v.replace(/[^0-9.,]/, ''); if (v.length == 0) return; v = v.split(/[,.]/); var d = v.length == 2 ? v[1] : '0'; v = v[0] + (d + '00').substr(0, 2); v = parseInt(v, 10); return v; }; // Focus on first form input when loading the page g.onload(() => { if (!document.activeElement || document.activeElement.tagName.toLowerCase() == 'body') { let form = document.querySelector('form[data-focus]'); if (!form) { return; } var i = form.querySelector(form.dataset.focus == 1 ? '[name]' : form.dataset.focus); i.focus(); } }, 'dom'); // Sélecteurs de listes g.onload(() => { var inputs = $('form .input-list > button'); inputs.forEach((i) => { i.onclick = () => { g.current_list_input = i.parentNode; g.openFrameDialog(i.value); return false; }; }); var multiples = $('form .input-list span button'); multiples.forEach((btn) => { btn.onclick = () => btn.parentNode.parentNode.removeChild(btn.parentNode); }); }); g.onload(() => { document.querySelectorAll('input[data-input="date"]').forEach((e) => { g.enhanceDateField(e); }); }); // To be able to select a whole table line just by clicking the row g.onload(function () { var tableActions = document.querySelectorAll('form table tfoot .actions select'); for (var i = 0; i < tableActions.length; i++) { tableActions[i].onchange = function () { if (!this.form.querySelector('table tbody input[type=checkbox]:checked')) { return !window.alert("Aucune ligne sélectionnée !"); } this.form.submit(); }; } // Ajouter action check/uncheck sur les checkbox de raccourci dans les tableaux document.querySelectorAll('table thead input[type=checkbox], table tfoot input[type=checkbox]').forEach((elm) => { elm.addEventListener('change', g.checkUncheck); }); document.querySelectorAll('table tbody input[type=checkbox]').forEach((elm) => { elm.addEventListener('change', () => { elm.parentNode.parentNode.classList.toggle('checked', elm.checked); }); }); }); })(); |
Modified src/www/admin/static/scripts/password.js from [ae6eb9a86f] to [e1cdbb36d3].
︙ | ︙ | |||
9 10 11 12 13 14 15 | { pw_elm = (typeof password == 'string') ? document.getElementById(password) : password; pw2_elm = (typeof password2 == 'string') ? document.getElementById(password2) : password2; suggest_elm = (typeof suggest == 'string') ? document.getElementById(suggest) : suggest; g.enhancePasswordField(pw_elm, pw2_elm); | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | { pw_elm = (typeof password == 'string') ? document.getElementById(password) : password; pw2_elm = (typeof password2 == 'string') ? document.getElementById(password2) : password2; suggest_elm = (typeof suggest == 'string') ? document.getElementById(suggest) : suggest; g.enhancePasswordField(pw_elm, pw2_elm); suggest_elm.size = suggest_elm.value.length + 3; suggest_elm.onclick = function () { pw_elm.value = this.value; pw2_elm.value = this.value; this.select(); checkPasswordStrength(); checkPasswordMatch(); |
︙ | ︙ | |||
32 33 34 35 36 37 38 | match_elm.className = 'password_check'; pw2_elm.parentNode.appendChild(match_elm); pw_elm.onkeyup = checkPasswordStrength; pw_elm.onchange = function () { checkPasswordStrength(); checkPasswordMatch(); }; pw_elm.onblur = function () { checkPasswordStrength(); checkPasswordMatch(); }; | < | < | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | match_elm.className = 'password_check'; pw2_elm.parentNode.appendChild(match_elm); pw_elm.onkeyup = checkPasswordStrength; pw_elm.onchange = function () { checkPasswordStrength(); checkPasswordMatch(); }; pw_elm.onblur = function () { checkPasswordStrength(); checkPasswordMatch(); }; pw2_elm.onkeyup = checkPasswordMatch; pw_elm.form.addEventListener('submit', function (e) { if (pw_elm.value == '') return true; if (scorePassword(pw_elm.value) <= 30 && !window.confirm("Êtes-vous sûr de vouloir utiliser un mot de passe aussi mauvais que ça ?")) { e = e || window.event; if(e.preventDefault) |
︙ | ︙ |
Modified src/www/admin/static/scripts/query_builder.min.js from [f2e9e173b4] to [a0102fba69].
|
| | | 1 | !function(){var e=function(e){this.columns=e};(window.SQLQueryBuilder=e).prototype.loadDefaultOperators=function(){for(var e in this.operators={"= ?":this.__("is equal to"),"!= ?":this.__("is not equal to"),"IN (??)":this.__("is equal to one of"),"NOT IN (??)":this.__("is not equal to one of"),"> ?":this.__("is greater than"),">= ?":this.__("is greater than or equal to"),"< ?":this.__("is less than"),"<= ?":this.__("is less than or equal to"),"BETWEEN ? AND ?":this.__("is between"),"NOT BETWEEN ? AND ?":this.__("is not between"),"IS NULL":this.__("is null"),"IS NOT NULL":this.__("is not null"),"LIKE ?%":this.__("begins with"),"NOT LIKE ?%":this.__("doesn't begin with"),"LIKE %?":this.__("ends with"),"NOT LIKE %?":this.__("doesn't end with"),"LIKE %?%":this.__("contains"),"NOT LIKE %?%":this.__("doesn't contain"),"&":this.__("matches one of"),"= 1":this.__("is true"),"= 0":this.__("is false")},this.types_operators={integer:["= ?","!= ?","IN (??)","NOT IN (??)","> ?",">= ?","< ?","<= ?","BETWEEN ? AND ?","NOT BETWEEN ? AND ?"],enum:["= ?","!= ?","IN (??)","NOT IN (??)"],boolean:["= 1","= 0"],text:["= ?","!= ?","IN (??)","NOT IN (??)","LIKE ?%","NOT LIKE ?%","LIKE %?","NOT LIKE %?","LIKE %?%","NOT LIKE %?%"],bitwise:["&"]},this.types_operators){var t={};for(var i in this.types_operators[e]){var o=this.types_operators[e][i];t[o]=this.operators[o]}this.types_operators[e]=t}this.types_operators.date=JSON.parse(JSON.stringify(this.types_operators.integer)),delete this.types_operators.date["<= ?"],delete this.types_operators.date[">= ?"],this.types_operators.date["< ?"]=this.__("before"),this.types_operators.date["> ?"]=this.__("after"),this.types_operators.datetime=this.types_operators.date},e.prototype.__=function(e){return e},e.prototype.init=function(e){this.parent=e;var t={"":"---"};for(column in this.columns)t[column]=this.columns[column].label;this.columnSelect=this.buildSelect(t)},e.prototype.addGroup=function(t,e){var i=document.createElement("fieldset"),o=document.createElement("legend"),n=this.buildSelect({AND:this.__("Matches ALL of the following conditions:"),OR:this.__("Matches ANY of the following conditions:"),ADD:this.__("Add a new set of conditions below this one"),DEL:this.__("Remove this set of conditions")});n.onfocus=function(){this.oldValue=this.value},n.value=e;var r=this;n.onchange=function(){if("DEL"==this.value){if(1==t.childNodes.length)return void(this.value=this.oldValue);t.removeChild(i)}else if("ADD"==this.value){var e=r.addGroup(t,"AND");r.addRow(e),this.value=this.oldValue}},o.appendChild(n),i.appendChild(o);var s=document.createElement("table");return i.appendChild(s),t.appendChild(i),i},e.prototype.addRow=function(e,t){var i=e.getElementsByTagName("table")[0],o=document.createElement("tr");(s=document.createElement("td")).className="buttons";var n,r=this;(n=this.buildInput("button","+")).onclick=function(){r.addRow(function(e,t){for(;(e=e.parentElement)&&!(e.matches||e.matchesSelector).call(e,t););return e}(this,"fieldset"),this.parentNode.parentNode)},s.appendChild(n),(n=this.buildInput("button","-")).onclick=function(){r.deleteRow(this.parentNode.parentNode)},s.appendChild(n),o.appendChild(s),(s=document.createElement("td")).className="column";var s,l=this.columnSelect.cloneNode(!0);return l.onchange=function(){return r.switchColumn(this)},s.appendChild(l),o.appendChild(s),(s=document.createElement("td")).className="operator",o.appendChild(s),(s=document.createElement("td")).className="values",o.appendChild(s),void 0===t?i.appendChild(o):i.insertBefore(o,t.nextSibling),o},e.prototype.deleteRow=function(e){e.parentNode.childNodes.length<=1||e.parentNode.removeChild(e)},e.prototype.switchColumn=function(e){var t=e.parentNode.parentNode;if(t.childNodes[2].innerHTML="",e.value){var i=this.addOperator(t,this.columns[e.value]);i.value=i.children[1].value,this.switchOperator(i,null)}},e.prototype.addOperator=function(e,t){var i=this.types_operators[t.type],o={"":"---"};for(var n in t.null&&(i["IS NULL"]=this.operators["IS NULL"],i["IS NOT NULL"]=this.operators["IS NOT NULL"]),i)o[n]=i[n];var r=this.buildSelect(o),s=this;return r.onchange=function(){return s.switchOperator(this)},e.childNodes[2].appendChild(r),r},e.prototype.switchOperator=function(e,t){var i=e.parentNode.parentNode;!t&&i.childNodes[3].firstChild&&(t=[i.childNodes[3].firstChild.value]),i.childNodes[3].innerHTML="";var o=i.childNodes[3],n=i.childNodes[1].firstChild,r=e.value,s=this.columns[n.value];if(r){var l=1,a=!1,d=null,h=r.match(/\?/g);if(h&&r.match(/\?\?/))l=t?t.length:1,a=!0;else if(h&&1<=h.length)l=h.length;else{if("bitwise"!=s.type||"&"!=r)return;l=1}for(var u=0;u<l;u++)if(d=this.addMatchField(o,d,s,r),"bitwise"==s.type&&t)for(var p=0;p<s.values.length;p++)o.querySelectorAll("input")[p].checked=-1!=t.indexOf(p.toString());else t&&(d.value=t[u]);if(a){(c=this.buildInput("button","-")).onclick=function(){this.parentNode.childNodes.length<=3||(this.parentNode.removeChild(this.previousSibling),this.parentNode.removeChild(this.previousSibling))},o.appendChild(c);var c=this.buildInput("button","+"),f=this;c.onclick=function(){f.addMatchField(o,this.previousSibling.previousSibling,s,r)},o.appendChild(c)}}},e.prototype.addMatchField=function(e,t,i,o){if("enum"==i.type)var n=this.buildSelect(i.values);else if("bitwise"==i.type){n=document.createElement("span");for(var r in i.values){var s=this.buildInput("checkbox",r),l=document.createElement("label");l.appendChild(s),l.appendChild(document.createTextNode(" "+i.values[r])),n.appendChild(l.cloneNode(!0))}}else n=this.buildInput(i.type,"",i);return n=e.insertBefore(n,t?t.nextSibling:null),t&&e.insertBefore(document.createElement("br"),n),n},e.prototype.buildInput=function(e,t,i){var o=document.createElement("input");return o.type="integer"==e?"number":e,o.value=t,o},e.prototype.buildSelect=function(e){var t=document.createElement("select");for(var i in e){var o=document.createElement("option");o.value=i,o.innerHTML=e[i],t.appendChild(o)}return t},e.prototype.import=function(e){for(var t in e)if(0!=e[t].conditions.length){var i=this.addGroup(this.parent,e[t].operator);for(var o in e[t].conditions){var n=e[t].conditions[o],r=this.addRow(i);r.childNodes[1].firstChild.value=n.column;var s=this.addOperator(r,this.columns[n.column]);s.value=n.operator,this.switchOperator(s,n.values)}}},e.prototype.export=function(){var e=this.parent.querySelectorAll("table"),t=[];for(var i in e)if(e.hasOwnProperty(i)){for(var o=(i=e[i]).rows,n=[],r=0;r<o.length;r++){var s=o[r];if(s.getElementsByTagName("select")[0].value){var l=Array.prototype.slice.call(s.cells[3].querySelectorAll("input, select")).map(function(e){return"checkbox"==e.type?e.checked?e.value:null:"button"!=e.type?e.value:void 0});l=l.filter(function(e){return null!==e});var a={column:s.cells[1].firstChild.value,operator:s.cells[2].firstChild.value,values:l};a.operator&&n.push(a)}}t.push({operator:i.parentNode.firstChild.firstChild.value,conditions:n})}return t}}(); |
Modified src/www/admin/static/scripts/skel_editor.js from [0e1522caf5] to [6b35de296d].
1 2 | (function (){ g.style('scripts/skel_editor.css'); | | | | 1 2 3 4 5 6 7 8 9 10 11 12 | (function (){ g.style('scripts/skel_editor.css'); g.script('scripts/code_editor.min.js', function () { var save_btn = document.querySelector('[name=save]'); save_btn.type = 'hidden'; var code = new codeEditor('f_content'); code.params.lang = { search: "Texte à chercher ?\n(expression régulière autorisée, pour cela commencer par un slash '/')", replace: "Texte pour le remplacement ?\n(utiliser $1, $2... pour les captures d'expression régulière)", |
︙ | ︙ | |||
191 192 193 194 195 196 197 | m.className = msg.className; toolbar.appendChild(m); msg.parentNode.removeChild(msg); } window.location.hash = ''; } | | | 191 192 193 194 195 196 197 198 199 | m.className = msg.className; toolbar.appendChild(m); msg.parentNode.removeChild(msg); } window.location.hash = ''; } }); }()); |
Modified src/www/admin/static/scripts/wiki_editor.css from [d04c8ee367] to [30c3c98262].
︙ | ︙ | |||
16 17 18 19 20 21 22 | } nav.te { margin-bottom: .5em; height: 30px; } | | < < < | < < | > > < < < < < < < < < > | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | } nav.te { margin-bottom: .5em; height: 30px; } nav.te button { text-decoration: none; cursor: pointer; background: #eee no-repeat center center; display: inline-block; vertical-align: bottom; transition: all .2s; border: 1px solid #999; box-shadow: 2px 2px 5px #999; } nav.te .bold, nav.te .italic, nav.te .title, nav.te .link { font-family: Georgia, "Times New Roman", serif; } nav.te .bold { font-weight: bold; } nav.te .italic { font-style: italic; } nav.te .link { text-decoration: underline; color: blue; } nav.te .fullscreen { text-indent: -70em; width: 32px; overflow: hidden; } nav.te .icnl { font-size: 18px; } nav.te .ext.icnl { |
︙ | ︙ | |||
79 80 81 82 83 84 85 | margin-left: 2em; } .textEditor.fullscreen nav.te .fullscreen { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEUAAABNTVFOTlBOTlBLB/faAAAAA3RSTlMAOsPdsomtAAAAQElEQVQI12NIEWCRZNi5gTePIe8D/08G6Q/8Txj0P/B/YVj/gf8fAzawHyQhD1ICJvI/8O9k2FnAl8eQosAiCQCgixb13aKGIwAAAABJRU5ErkJggg=="); } | | | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | margin-left: 2em; } .textEditor.fullscreen nav.te .fullscreen { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEUAAABNTVFOTlBOTlBLB/faAAAAA3RSTlMAOsPdsomtAAAAQElEQVQI12NIEWCRZNi5gTePIe8D/08G6Q/8Txj0P/B/YVj/gf8fAzawHyQhD1ICJvI/8O9k2FnAl8eQosAiCQCgixb13aKGIwAAAABJRU5ErkJggg=="); } .textEditor nav button.close { display: none; float: right; } .textEditor nav button.reload { display: none; float: left; } .textEditor.fullscreen { position: fixed; top: 0; |
︙ | ︙ | |||
110 111 112 113 114 115 116 | height: 90%; } .textEditor.iframe textarea { display: none; } | | | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | height: 90%; } .textEditor.iframe textarea { display: none; } .textEditor.iframe nav button { display: none; } .textEditor.iframe nav button.close, .textEditor.iframe nav button.reload { display: inline-block; } .textEditor iframe { border: none; background: #eee; border-radius: .5em; |
︙ | ︙ |
Modified src/www/admin/static/scripts/wiki_editor.js from [e1b49b3d06] to [2d8c9cc5c3].
1 2 3 4 5 6 | (function () { var wiki_id = window.location.search.match(/id=(\d+)/)[1]; g.onload(function () { g.style('scripts/wiki_editor.css'); | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | (function () { var wiki_id = window.location.search.match(/id=(\d+)/)[1]; g.onload(function () { g.style('scripts/wiki_editor.css'); g.script('scripts/text_editor.min.js', function () { var t = new textEditor('f_contenu'); t.parent = t.textarea.parentNode; var toolbar = document.createElement('nav'); toolbar.className = 'te'; var toggleFullscreen = function (e) |
︙ | ︙ | |||
118 119 120 121 122 123 124 | t.parent.className = t.parent.className.replace(/ iframe$/, ''); t.iframe.className = 'hidden'; }; var appendButton = function (name, title, action, altTitle) { | | > > > > | > | | | | | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | t.parent.className = t.parent.className.replace(/ iframe$/, ''); t.iframe.className = 'hidden'; }; var appendButton = function (name, title, action, altTitle) { var btn = document.createElement('button'); btn.type = 'button'; btn.title = altTitle ? altTitle : title; if (title.length == 1) { btn.dataset.icon = title; } else { btn.innerText = title; } btn.className = 'icn-btn ' +name; btn.onclick = function () { action.call(); return false; }; toolbar.appendChild(btn); return btn; }; var wrapTags = function (left, right) { t.wrapSelection(t.getSelection(), left, right); return true; }; appendButton('title', "== Titre", function () { wrapTags("== ", ""); } ); appendButton('bold', '**gras**', function () { wrapTags('**', '**'); } ); appendButton('italic', "''italique''", function () { wrapTags("''", "''"); } ); appendButton('link', "[[lien|http://]]", function () { if (url = window.prompt('Adresse URL ?')) wrapTags("[[", "|" + url + ']]'); } ); appendButton('file', "📎", openFileInsert, 'Insérer fichier / image'); appendButton('ext preview', '⎙', openPreview, 'Prévisualiser'); appendButton('ext help', '❓', openSyntaxHelp, 'Aide sur la syntaxe'); appendButton('ext fullscreen', 'Plein écran', toggleFullscreen, 'Plein écran'); appendButton('ext close', 'Fermer', closeIFrame); t.parent.insertBefore(toolbar, t.parent.firstChild); t.shortcuts.push({key: 'F11', callback: toggleFullscreen}); t.shortcuts.push({ctrl: true, key: 'b', callback: function () { return wrapTags('**', '**'); } }); t.shortcuts.push({ctrl: true, key: 'g', callback: function () { return wrapTags('**', '**'); } }); t.shortcuts.push({ctrl: true, key: 'i', callback: function () { return wrapTags("''", "''"); } }); if (window.location.hash.match(/fullscreen/)) { t.toggleFullscreen(); window.location.hash = ''; } }); }); }()); |
Modified src/www/admin/static/scripts/wiki_fichiers.js from [fdc7825154] to [0dc8ddc2bb].
︙ | ︙ | |||
73 74 75 76 77 78 79 | thumb: this.firstChild.src }); return false; }; } } | | | | | > | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | thumb: this.firstChild.src }); return false; }; } } var a = document.createElement('button'); a.className = 'icn-btn'; a.innerText = 'Supprimer'; a.dataset.icon = '✘'; a.type = 'button'; a.onclick = function() { if (confirm('Supprimer ce fichier ?')) this.parentNode.submit(); }; var items = document.body.getElementsByTagName('form'); for (var i = 0; i < items.length, form = items[i]; i++) { if (form.className != 'actions') continue; |
︙ | ︙ |
Added src/www/admin/static/styles/00-reset.css version [763506382d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | @charset "UTF-8"; @font-face { font-family: 'gicon'; src: url('../font/garradin.eot?2021'); src: url('../font/garradin.eot?2021#iefix') format('embedded-opentype'), url('../font/garradin.woff?2021') format('woff'), url('../font/garradin.woff2?2021') format('woff2'), url('../font/garradin.ttf?2021') format('truetype'), url('../font/garradin.svg?2021#garradin') format('svg'); font-weight: normal; font-style: normal; } body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, textarea, p, blockquote, th, td, figure, article, aside, section, header, footer { padding: 0; margin: 0; } fieldset, img { border: 0; } table { border-collapse: collapse; border-spacing: 0; } ol, ul { list-style: none; } caption, th { text-align: left; } article, aside, figure, section, header, footer, main { display: block; } span { display: inline-block; } h1 { font-size: 2em; } h2 { font-size: 1.5em; } h3 { font-size: 1.2em; } h4 { font-size: 1em; } h5 { font-size: 0.9em; } h6 { font-size: 0.8em; } |
Added src/www/admin/static/styles/01-layout.css version [41d5ef04ee].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | /* marron : #9c4f15 rgb(156, 79, 21) orange : #d98628 rgb(217, 134, 40) */ :root { --gBgColor: 255, 255, 255; --gMainColor: 156, 79, 21; --gSecondColor: 217, 134, 40; --gBgImage: url("../gdin_bg.png"); } html { width: 100%; height: 100%; } body { font-size: 100%; color: #000; font-family: "Trebuchet MS", Arial, Helvetica, Sans-serif; padding-bottom: 1em; background: rgb(var(--gBgColor)) var(--gBgImage) no-repeat 0px 0px fixed; } main { margin: 0px 1em 1em 180px; position: relative; } main img { max-width: 100%; } .header h1 { color: rgb(var(--gMainColor)); margin-left: 180px; margin-bottom: 0.4em; } .header .menu { position: fixed; overflow: auto; z-index: 10000; width: 170px; top: 0; bottom: 0; padding-top: 100px; background: rgb(var(--gMainColor)) var(--gBgImage) no-repeat 0px 0px; } .header .menu::-webkit-scrollbar { width: 8px; background: rgba(255, 255, 255, 0.25); box-shadow: inset 0px 0px 10px #666; } .header .menu::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.5); border-radius: 10px; } .header .menu i { font-style: normal; } .header .menu a { color: #fff; color: rgb(var(--gBgColor)); font-weight: bold; padding: 0.4em 0.4em 0.4em 1em; display: block; text-decoration: none; transition: background .3s; } .header .menu a:hover { text-decoration: underline; background: rgba(var(--gSecondColor), 0.5); } .header .menu li li a { font-size: 0.8em; padding-left: 2em; } .header .menu li.current > a { background: #fff; background: rgb(var(--gBgColor)); color: rgb(var(--gMainColor)); } .header .menu a b { float: right; text-decoration: none; margin-top: -.2em; font-size: 20pt; color: rgba(255, 255, 255, .5); } .header .menu li.current > a b { color: rgba(var(--gSecondColor), 0.5); } ul.gallery { text-align: center; } ul.gallery li { display: inline-block; margin: .3em; vertical-align: middle; width: 150px; } ul.gallery li img { max-width: 150px; max-height: 150px; } ul.gallery .actions { text-align: center; z-index: 100; } #queryBuilder .column select, #queryBuilderForm .actions select { max-width: 15em; } #queryBuilder table td { vertical-align: top; padding: .1em .2em; } #queryBuilder table td.buttons { white-space: nowrap; } #queryBuilder input[type=button], #queryBuilder .values input { margin: .1em; } #queryBuilderForm .actions label { margin: 0 .5em; } #queryBuilder table .values label { margin: 0 .3em; } #queryBuilderForm input[type=number] { width: 4em; } |
Added src/www/admin/static/styles/02-common.css version [14d9c47672].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | /** Alert, confirm and error messages */ h3.warning { margin: 1em; color: red; } span.error, b.error { color: #900; } span.confirm, b.confirm { color: #090; } span.alert, b.alert { color: #990; } .alert p, .error p, .confirm p { margin-bottom: .8em; } .alert.block, .error.block, .confirm.block, .help.block { border: 1px solid #ccc; padding: .5em; margin-bottom: 1em; border-radius: .3em; padding-left: 3em; position: relative; } .alert.block { border-color: #cc0; background-color: #ffc; } .error.block { border-color: #c00; background-color: #fcc; } .confirm.block { border-color: #0c0; background-color: #cfc; } .help.block { border-color: #999; background-color: #eee; } .confirm.block::before, .alert.block::before, .error.block::before, .help.block::before { font-family: "gicon"; left: .5em; top: .2em; position: absolute; font-size: 1.5em; text-shadow: 2px 2px 5px #666; } .confirm.block::before { content: "☑"; color: green; } .alert.block::before { content: "⚠"; color: yellow; } .error.block::before { content: "⚠"; color: red; } .help.block::before { content: "❓"; color: #666; } .help { color: #666; } p.help { margin: 1em; } .help ul li { list-style-type: disc; margin: .5em; margin-left: 2em; } dd em.help { margin-left: 1em; } dd.help li { list-style-type: disc; } .error ul, .alert ul, .confirm ul { margin-left: 1.5em; list-style: disc; } h2.ruler { margin: .5em; text-align: center; color: #333; overflow: hidden; } h2.ruler:before, h2.ruler:after { background-color: #000; content: ""; display: inline-block; height: 1px; position: relative; vertical-align: middle; width: 50%; } h2.ruler:before { right: 0.5em; margin-left: -50%; } h2.ruler:after { left: 0.5em; margin-right: -50%; } .num a, a.num { text-decoration: none; border-radius: .5rem; display: inline-block; text-align: center; padding: 0 .3rem; background: rgba(var(--gMainColor), 0.7); color: #fff; white-space: pre; } .droits b { border: 2px solid #999; border-radius: 1em; color: #000; background: #ccc; width: 16px; display: inline-block; text-align: center; font-size: 0.8em; cursor: help; vertical-align: middle; position: relative; z-index: 10; font-family: "gicon", "Trebuchet MS", Arial, Helvetica, sans-serif; } .droits b.aucun { border-color: #ccc; background: #eee; color: #999; } .droits b.acces { border-color: #cc9; color: #660; background: #ffe; } .droits b.ecriture { border-color: #9c9; color: #060; background: #efe; } .droits b.aucun:before { content: "X"; position: absolute; left: 0; right: 0; top: -3px; color: #ccc; z-index: -1; font-size: 1.5em; overflow: hidden; } .droits b.admin { color: #900; border-color: #c99; background: #fee; } .infos { margin-bottom: 1em; } .infos h3 { margin-bottom: 0.5em; } .infos p { margin-bottom: 0.8em; } .infos dl { margin-bottom: 0.8em; } .infos dl dd { margin: 0.2em 1em; } .shortFormRight { width: 30em; float: right; text-align: center; margin-left: 1em; } .shortFormLeft p { display: inline-block; } .shortFormLeft .special { display: none; } .shortFormRight p.submit { margin-top: -2em; float: right; } .memberList { clear: both; } .pagination { clear: both; list-style-type: none; padding: 0.4em 0; text-align: center; } .pagination li { display: inline-block; margin: 0 0.3em; } .pagination li.current { font-size: 1.3em; } .pagination li a { color: #000; } .templatesList ul { margin: 1em 2em; } dl.list dt, dl.list dd { margin: .3em 0; } dl.list dt { font-size: 1.2em; font-weight: bold; margin-top: .8em; } dl.list dd.desc { color: #666; } dl.describe { margin-bottom: 1rem; display: grid; grid-template: auto / 15rem 1fr; } dl.describe > dt { grid-column: 1; margin: .2rem .5rem; text-align: right; color: #666; align-self: center; } dl.describe > dd { grid-column: 2; margin: .2rem .5rem; align-self: center; } dl.describe ul { margin-left: 1.5em; list-style-type: disc; } dl.cotisation { background: rgb(255, 174, 80); background: rgba(217, 134, 40, 0.2); background: rgba(var(--gSecondColor), 0.2); padding: .5em; border-radius: .5em; margin: 1em; } dl.cotisation dt { font-weight: bold; } dl.cotisation dd { margin: .2em 0 .4em 1em; } aside.describe { width: 20em; float: right; margin: .5em; background: rgba(var(--gSecondColor), 0.2); border-radius: .5em; border: 2px solid rgba(var(--gSecondColor), 0.5); padding: .5em; z-index: 200; color: #666; } aside.describe dl.describe { display: block; } aside.describe dl.describe dt { text-align: left; font-weight: bold; color: #000; } pre.sql_schema { float: right; color: #666; font-size: .9em; width: 30%; overflow: auto; } .hidden { display: none; } img.qrcode { float: right; padding: .5em; border: .5em solid #000; background: #fff; } details summary { list-style: none; padding: 0.2em 0.5em; transition: background-color .2s; position: relative; } details summary:hover { cursor: pointer; background-color: rgba(var(--gMainColor), 0.1); } details summary::-webkit-details-marker { display: none; } details summary::after { content: "↓"; position: absolute; left: 0; top: 0; /* From .icn-btn */ display: inline-block; color: rgb(var(--gMainColor)); border: 1px solid rgba(var(--gSecondColor), 0.5); background: #fff; font-size: 1.5em; border-radius: .2em; padding: .2em .4em; margin: .2em .5em; transition: color .3s, background-color .3s; font-family: "gicon", sans-serif; text-shadow: 1px 1px 1px #999; } details[open] summary::after { content: "↑"; } details summary:hover::after { background-color: rgb(var(--gMainColor)); color: #fff; } details summary.block { padding-right: 4em !important; } details summary.block::after { right: 0; left: inherit; } |
Added src/www/admin/static/styles/03-forms.css version [ddd03e3cc7].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | /* Forms */ fieldset { border: 1px solid #ccc; padding: 0.8em 1em 0 1em; margin-bottom: 1em; padding: 0.5em; } fieldset legend { padding: 0 0.5em; font-weight: bold; color: #000; } table tr.clickable:hover { cursor: pointer; color: #633; background: #ffc; } dl dt label { font-weight: bold; } fieldset dl dt b { color: #900; font-size: 0.7em; font-weight: normal; vertical-align: super; } fieldset dl dt i { color: #999; font-size: 0.7em; font-weight: normal; vertical-align: super; } fieldset dl dd.tip { color: #666; } fieldset dl dd { padding: 0.2em 0.5em 0.2em 1em; } fieldset dl dd ol, fieldset dl dd ul { margin-left: 1.5em; } fieldset dl dl { margin: .5em 0 .5em 1.2em; } label:hover { cursor: pointer; border-bottom: 1px dotted #900; } input[type=checkbox] + label:hover { border: none; } /* We can't use :not([type=checkbox]):not([type=radio]) here as it is too specific and then it's a mess to override the selector after... */ input[type=text], input[type=number], input[type=color], input[type=date], input[type=datetime-local], input[type=datetime], input[type=time], input[type=week], input[type=email], input[type=file], input[type=url], input[type=month], input[type=password], input[type=range], input[type=search], input[type=tel], textarea, select, .input-list { padding: .4rem .6rem; font-family: inherit; min-width: 20em; max-width: 100%; border: 1px solid rgb(var(--gMainColor)); font-size: inherit; background: #fff; color: #000; border-radius: .25rem; transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; } input:not(:placeholder-shown):focus:invalid { border-color: #f33; } input.time { text-align: center; padding: .2em 0; } /* Fake checkbox and radio buttons */ input[type=checkbox], input[type=radio] { position: absolute; opacity: 0; } input[type=checkbox] + label::before, input[type=radio] + label::before { display: inline-block; width: 1em; height: 1em; text-align: center; transition: color .2s, box-shadow .2s ease-in-out; text-shadow: 1px 1px 3px #ccc; cursor: pointer; font-family: gicon; font-size: 1.2rem; font-weight: normal; color: rgb(var(--gMainColor)); margin-right: .5em; border-radius: .25rem; padding: .1rem .2rem; } input[type=checkbox] + label::before { content: "☐"; } input[type=checkbox]:checked + label::before { content: "☑"; } input[type=radio] + label::before { content: "◯"; } input[type=radio]:checked + label::before { content: "⬤"; } input:hover + label::before { color: rgb(var(--gSecondColor)); } input:checked + label::before { text-shadow: 1px 1px 5px #ff9; } input:focus, button:focus, select:focus, textarea:focus, input[type=radio]:focus + label::before, input[type=checkbox]:focus + label::before { box-shadow: 0 0 5px .2rem rgb(var(--gSecondColor)); outline: 0; } /* buttons */ input[type=submit], input[type=button], button, input[type=file] { border-radius: 1em; border: none; box-shadow: 0px 0px 5px 0 #ccc; cursor: pointer; border: 2px solid rgba(var(--gMainColor), 0.5); background-color: rgba(var(--gSecondColor), 0.1); display: inline-block; font-size: inherit; border-radius: .2em; padding: .2em .4em; margin: .2em .5em; text-decoration: none; transition: color .3s, background-color .3s; color: #000; } a.icn-btn { cursor: pointer; color: #003; border: 1px solid rgba(var(--gMainColor), 0.5); background-color: rgba(var(--gSecondColor), 0.1); user-select: none; display: inline-block; font-size: inherit; border-radius: .2em; padding: .2em .4em; margin: .2em .5em; white-space: pre; transition: color .3s, background-color .3s; text-decoration: underline; } .submit .main { color: #000; font-size: 1.2em; border-radius: 1em; padding: .5em 1em; } .submit .main[data-icon]:before { display: none; } p.submit .main[data-icon]:after { padding: 0 0 0 .5rem; color: rgba(var(--gSecondColor)); font-size: 1.5rem; line-height: .2em; } .submit .minor { font-size: .9em; } input[type=submit]:hover, input[type=button]:hover, button:hover, a.icn-btn:hover, input[type=file]:hover, .radio-btn:hover div, a.num:hover, .num a:hover { background-color: rgba(var(--gSecondColor), 0.2); color: darkred !important; border-color: rgb(var(--gSecondColor)); } input[type=submit]:active, input[type=button]:active, button:active, input[type=file]:active { box-shadow: 0 0 10px .1rem rgb(var(--gSecondColor)); } input[type=color] { cursor: pointer; } input.resetButton { margin-left: 1em; } input[readonly], input.disabled, input[disabled], textarea[disabled], select[disabled] { cursor: not-allowed; color: #666; background-color: #eee; border-color: #999; } input[disabled]:hover, input[readonly]:hover { background-color: unset; color: unset; border-color: unset; } select, input[size], input[type=color], button, input[type=button], input[type=submit], input[type=number] { min-width: 0; } /* Radio button lists (eg. new transaction) */ form .radio-btn { display: table; width: 100%; padding: 0; border-spacing: .5rem .2rem; } form .radio-btn label { display: table-row; } form .radio-btn input + label::before { display: table-cell; } form .radio-btn input:focus + label::before { box-shadow: none; } form .radio-btn input:focus + label div { box-shadow: 0 0 5px .2rem rgb(var(--gSecondColor)); } form .radio-btn div { display: table-cell; border: 1px solid rgba(var(--gSecondColor), 0.5); background-color: rgba(var(--gSecondColor), 0.1); font-size: inherit; border-radius: .2em; padding: .2em .4em; transition: color .3s, background-color .3s; color: #333; } form .radio-btn h3 { text-decoration: underline; } form .radio-btn input { margin: 1em; } form .radio-btn .help { margin: .8em 0 0 0; font-size: .8em; } form .radio-btn input:checked + label div { background-color: rgba(var(--gSecondColor), 0.3); } /* Custom list input */ form .input-list { padding: 0; display: inline-flex; flex-wrap: wrap; align-items: center; justify-content: start; min-width: 0; } form .input-list .label { padding: .4rem .6rem; } form .input-list button { padding: .4rem .6rem; align-self: stretch; flex-shrink: 0; margin: 0; border: none; } form .input-list .label button { padding: .2rem; border: none; background: none; } input.money { text-align: right; } input.money + b { padding: .2rem .6rem; line-height: 1.5rem; color: #999; } p.submit { margin: 1em; } form .checkUncheck { float: left; } form span.password_check { margin-left: 1em; padding: .1em .3em; border-radius: .5em; } form span.password_check.fail { background-color: #f99; } form span.password_check.weak { background-color: #ff9; } form span.password_check.medium { background-color: #ccf; } form span.password_check.ok { background-color: #cfc; } dd.help input[type=text] { cursor: pointer; font-family: monospace; } form p.actions { float: right; } /** Datepicker widget */ .datepicker-parent { position: relative; } dialog { display: none; } dialog[open] { display: block; } dialog.datepicker { position: absolute; left: 0; margin: 0; padding: .3rem; border: none; box-shadow: 0 0 5px #000; border-radius: .5rem; z-index: 1000; } .datepicker nav { display: flex; justify-content: space-between; text-align: center; } .datepicker h3 { font-size: inherit; margin: 0 .5rem; } .datepicker table { border-collapse: collapse; width: 100%; } .datepicker thead td { font-size: 80%; color: #999; } .datepicker tbody tr:nth-child(even) { background-color: #eee; } .datepicker tbody td:nth-child(6) { color: #666; } .datepicker tbody td:nth-child(7) { color: #999; } .datepicker tbody td { padding: .2rem .4rem; text-align: center; width: 14.3%; } .datepicker tbody td:not(:empty):hover { cursor: pointer; background: #fcc; text-decoration: underline; } .datepicker tbody td.focus { background: #339; color: #fff; } .datepicker input { font-family: gicon; } [data-icon]:before, summary::after, .main[data-icon]:after { display: inline-block; font-family: "gicon", sans-serif; text-shadow: 1px 1px 1px #ccc; padding-right: .5em; font-size: 1.2em; line-height: .8em; vertical-align: middle; content: attr(data-icon); } [data-icon]:empty:before { padding: 0; } .icn, .icnl { font-family: "gicon", sans-serif; font-style: normal; font-weight: normal; speak: none; font-variant: normal; text-transform: none; position: relative; } .actions .icn, .icn.action { text-decoration: none; border-radius: 1em; display: inline-block; text-align: center; font-size: 1.2em; line-height: .8em; vertical-align: middle; padding: .2em; font-family: "gicon", sans-serif; color: #9c4f15; color: rgb(var(--gMainColor)); text-shadow: 1px 1px 1px #999; border: none; cursor: pointer; position: relative; z-index: 200; } fieldset.memberMessage { max-width: 30em; } fieldset.memberMessage #f_sujet, fieldset.memberMessage #f_message { width: 95%; } |
Added src/www/admin/static/styles/04-dialogs.css version [9ca4a3ffe3].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | body#popup { background-position: -170px 0px; } body#transparent { background: transparent; } body#popup main { margin: 1em 1em 1em 2.5em; } body#transparent main { margin: 0; padding: .2em; } /** Dialogs pop-ins */ #dialog { width: 100%; height: 100%; margin: 0; padding: 0; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.7); position: fixed; opacity: 1; transition: opacity .5s; z-index: 100000; display: flex; flex-direction: column; align-items: center; justify-content: center; border: none; } #dialog > iframe { width: 90%; height: 90%; border: none; box-shadow: 0px 0px 5px #000; } #dialog button { background: rgb(var(--gMainColor)); color: #fff; font-size: 1.3em; display: block; width: 90%; } .loader { width: 100%; min-height: 32px; display: block; position: relative; } .loader.install { margin-top: -40px; } .loader b { text-shadow: 2px 2px 5px #999; background: rgb(255, 255, 255); background: rgba(255, 255, 255, 0.5); border-radius: .5em; font-size: 16px; line-height: 16px; height: 16px; z-index: 9999; position: absolute; display: block; left: 10px; top: 10px; padding: .2em; } .loader img { position: absolute; opacity: 0; transition: all 0.5s ease; z-index: 2; } |
Added src/www/admin/static/styles/05-navigation.css version [e121b7221f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /** Context-specific tabs */ nav.tabs ul { list-style-type: none; margin: 1em 0; border-bottom: 2px solid #9c4f15; border-bottom-color: rgb(var(--gMainColor)); padding: 0 1em; z-index: 100; display: flex; flex-wrap: wrap; align-items: flex-end; } nav.tabs .sub { margin: -1em 0 1em 2em; padding-top: 1em; border-left: 2px solid rgb(var(--gMainColor)); border-bottom-left-radius: .5em; } nav.tabs .sub .title { margin: 0 1em 0 -1em; font-weight: bold; padding: .1em .5em; } nav.tabs li { margin: 0 0.2em; } nav.tabs li a { display: inline-block; background: rgba(var(--gSecondColor), .5); border-radius: .5em .5em 0 0; padding: .1em .5em; color: #000; text-decoration: none; transition: background-color .2s, color .2s; } nav.tabs .current a { background: rgb(var(--gMainColor)); color: rgb(var(--gBgColor)); } nav.tabs li a:hover { color: rgb(var(--gBgColor)); background-color: rgb(var(--gMainColor)); text-decoration: underline; border-bottom: none; } nav.tabs aside { float: right; } |
Added src/www/admin/static/styles/06-tables.css version [6775097e90].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | table.list { margin-bottom: 1em; width: 100%; } table.list caption { text-align: center; font-size: 1.2em; } table.list tbody td.desc { font-size: .9em; color: #666; } table.list.auto { width: auto; } table.list table { margin: 0; } table.list th { text-align: left; font-weight: bold; } table.list thead { background: rgba(var(--gSecondColor), 0.5); } table.list tfoot tr { background: rgba(var(--gSecondColor), 0.2); } table.list th, table.list td { padding: 0.2em 0.5em; } table.list tr { border: 1px solid rgba(var(--gSecondColor), 0.5); transition: background .2s } table.list tr:nth-child(even), table.multi tbody:nth-child(even) { background: rgba(var(--gSecondColor), 0.2); } table.list tr.disabled { color: #666; } table.multi tr { background: inherit !important; } table.list tr.checked { color: #633; background: #ffc; } table.list .error { color: red; font-weight: bold; } table.list .alert { color: darkred; font-weight: bold; } table.list .confirm { color: darkgreen; } table.list .num { text-align: center; } table.list .check { width: 1%; } table.search th { background: rgb(217, 134, 40); background: rgba(217, 134, 40, 0.5); background: rgba(var(--gSecondColor), 0.5); } table.list .disabled { background: #eee; color: #999; } .userOrder .cur { background: rgba(var(--gSecondColor), 1.0); color: rgb(var(--gBgColor)); } table.list .userOrder td, table.list .userOrder th { position: relative; padding-left: 2.3em; } table.list .userOrder .check { padding-left: .5em; } .userOrder .icn { position: absolute; left: .3em; top: 0; color: rgb(var(--gMainColor)); text-decoration: none; font-size: 1.5em; line-height: .5em; width: 1em; text-align: center; vertical-align: middle; font-weight: normal; text-shadow: 0px 0px 1px rgb(var(--gBgColor)); margin: 0; } .userOrder .icn.dn { margin-top: .6em; } thead .icn:hover { color: darkred; text-shadow: none; } thead .cur.desc .icn.dn, thead .cur.asc .icn.up { color: #fff; text-shadow: none; } table.list .actions { text-align: right; } table.list .separator { border-left: 2px dashed #999; } |
Added src/www/admin/static/styles/10-accounting.css version [2779caf5e1].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | /** Accounting specifics */ .money { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; } b.money { font-weight: inherit; white-space: pre; } .transaction-lines td.money { text-align: left; } .transaction-lines td.money input + b { display: none; } .transaction-lines select { max-width: 10em; } .transaction-lines input[type=text] { min-width: 0 !important; } nav.acc-year { background: white; text-align: center; border-radius: .5rem; border: .2rem solid rgba(var(--gMainColor), 0.5); display: flex; align-items: center; margin-bottom: .5rem; } nav.acc-year > * { padding: .2rem .5rem; } nav.acc-year h4 { font-weight: normal; } table.statement, table.statement table { width: 100%; } table.statement td, table.statement th { padding: .5rem; vertical-align: top; } table.statement table.list td, table.statement table.list th { padding: .2rem .5rem; } table.statement table { border: 1px solid rgba(var(--gSecondColor), 0.5); } td.money, th.money { text-align: right; } .statement table tfoot tr { background: rgba(var(--gSecondColor), 0.1); color: rgb(var(--gMainColor)); } .year-header { text-align: center; margin-bottom: .8em; padding-bottom: .5em; border-bottom: 1pt solid #999; } .year-header .print-btn button { font-size: 1.3rem; } .year-infos { text-align: center; } .year-infos .graphs { display: flex; flex-wrap: wrap; justify-content: center; } .year-infos .graphs figure { margin: 1rem; } table.accounts { width: 100%; } table.accounts .actions { text-align: right; } table.accounts tbody tr td:first-child { font-family: monospace; } table.accounts th { font-weight: normal; } table.accounts .account-level-1 th { font-size: 1.6em; } table.accounts .account-level-2 th { padding-left: 1em; font-size: 1.3em; } table.accounts .account-level-3 th { padding-left: 2em; } table.accounts .account-level-4 th { padding-left: 3em; } table.accounts .account-level-5 th { padding-left: 4em; } table.accounts .account-level-6 th { padding-left: 5em; } |
Modified src/www/admin/static/styles/config.css from [ec00c1eea1] to [bc72f7c8a4].
︙ | ︙ | |||
32 33 34 35 36 37 38 | border: 1px solid #999; padding: .2em .5em; } .error .event table { margin: .5em; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | border: 1px solid #999; padding: .2em .5em; } .error .event table { margin: .5em; } #orderFields fieldset { position: relative; min-height: 2em; transition: all 1s; overflow: hidden; max-height: 5000px; } #orderFields fieldset legend { font-size: 1.2em; line-height: .8em; color: #666; } #orderFields fieldset .actions { display: block; position: absolute; top: 1em; right: 1em; } #orderFields fieldset .actions .icn { position: absolute; } #orderFields fieldset dl { overflow: hidden; transition: all .5s; opacity: 1; display: block; max-height: 5000px; } #orderFields fieldset dl.hidden { opacity: 0; max-height: 0; } #orderFields fieldset.removed { max-height: 0; opacity: 0; border-color: red; min-height: 0; height: 0; } #orderFields fieldset .actions .remove { right: 0em; } #orderFields fieldset .actions .edit { right: 1.5em; } #orderFields fieldset .actions .down { right: 3em; } #orderFields fieldset .actions .up { right: 4.5em; } #orderFields fieldset:nth-child(1) .actions .up, #orderFields fieldset:nth-last-child(1) .actions .down { display: none; } #orderFields fieldset .actions .icn { cursor: pointer; } #orderFields fieldset .interactive:hover { cursor: pointer; text-decoration: underline; } |
Modified src/www/admin/upgrade.php from [accfe43dfe] to [c92e73bdbf].
1 2 3 4 | <?php namespace Garradin; | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php namespace Garradin; const UPGRADE_PROCESS = true; require_once __DIR__ . '/../../include/test_required.php'; require_once __DIR__ . '/../../include/init.php'; $config = Config::getInstance(); Upgrade::preCheck(); echo '<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, target-densitydpi=device-dpi" /> <link rel="stylesheet" type="text/css" href="static/admin.css" media="all" /> |
︙ | ︙ | |||
65 66 67 68 69 70 71 | <div id="loader" class="loader" style="margin: 2em 0; height: 50px;"></div> <script> animatedLoader(document.getElementById("loader"), 5); </script>'; flush(); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < | < < < | | | | | | < < < | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <div id="loader" class="loader" style="margin: 2em 0; height: 50px;"></div> <script> animatedLoader(document.getElementById("loader"), 5); </script>'; flush(); Upgrade::upgrade(); echo '<h2>Mise à jour terminée.</h2> <p><a href="'.ADMIN_URL.'">Retour</a></p> <script type="text/javascript"> window.setTimeout(function () { window.location.href = "'.ADMIN_URL.'"; stopAnimatedLoader(); }, 1000); </script> </main> </body> </html>'; |
Modified src/www/admin/wiki/_fichiers.php from [abf2d3676b] to [aec8dcbc2d].
︙ | ︙ | |||
22 23 24 25 26 27 28 | elseif (f('delete')) { if ($form->check($csrf_id)) { try { $fichier = new Fichiers(f('delete')); | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | elseif (f('delete')) { if ($form->check($csrf_id)) { try { $fichier = new Fichiers(f('delete')); if (!$fichier->checkAccess($session, true)) { throw new UserException('Vous n\'avez pas accès à ce fichier.'); } $fichier->remove(); Utils::redirect(ADMIN_URL . 'wiki/_fichiers.php?page=' . $page->id); } |
︙ | ︙ |
Modified src/www/index.php from [f59003a96f] to [1c65f87820].
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; require __DIR__ . '/_inc.php'; if (Config::getInstance()->get('desactiver_site')) { Utils::redirect(ADMIN_URL); } $squelette = new Squelette; $squelette->dispatchURI(); | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php namespace Garradin; if (PHP_VERSION_ID < 70200) { die("PHP 7.2 ou supérieur est requis."); } require __DIR__ . '/_inc.php'; if (Config::getInstance()->get('desactiver_site')) { Utils::redirect(ADMIN_URL); } $squelette = new Squelette; $squelette->dispatchURI(); |
Modified tests/run.php from [e0e24bf932] to [43c2b61a01].
1 2 | <?php | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php define('Garradin\WWW_URI', '/'); define('Garradin\WWW_URL', 'http://localhost/'); const INIT = __DIR__ . '/../src/include/init.php'; if (!empty($_SERVER['argv'][1])) { require $_SERVER['argv'][1]; exit; } else |
︙ | ︙ |
Modified tests/unit_tests/01_basic/db.php from [88dbf0c61d] to [66b9155618].
1 2 3 4 5 6 7 8 | <?php namespace Garradin; use KD2\Test; const DB_FILE = ':memory:'; | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php namespace Garradin; use KD2\Test; const DB_FILE = ':memory:'; const INSTALL_PROCESS = true; require_once INIT; $db = DB::getInstance(); // test exec Test::assert($db->exec('CREATE TABLE test (a, b);')); // test insert |
︙ | ︙ | |||
30 31 32 33 34 35 36 | Test::assert($db->update('test', ['a' => 5, 'b' => 6], 'a = :a AND b = :b', ['a' => 3, 'b' => 4])); // test update with mixed type bindings try { $db->update('test', ['a' => 5, 'b' => 6], 'a = ? AND b = ?', [3, 4]); $failed = false; } | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | Test::assert($db->update('test', ['a' => 5, 'b' => 6], 'a = :a AND b = :b', ['a' => 3, 'b' => 4])); // test update with mixed type bindings try { $db->update('test', ['a' => 5, 'b' => 6], 'a = ? AND b = ?', [3, 4]); $failed = false; } catch (\LogicException $e) { $failed = true; } Test::assert($failed === true); // test if update worked Test::equals((object)['a' => 5, 'b' => 6], $db->first('SELECT a, b FROM test LIMIT 1, 1;')); |
︙ | ︙ | |||
62 63 64 65 66 67 68 | $expected = [(object)['a' => 1, 'b' => 2], (object)['a' => 9, 'b' => 10]]; Test::equals($expected, $db->get('SELECT * FROM test LIMIT 2;')); $expected = [1 => 2, 9 => 10]; Test::equals($expected, $db->getAssoc('SELECT * FROM test LIMIT 2;')); $expected = [1 => (object) ['a' => 1, 'b' => 2], 9 => (object) ['a' => 9, 'b' => 10]]; | | < < < < | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | $expected = [(object)['a' => 1, 'b' => 2], (object)['a' => 9, 'b' => 10]]; Test::equals($expected, $db->get('SELECT * FROM test LIMIT 2;')); $expected = [1 => 2, 9 => 10]; Test::equals($expected, $db->getAssoc('SELECT * FROM test LIMIT 2;')); $expected = [1 => (object) ['a' => 1, 'b' => 2], 9 => (object) ['a' => 9, 'b' => 10]]; Test::equals(json_encode($expected), json_encode($db->getGrouped('SELECT * FROM test LIMIT 2;'))); // test transactions Test::assert($db->begin()); Test::assert($db->insert('test', ['a' => 42, 'b' => 43])); Test::assert($db->insert('test', ['a' => 44, 'b' => 45])); // test rollback Test::assert($db->rollback()); Test::equals(3, $db->firstColumn('SELECT COUNT(*) FROM test;')); |
︙ | ︙ |
Modified tests/unit_tests/01_basic/paths.php from [802a0c36b5] to [10b0dc1a36].
1 2 3 4 5 | <?php namespace Garradin; use KD2\Test; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; use KD2\Test; require_once INIT; Test::assert(defined('Garradin\ROOT')); Test::assert(is_readable(ROOT)); Test::assert(defined('Garradin\PLUGINS_ROOT')); Test::assert(is_readable(PLUGINS_ROOT)); |
︙ | ︙ |
Modified tests/unit_tests/01_basic/version.php from [20ce832281] to [9444e092b3].
1 2 3 4 5 | <?php namespace Garradin; use KD2\Test; | | | 1 2 3 4 5 6 7 8 9 | <?php namespace Garradin; use KD2\Test; require_once INIT; Test::assert(function_exists('Garradin\garradin_version')); Test::assert(garradin_version()); |
Added tests/unit_tests/02_accounting/money.php version [b5a7b488bb].
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php namespace Garradin; use KD2\Test; require_once INIT; Test::strictlyEquals(500, Utils::moneyToInteger('5')); Test::strictlyEquals(442, Utils::moneyToInteger('4,42')); Test::strictlyEquals(442, Utils::moneyToInteger('4.42')); Test::strictlyEquals(4, Utils::moneyToInteger('0,04')); Test::strictlyEquals(30, Utils::moneyToInteger('0,3')); Test::strictlyEquals(202034, Utils::moneyToInteger('2020,34')); Test::strictlyEquals('5,50', Utils::money_format(550)); Test::strictlyEquals('0,05', Utils::money_format(5)); Test::strictlyEquals('0,50', Utils::money_format(50)); Test::strictlyEquals('1 000,50', Utils::money_format(100050)); |