├── .gitignore ├── config.php ├── img ├── ATM_logo.jpg ├── multiclone.png ├── multiclone_large.png ├── object_multiclone.png ├── object_multiclone_mod.png ├── Dolibarr_Preferred_Partner_logo.png ├── multiclone_object.svg └── multiclone.svg ├── script └── create-maj-base.php ├── config.default.php ├── langs ├── en_US │ └── multiclone.lang └── fr_FR │ └── multiclone.lang ├── ChangeLog.md ├── backport └── v19 │ └── core │ └── class │ └── commonhookactions.class.php ├── README.md ├── tpl ├── linkedobjectblock.tpl.php └── card.tpl.php ├── README-fr_FR.md ├── admin ├── multiclone_about.php └── multiclone_setup.php ├── core ├── triggers │ └── interface_99_modmulticlone_multiclonetrigger.class.php └── modules │ └── modmulticlone.class.php ├── lib └── multiclone.lib.php └── class ├── actions_multiclone.class.php └── multiclone.class.php /.gitignore: -------------------------------------------------------------------------------- 1 | .buildpath 2 | .project 3 | .settings/ 4 | *.log 5 | /nbproject/* -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | init_db_by_vars(); 21 | */ 22 | -------------------------------------------------------------------------------- /config.default.php: -------------------------------------------------------------------------------- 1 | ATM Consulting
You can find the documentation on our wiki

For any question or feedback, contact us on support@atm-consulting.fr

For any commercial question, contact us on contact@atm-consulting.fr or at +33 9 77 19 50 70

Find our other modules on Dolistore 5 | 6 | multicloneSetup = multiclone module setup 7 | multicloneAbout = About multiclone 8 | 9 | 10 | FeatureRequireModSalariesEnabled=Require Salary module to be active. 11 | FeatureRequireModTaxEnabled=Require Tax module to be active.ConfirmClonesalary -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## Unreleased 5 | 6 | 7 | 8 | ## Release 1.4 9 | - FIX : Frequency on multiclone- **17/11/2025** - 1.4.4 10 | - FIX : Compat V22 - **02/10/2025** - 1.4.3 11 | - FIX : Fatal Unsupported operand type string instead of int - **26/02/2025** - 1.4.2 12 | - FIX : Compat v21 : Using deprecated "->periode" change to "->period" - **05/02/2025** - 1.4.1 13 | - FIX: Compat v20 14 | Changed Dolibarr compatibility range to 16 min - 20 max - *28/07/2024* - 1.4.0 15 | 16 | ## Release 1.3 17 | 18 | - NEW : Dolibarr compatibility V19 - *04/12/2023* - 1.3.0 19 | Changed Dolibarr compatibility range to 15 min - 19 max 20 | Changed PHP compatibility range to 7.0 min - 8.2 max 21 | 22 | ## Release 1.2 23 | 24 | - FIX : Compat V18 *14/06/2023* - 1.2.5 25 | - FIX : Warning if empty string for date function *22/09/2022* - 1.2.4 26 | - FIX : Editor name and familly *03/08/2022* - 1.2.3 27 | - FIX : Modification du label lors d'un multiclone sur charge sociale & ajout utilisateur vide *19/07/2022* - 1.2.2 28 | - FIX : Remove useless condition because already in setup *18/05/2022* - 1.2.1 29 | - NEW : Refonte du module & ajout du fonctionnement sur objets Salaire, Charges sociales et factures fournisseur *25/01/2022* - 1.2.0 30 | - NEW : Module redesign - admin setup and display *09/12/2021* - 1.1.0 31 | 32 | ## Release 1.0 33 | 34 | - NEW : Clone multiple sur facture commande et propal ET sur commande on peut définir une fréquence par mois de date de livraison *18/01/2018* - 1.0.1 35 | - Init : *18/01/2018* - 1.0.0 36 | -------------------------------------------------------------------------------- /backport/v19/core/class/commonhookactions.class.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | /** 22 | * \file htdocs/core/class/commonhookactions.class.php 23 | * \ingroup core 24 | * \brief File of parent class of all other hook actions classes 25 | */ 26 | 27 | 28 | if (file_exists(DOL_DOCUMENT_ROOT . '/core/class/commonhookactions.class.php')){ 29 | require_once DOL_DOCUMENT_ROOT . '/core/class/commonhookactions.class.php'; 30 | /** 31 | * Parent class of all other hook actions classes 32 | */ 33 | abstract class RetroCompatCommonHookActions extends \CommonHookActions { } 34 | } else { 35 | /** 36 | * Parent class of all other hook actions classes 37 | */ 38 | abstract class RetroCompatCommonHookActions 39 | { 40 | /** 41 | * @var string String of results. 42 | */ 43 | public $resprints; 44 | 45 | /** 46 | * @var array Array of results. 47 | */ 48 | public $results = array(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DOLIBARR MODULE MULTICLONE 2 | 3 | Multi-Clone is a Dolibarr module usefull to manage clone planning 4 | 5 | ## LICENSE 6 | Copyright (C) 2019 ATM Consulting 7 | Multi-Clone is released under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version (GPL-3+). 8 | 9 | See the [COPYING](https://github.com/Dolibarr/dolibarr/blob/develop/COPYING) file for a full copy of the license. 10 | 11 | ## INSTALL 12 | 13 | ### Dependencies 14 | 15 | This module need this modules to be installed on your dolibarr : 16 | - abricot : a tools library 17 | 18 | ### From the ZIP file and GUI interface 19 | 20 | - If you get the module in a zip file (like when downloading it from the market place [Dolistore](https://www.dolistore.com)), go into 21 | menu ```Home - Setup - Modules - Deploy external module``` and upload the zip file. 22 | 23 | 24 | Note: If this screen tell you there is no custom directory, check your setup is correct: 25 | 26 | - In your Dolibarr installation directory, edit the ```htdocs/conf/conf.php``` file and check that following lines are not commented: 27 | 28 | ```php 29 | //$dolibarr_main_url_root_alt ... 30 | //$dolibarr_main_document_root_alt ... 31 | ``` 32 | 33 | - Uncomment them if necessary (delete the leading ```//```) and assign a sensible value according to your Dolibarr installation 34 | 35 | For example : 36 | 37 | - UNIX: 38 | ```php 39 | $dolibarr_main_url_root_alt = '/custom'; 40 | $dolibarr_main_document_root_alt = '/var/www/Dolibarr/htdocs/custom'; 41 | ``` 42 | 43 | - Windows: 44 | ```php 45 | $dolibarr_main_url_root_alt = '/custom'; 46 | $dolibarr_main_document_root_alt = 'C:/My Web Sites/Dolibarr/htdocs/custom'; 47 | ``` 48 | 49 | ### From a GIT repository 50 | 51 | - Clone the repository in ```$dolibarr_main_document_root_alt/multiclone``` 52 | 53 | ```sh 54 | cd ....../custom 55 | git clone git@github.com:gitlogin/multiclone.git multiclone 56 | ``` 57 | 58 | ### Final steps 59 | 60 | From your browser: 61 | 62 | - Log into Dolibarr as a super-administrator 63 | - Go to "Setup" -> "Modules" 64 | - You should now be able to find and enable the module 65 | 66 | 67 | -------------------------------------------------------------------------------- /tpl/linkedobjectblock.tpl.php: -------------------------------------------------------------------------------- 1 | 3 | * Copyright (C) 2013 Juanjo Menent 4 | * Copyright (C) 2014 Marcos García 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | */ 20 | ?> 21 | 22 | 23 | 24 | load("multiclone@multiclone"); 32 | echo '
'; 33 | print_titre($langs->trans("multicloneRelated")); 34 | ?> 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | $objectlink) 47 | { 48 | $var=!$var; 49 | ?> 50 | > 51 | 52 | 53 | 54 | 55 | 56 | 57 | 60 | 61 |
trans("Ref"); ?>trans("Label"); ?>trans("DateMaj"); ?>trans("Status"); ?>
getNomUrl(1); ?>label; ?>date_maj,'day'); ?>getLibStatut(0); ?>">transnoentitiesnoconv("RemoveLink")); ?>
62 | 63 | -------------------------------------------------------------------------------- /README-fr_FR.md: -------------------------------------------------------------------------------- 1 | # MODULE MULTI-CLONE POUR DOLIBARR 2 | 3 | Le module Multi-Clone est un module Dolibarr permettant Permettre de cloner des documents en spécifiant le nombre de clones et la fréquence de clonage en mois. 4 | 5 | ## LICENSE 6 | Copyright (C) 2019 ATM Consulting 7 | Multi-Clone is released under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version (GPL-3+). 8 | 9 | See the [COPYING](https://github.com/Dolibarr/dolibarr/blob/develop/COPYING) file for a full copy of the license. 10 | 11 | ## INSTALL 12 | 13 | ### Dependencies 14 | 15 | This module need this modules to be installed on your dolibarr : 16 | - abricot : a tools library 17 | 18 | ### From the ZIP file and GUI interface 19 | 20 | - If you get the module in a zip file (like when downloading it from the market place [Dolistore](https://www.dolistore.com)), go into 21 | menu ```Home - Setup - Modules - Deploy external module``` and upload the zip file. 22 | 23 | 24 | Note: If this screen tell you there is no custom directory, check your setup is correct: 25 | 26 | - In your Dolibarr installation directory, edit the ```htdocs/conf/conf.php``` file and check that following lines are not commented: 27 | 28 | ```php 29 | //$dolibarr_main_url_root_alt ... 30 | //$dolibarr_main_document_root_alt ... 31 | ``` 32 | 33 | - Uncomment them if necessary (delete the leading ```//```) and assign a sensible value according to your Dolibarr installation 34 | 35 | For example : 36 | 37 | - UNIX: 38 | ```php 39 | $dolibarr_main_url_root_alt = '/custom'; 40 | $dolibarr_main_document_root_alt = '/var/www/Dolibarr/htdocs/custom'; 41 | ``` 42 | 43 | - Windows: 44 | ```php 45 | $dolibarr_main_url_root_alt = '/custom'; 46 | $dolibarr_main_document_root_alt = 'C:/My Web Sites/Dolibarr/htdocs/custom'; 47 | ``` 48 | 49 | ### From a GIT repository 50 | 51 | - Clone the repository in ```$dolibarr_main_document_root_alt/multiclone``` 52 | 53 | ```sh 54 | cd ....../custom 55 | git clone git@github.com:gitlogin/multiclone.git multiclone 56 | ``` 57 | 58 | ### Final steps 59 | 60 | From your browser: 61 | 62 | - Log into Dolibarr as a super-administrator 63 | - Go to "Setup" -> "Modules" 64 | - You should now be able to find and enable the module 65 | 66 | 67 | -------------------------------------------------------------------------------- /admin/multiclone_about.php: -------------------------------------------------------------------------------- 1 | 3 | * Copyright (C) 2015 ATM Consulting 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /** 20 | * \file admin/about.php 21 | * \ingroup multiclone 22 | * \brief This file is an example about page 23 | * Put some comments here 24 | */ 25 | // Dolibarr environment 26 | $res = @include("../../main.inc.php"); // From htdocs directory 27 | if (! $res) { 28 | $res = @include("../../../main.inc.php"); // From "custom" directory 29 | } 30 | 31 | // Libraries 32 | require_once DOL_DOCUMENT_ROOT . "/core/lib/admin.lib.php"; 33 | require_once '../lib/multiclone.lib.php'; 34 | 35 | // Translations 36 | $langs->load("multiclone@multiclone"); 37 | 38 | // Access control 39 | if (! $user->admin) { 40 | accessforbidden(); 41 | } 42 | 43 | /* 44 | * View 45 | */ 46 | $page_name = "multicloneAbout"; 47 | llxHeader('', $langs->trans($page_name)); 48 | 49 | // Subheader 50 | $linkback = '' 51 | . $langs->trans("BackToModuleList") . ''; 52 | print_fiche_titre($langs->trans($page_name), $linkback); 53 | 54 | // Configuration header 55 | $head = multicloneAdminPrepareHead(); 56 | dol_fiche_head( 57 | $head, 58 | 'about', 59 | $langs->trans("Module104968Name"), 60 | 0, 61 | 'multiclone@multiclone' 62 | ); 63 | 64 | // About page goes here 65 | print '
'; 66 | print '
'.$langs->trans('ATMAbout').'
'; 67 | 68 | dol_fiche_end(); 69 | 70 | print '
'; 71 | print ''; 72 | print '
'; 73 | 74 | llxFooter(); 75 | 76 | $db->close(); -------------------------------------------------------------------------------- /tpl/card.tpl.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
[langs.transnoentities(Ref)][view.showRef;strconv=no]
[langs.transnoentities(Label)][view.showLabel;strconv=no]
[langs.transnoentities(Status)][object.getLibStatut(1);strconv=no]
21 | 22 | 23 | 24 | [onshow;block=begin;when [view.mode]='edit'] 25 |
26 | 27 | 28 | [onshow;block=begin;when [object.getId()]+-0] 29 | 30 | 31 | [onshow;block=end] 32 | 33 | [onshow;block=begin;when [object.getId()]=0] 34 | 35 | [onshow;block=end] 36 | 37 | 38 | 39 |
40 | [onshow;block=end] 41 | 42 | [onshow;block=begin;when [view.mode]!='edit'] 43 |
44 | [onshow;block=begin;when [user.rights.multiclone.write;noerr]=1] 45 | 46 | [onshow;block=begin;when [object.status]=[Tmulticlone.STATUS_DRAFT]] 47 | 48 | 49 | 50 | 51 | [onshow;block=end] 52 | 53 | [onshow;block=begin;when [object.status]=[Tmulticlone.STATUS_VALIDATED]] 54 | 55 | 56 | 57 | [onshow;block=end] 58 | 59 | 60 | 61 | 62 | [onshow;block=begin;when [object.status]-+[Tmulticlone.STATUS_REFUSED]] 63 | 64 | 65 | 66 | [onshow;block=end] 67 | 68 | [onshow;block=end] 69 |
70 | [onshow;block=end] -------------------------------------------------------------------------------- /langs/fr_FR/multiclone.lang: -------------------------------------------------------------------------------- 1 | Module104968Name = Multiclone 2 | Module104968Desc = Permettre de cloner des documents documents en spécifiant le nombre de clones et la fréquence de clonage en mois 3 | 4 | ATMAbout = Ce module a été développé par ATM Consulting
Vous pouvez retrouver la documentation sur notre wiki

Pour toute question technique ou retour, contactez-nous sur support@atm-consulting.fr

Pour toute question commerciale, contactez-nous sur contact@atm-consulting.fr ou au +33 9 77 19 50 70

Retrouvez nos autres modules sur Dolistore 5 | 6 | multicloneSetup = Configuration du module multiclone 7 | multicloneAbout = À propos du module multiclone 8 | 9 | multiclone=multiclone 10 | 11 | # MENU 12 | TopMenumulticlone=multiclone 13 | 14 | # STATUS 15 | multicloneStatusDraft=Brouillon (à valider) 16 | multicloneStatusValidated=Validée (à accepter) 17 | multicloneStatusRefused=Refusée (fermée) 18 | multicloneStatusAccepted=Acceptée (fermée) 19 | 20 | Draft=Brouillon 21 | Validate=Validé 22 | Refused=Refusé 23 | Accepted=Accepté 24 | 25 | # LIST 26 | multicloneList=Liste multiclone 27 | Nomulticlone=(vide) 28 | 29 | # CARD 30 | Newmulticlone=Création multiclone 31 | multicloneCard=Fiche multiclone 32 | 33 | # CARD TPL 34 | Save=Enregistrer 35 | CreateDraft=Créer brouillon 36 | Cancel=Annuler 37 | Validate=Valider 38 | Modify=Modifier 39 | Reopen=Rouvrir 40 | ToClone=Cloner 41 | Delete=Supprimer 42 | 43 | #Formconfirm 44 | 45 | Clone=Cloner 46 | CloneFrequency=Fréquence du clone (en mois) 47 | CloneQty=Nombre de clones 48 | MulticloneMaxAuthorizedValueReached=Le nombre de clones saisi (%s) est supérieur au maximum de clones autorisés dans la configuration (%s) 49 | ErrorMulticlone=Une erreur est survenue durant le clone : %s 50 | 51 | ConfirmClonepropal=Êtes-vous sûr(e) de vouloir cloner la proposition commerciale %s ? 52 | ConfirmClonecommande=Êtes-vous sûr(e) de vouloir cloner la commande %s ? 53 | ConfirmClonefacture=Êtes-vous sûr(e) de vouloir cloner la facture %s ? 54 | ConfirmCloneinvoice_supplier=Êtes-vous sûr(e) de vouloir cloner la facture fournisseur %s ? 55 | ConfirmClonechargesociales=Êtes-vous sûr(e) de vouloir cloner la charge sociale %s ? 56 | ConfirmClonesalary=Êtes-vous sûr(e) de vouloir cloner le salaire %s ? 57 | 58 | SelectUser=Sélectionner un utilisateur 59 | 60 | # Warning no date (before formconfirm) 61 | WarningNoDeliveryDateSet=Attention : la date de livraison n’est pas renseignée. La fréquence du clone sera ignorée. 62 | WarningNoPaymentDeadlineSet=Attention : la date limite de règlement de la facture n’est pas renseignée. La fréquence du clone sera ignorée. 63 | 64 | #SETUP PAGE 65 | BackToModuleList = Retour à la liste des modules 66 | AdvancedParameters = Paramètres avancés 67 | ValidatePropalOnClone = Passer au statut "validé" les propositions lors du clonage 68 | ValidateOrderOnClone = Passer au statut "validé" les commandes lors du clonage 69 | ValidateInvoiceOnClone = Passer au statut "validé" les factures lors du clonage 70 | ActivateForObject = Activer Multiclone sur les %s 71 | MaxAuthorizedCloneValue = Valeur maximale de clones autorisée (100 par défaut) 72 | FeatureNotAvailableForThisDolVersion = Fonctionnalité non disponible avec votre version actuelle de Dolibarr.
Nécessite la version 16.0 de Dolibarr. 73 | FeatureRequireModSalariesEnabled=Nécessite que le module Salaires soit activé. 74 | FeatureRequireModTaxEnabled=Nécessite que le module Taxes soit activé. -------------------------------------------------------------------------------- /core/triggers/interface_99_modmulticlone_multiclonetrigger.class.php: -------------------------------------------------------------------------------- 1 | 4 | * Copyright (C) 2015 ATM Consulting 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * \file core/triggers/interface_99_modMyodule_multiclonetrigger.class.php 22 | * \ingroup multiclone 23 | * \brief Sample trigger 24 | * \remarks You can create other triggers by copying this one 25 | * - File name should be either: 26 | * interface_99_modMulticlone_Mytrigger.class.php 27 | * interface_99_all_Mytrigger.class.php 28 | * - The file must stay in core/triggers 29 | * - The class name must be InterfaceMytrigger 30 | * - The constructor method must be named InterfaceMytrigger 31 | * - The name property name must be Mytrigger 32 | */ 33 | 34 | /** 35 | * Trigger class 36 | */ 37 | class Interfacemulticlonetrigger 38 | { 39 | 40 | private $db; 41 | 42 | /** 43 | * Constructor 44 | * 45 | * @param DoliDB $db Database handler 46 | */ 47 | public function __construct($db) 48 | { 49 | $this->db = $db; 50 | 51 | $this->name = preg_replace('/^Interface/i', '', get_class($this)); 52 | $this->family = "demo"; 53 | $this->description = "Triggers of this module are empty functions." 54 | ."They have no effect." 55 | ."They are provided for tutorial purpose only."; 56 | // 'development', 'experimental', 'dolibarr' or version 57 | $this->version = 'development'; 58 | $this->picto = 'multiclone@multiclone'; 59 | } 60 | 61 | /** 62 | * Trigger name 63 | * 64 | * @return string Name of trigger file 65 | */ 66 | public function getName() 67 | { 68 | return $this->name; 69 | } 70 | 71 | /** 72 | * Trigger description 73 | * 74 | * @return string Description of trigger file 75 | */ 76 | public function getDesc() 77 | { 78 | return $this->description; 79 | } 80 | 81 | /** 82 | * Trigger version 83 | * 84 | * @return string Version of trigger file 85 | */ 86 | public function getVersion() 87 | { 88 | global $langs; 89 | $langs->load("admin"); 90 | 91 | if ($this->version == 'development') 92 | { 93 | return $langs->trans("Development"); 94 | } 95 | elseif ($this->version == 'experimental') 96 | return $langs->trans("Experimental"); 97 | elseif ($this->version == 'dolibarr') 98 | return DOL_VERSION; 99 | elseif ($this->version) 100 | return $this->version; 101 | else 102 | { 103 | return $langs->trans("Unknown"); 104 | } 105 | } 106 | 107 | /** 108 | * Function called when a Dolibarrr business event is done. 109 | * All functions "run_trigger" are triggered if file 110 | * is inside directory core/triggers 111 | * 112 | * @param string $action Event action code 113 | * @param Commande|Facture|Propal $object Object 114 | * @param User $user Object user 115 | * @param Translate $langs Object langs 116 | * @param conf $conf Object conf 117 | * @return int <0 if KO, 0 if no triggered ran, >0 if OK 118 | */ 119 | public function run_trigger($action, $object, $user, $langs, $conf) 120 | { 121 | // Put here code you want to execute when a Dolibarr business events occurs. 122 | // Data and type of action are stored into $object and $action 123 | // Users 124 | global $user, $db, $conf; 125 | 126 | 127 | return 0; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /lib/multiclone.lib.php: -------------------------------------------------------------------------------- 1 | 3 | * Copyright (C) 2015 ATM Consulting 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /** 20 | * \file lib/multiclone.lib.php 21 | * \ingroup multiclone 22 | * \brief This file is an example module library 23 | * Put some comments here 24 | */ 25 | 26 | function multicloneAdminPrepareHead() 27 | { 28 | global $langs, $conf, $object; 29 | 30 | $langs->load("multiclone@multiclone"); 31 | 32 | $h = 0; 33 | $head = array(); 34 | 35 | $head[$h][0] = dol_buildpath("/multiclone/admin/multiclone_setup.php", 1); 36 | $head[$h][1] = $langs->trans("Parameters"); 37 | $head[$h][2] = 'settings'; 38 | $h++; 39 | $head[$h][0] = dol_buildpath("/multiclone/admin/multiclone_about.php", 1); 40 | $head[$h][1] = $langs->trans("About"); 41 | $head[$h][2] = 'about'; 42 | $h++; 43 | 44 | // Show more tabs from modules 45 | // Entries must be declared in modules descriptor with line 46 | //$this->tabs = array( 47 | // 'entity:+tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__' 48 | //); // to add new tab 49 | //$this->tabs = array( 50 | // 'entity:-tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__' 51 | //); // to remove a tab 52 | complete_head_from_modules($conf, $langs, $object, $head, $h, 'multiclone'); 53 | 54 | return $head; 55 | } 56 | 57 | /** 58 | * Return array of tabs to used on pages for third parties cards. 59 | * 60 | * @param Tmulticlone $object Object company shown 61 | * @return array Array of tabs 62 | */ 63 | function multiclone_prepare_head(Tmulticlone $object) 64 | { 65 | global $db, $langs, $conf, $user; 66 | $h = 0; 67 | $head = array(); 68 | $head[$h][0] = dol_buildpath('/multiclone/card.php', 1).'?id='.$object->getId(); 69 | $head[$h][1] = $langs->trans("multicloneCard"); 70 | $head[$h][2] = 'card'; 71 | $h++; 72 | 73 | // Show more tabs from modules 74 | // Entries must be declared in modules descriptor with line 75 | // $this->tabs = array('entity:+tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__'); to add new tab 76 | // $this->tabs = array('entity:-tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__'); to remove a tab 77 | complete_head_from_modules($conf,$langs,$object,$head,$h,'multiclone'); 78 | 79 | return $head; 80 | } 81 | 82 | function getFormConfirmmulticlone(&$PDOdb, &$form, &$object, $action) 83 | { 84 | global $langs,$conf,$user; 85 | 86 | $formconfirm = ''; 87 | 88 | if ($action == 'validate' && $user->hasRight('multiclone', 'write')) 89 | { 90 | $text = $langs->trans('ConfirmValidatemulticlone', $object->ref); 91 | $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('Validatemulticlone'), $text, 'confirm_validate', '', 0, 1); 92 | } 93 | elseif ($action == 'delete' && $user->hasRight('multiclone', 'write')) 94 | { 95 | $text = $langs->trans('ConfirmDeletemulticlone'); 96 | $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('Deletemulticlone'), $text, 'confirm_delete', '', 0, 1); 97 | } 98 | elseif ($action == 'clone' && $user->hasRight('multiclone', 'write')) 99 | { 100 | $text = $langs->trans('ConfirmClonemulticlone', $object->ref); 101 | $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('Clonemulticlone'), $text, 'confirm_clone', '', 0, 1); 102 | } 103 | 104 | return $formconfirm; 105 | } -------------------------------------------------------------------------------- /img/multiclone_object.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 45 | 48 | 53 | 58 | 59 | 61 | 62 | 64 | image/svg+xml 65 | 67 | 68 | 69 | 70 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /img/multiclone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 45 | 48 | 53 | 58 | 59 | 61 | 62 | 64 | image/svg+xml 65 | 67 | 68 | 69 | 70 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 117 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /class/actions_multiclone.class.php: -------------------------------------------------------------------------------- 1 | 4 | * Copyright (C) 2015 ATM Consulting 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * \file class/actions_multiclone.class.php 22 | * \ingroup multiclone 23 | * \brief This file is an example hook overload class file 24 | * Put some comments here 25 | */ 26 | 27 | /** 28 | * Class Actionsmulticlone 29 | */ 30 | require_once __DIR__ . '/../backport/v19/core/class/commonhookactions.class.php'; 31 | 32 | class Actionsmulticlone extends multiclone\RetroCompatCommonHookActions 33 | { 34 | 35 | /** 36 | * @var array Hook results. Propagated to $hookmanager->resArray for later reuse 37 | */ 38 | public $results = array(); 39 | 40 | /** 41 | * @var string String displayed by executeHook() immediately after return 42 | */ 43 | public $resprints; 44 | 45 | /** 46 | * @var array Errors 47 | */ 48 | public $errors = array(); 49 | 50 | /** 51 | * Constructor 52 | */ 53 | public function __construct() 54 | { 55 | 56 | } 57 | 58 | /** 59 | * Overloading the doActions function : replacing the parent's function with the one below 60 | * 61 | * @param array() $parameters Hook metadatas (context, etc...) 62 | * @param CommonObject &$object The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...) 63 | * @param string &$action Current action (if set). Generally create or edit or null 64 | * @param HookManager $hookmanager Hook manager propagated to allow calling another hook 65 | * @return int < 0 on error, 0 on success, 1 to replace standard code 66 | */ 67 | function doActions($parameters, &$object, &$action, $hookmanager) { 68 | global $conf, $langs, $db; 69 | 70 | if ((in_array('ordercard', explode(':', $parameters['context'])) && getDolGlobalInt('MULTICLONE_ACTIVATE_FOR_ORDER')) 71 | || (in_array('invoicecard', explode(':', $parameters['context'])) && getDolGlobalInt('MULTICLONE_ACTIVATE_FOR_INVOICE')) 72 | || (in_array('invoicesuppliercard', explode(':', $parameters['context'])) && getDolGlobalInt('MULTICLONE_ACTIVATE_FOR_SUPPLIER_INVOICE')) 73 | || (in_array('propalcard', explode(':', $parameters['context'])) && getDolGlobalInt('MULTICLONE_ACTIVATE_FOR_PROPAL')) 74 | || (in_array('salarycard', explode(':', $parameters['context'])) && getDolGlobalInt('MULTICLONE_ACTIVATE_FOR_SALARY')) 75 | || (in_array('taxcard', explode(':', $parameters['context'])) && getDolGlobalInt('MULTICLONE_ACTIVATE_FOR_TAX'))) { 76 | // Passage à l'action multiclone dès lors que l'action clone est encleché 77 | // Pas de traitement de l'action clone : remplacé par le traitement de l'action multiclone 78 | if ($action === 'clone') { 79 | $action = 'multiclone'; 80 | } elseif ($action === 'confirm_multiclone') { 81 | dol_include_once('/multiclone/class/multiclone.class.php'); 82 | 83 | $qty = GETPOST('cloneqty', 'int'); 84 | $frequency = GETPOSTINT('frequency'); 85 | if (empty($frequency)) { 86 | $frequency = 1; 87 | } 88 | $socid = GETPOST('socid', 'int'); 89 | if (empty($socid)){ 90 | $idToSend = GETPOST('userid', 'int'); 91 | } else { 92 | $idToSend = $socid; 93 | } 94 | 95 | multiclone::multiCreateFromClone($object, $qty, $frequency, $idToSend); 96 | } 97 | } 98 | } 99 | 100 | function formConfirm($parameters, &$object, &$action, $hookmanager) { 101 | global $langs; 102 | 103 | dol_include_once('multiclone/class/multiclone.class.php'); 104 | if (in_array('ordercard', explode(':', $parameters['context'])) 105 | || in_array('invoicecard', explode(':', $parameters['context'])) 106 | || in_array('invoicesuppliercard', explode(':', $parameters['context'])) 107 | || in_array('propalcard', explode(':', $parameters['context'])) 108 | || in_array('salarycard', explode(':', $parameters['context'])) 109 | || in_array('taxcard', explode(':', $parameters['context']))) { 110 | if ($action == 'multiclone') { 111 | $langs->load('multiclone@multiclone'); 112 | //On check que les date soit rempli, sinon pas de traitement de la fréquence 113 | switch ($object->element) { 114 | case 'commande': 115 | if (empty($object->delivery_date)) { 116 | $messageKey = 'WarningNoDeliveryDateSet'; 117 | setEventMessage($langs->trans($messageKey), 'warnings'); 118 | } 119 | break; 120 | case 'facture': 121 | case 'invoice_supplier': 122 | if (empty($object->date)) { 123 | $messageKey = 'WarningNoInvoiceDateSet'; 124 | setEventMessage($langs->trans($messageKey), 'warnings'); 125 | } 126 | break; 127 | case 'propal': 128 | if (empty($object->date)) { 129 | $messageKey = 'WarningNoPropalDateSet'; 130 | setEventMessage($langs->trans($messageKey), 'warnings'); 131 | } 132 | break; 133 | // Pour ceux-là, les champs de date sont nécéssaires à la création, pas besoin de vérifier 134 | case 'salary': 135 | case 'chargesociales': 136 | default: 137 | break; 138 | 139 | } 140 | print multiclone::getFormConfirmClone($object); 141 | return 1; 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /admin/multiclone_setup.php: -------------------------------------------------------------------------------- 1 | 3 | * Copyright (C) 2021 ATM Consulting 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /** 20 | * \file multiclone/admin/setup.php 21 | * \ingroup multiclone 22 | * \brief Multiclone setup page. 23 | */ 24 | 25 | // Load Dolibarr environment 26 | $res = 0; 27 | // Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) 28 | if(! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; 29 | // Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME 30 | $tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; 31 | $tmp2 = realpath(__FILE__); 32 | $i = strlen($tmp) - 1; 33 | $j = strlen($tmp2) - 1; 34 | while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { 35 | $i--; 36 | $j--; 37 | } 38 | if(! $res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; 39 | if(! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; 40 | // Try main.inc.php using relative path 41 | if(! $res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php"; 42 | if(! $res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php"; 43 | if(! $res) die("Include of main fails"); 44 | 45 | global $langs, $user, $conf; 46 | $inputCount = 1; 47 | 48 | // Libraries 49 | require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php"; 50 | require_once '../lib/multiclone.lib.php'; 51 | 52 | // Translations 53 | $langs->loadLangs(array("multiclone@multiclone", "bills", "propal", "orders", "salaries", "compta", "admin")); 54 | 55 | // Access control 56 | if(! $user->admin) accessforbidden(); 57 | 58 | // Parameters 59 | $action = GETPOST('action', 'alpha'); 60 | $backtopage = GETPOST('backtopage', 'alpha'); 61 | $value = GETPOST('value', 'alpha'); 62 | 63 | /* 64 | * Actions 65 | */ 66 | 67 | if((float) DOL_VERSION >= 6) { 68 | include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php'; 69 | } 70 | 71 | /* 72 | * View 73 | */ 74 | $page_name = "multicloneSetup"; 75 | llxHeader('', $langs->trans($page_name)); 76 | 77 | // Subheader 78 | $linkback = ''. $langs->trans("BackToModuleList") . ''; 79 | 80 | print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup'); 81 | 82 | // Configuration header 83 | $head = multicloneAdminPrepareHead(); 84 | print dol_get_fiche_head($head,'settings', $langs->trans("ModulemulticloneName"), -1,"multiclone@multiclone"); 85 | 86 | // Setup page goes here 87 | $var = 0; 88 | 89 | print '
'; 90 | print ''; 91 | 92 | print ''; 93 | 94 | _setupPrintTitle($langs->trans("Parameters")); 95 | 96 | _printOnOff('MULTICLONE_VALIDATE_PROPAL', $langs->trans("ValidatePropalOnClone")); 97 | _printOnOff('MULTICLONE_VALIDATE_ORDER', $langs->trans("ValidateOrderOnClone")); 98 | _printOnOff('MULTICLONE_VALIDATE_INVOICE', $langs->trans("ValidateInvoiceOnClone")); 99 | 100 | _setupPrintTitle($langs->trans("AdvancedParameters")); 101 | 102 | if (isModEnabled('propal')) { 103 | _printOnOff('MULTICLONE_ACTIVATE_FOR_PROPAL', $langs->trans("ActivateForObject", $langs->trans('Proposals'))); 104 | } 105 | 106 | if (isModEnabled('commande')) { 107 | _printOnOff('MULTICLONE_ACTIVATE_FOR_ORDER', $langs->trans("ActivateForObject", $langs->trans('Orders'))); 108 | } 109 | 110 | if (isModEnabled('facture')) { 111 | _printOnOff('MULTICLONE_ACTIVATE_FOR_INVOICE', $langs->trans("ActivateForObject", $langs->trans('Invoices'))); 112 | } 113 | 114 | if (isModEnabled('fournisseur')) { 115 | _printOnOff('MULTICLONE_ACTIVATE_FOR_SUPPLIER_INVOICE', $langs->trans("ActivateForObject", $langs->trans('BillsSuppliers'))); 116 | } 117 | 118 | if(!isModEnabled('tax')) { 119 | _printInputFormPart('', $langs->trans("ActivateForObject", $langs->trans('SocialContributions')), '', array(), '', $langs->trans('FeatureRequireModTaxEnabled')); 120 | } else { 121 | _printOnOff('MULTICLONE_ACTIVATE_FOR_TAX', $langs->trans("ActivateForObject", $langs->trans('SocialContributions'))); 122 | } 123 | 124 | if(!isModEnabled('salaries')) { 125 | _printInputFormPart('', $langs->trans("ActivateForObject", $langs->trans('Salaries')), '', array(), '', $langs->trans('FeatureRequireModSalariesEnabled')); 126 | } else { 127 | _printOnOff('MULTICLONE_ACTIVATE_FOR_SALARY', $langs->trans("ActivateForObject", $langs->trans('Salaries'))); 128 | } 129 | 130 | 131 | 132 | if (!getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')) { 133 | dolibarr_set_const($db, 'MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE', 100); 134 | } 135 | 136 | $metas = array('type' => 'number', 'min' => 0, 'placeholder' => 100); 137 | _printInputFormPart('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE', $langs->trans("MaxAuthorizedCloneValue"), '', $metas); 138 | 139 | 140 | print '
'; 141 | 142 | _updateBtn(); 143 | 144 | print '
'; 145 | 146 | llxFooter(); 147 | 148 | $db->close(); 149 | 150 | /** 151 | * Display title 152 | * 153 | * @param string $title 154 | */ 155 | function _setupPrintTitle($title = "", $width = 300) { 156 | global $langs; 157 | print ''; 158 | print ''.$langs->trans($title).''."\n"; 159 | print ''; 160 | } 161 | 162 | /** 163 | * Print an update button 164 | * 165 | * @return void 166 | */ 167 | function _updateBtn() { 168 | global $langs; 169 | print '
'; 170 | print ''; 171 | print '
'; 172 | } 173 | 174 | /** 175 | * Print a On/Off button 176 | * 177 | * @param string $confkey the conf key 178 | * @param bool $title Title of conf 179 | * @param string $desc Description 180 | * 181 | * @return void 182 | */ 183 | function _printOnOff($confkey, $title = false, $desc = '') { 184 | global $var, $bc, $langs; 185 | print ''; 186 | print ''.($title ? $title : $langs->trans($confkey)); 187 | if(! empty($desc)) { 188 | print '
'.$langs->trans($desc).''; 189 | } 190 | print ''; 191 | print ' '; 192 | print ''; 193 | print ajax_constantonoff($confkey); 194 | print ''; 195 | } 196 | 197 | /** 198 | * Print a form part 199 | * 200 | * @param string $confkey the conf key 201 | * @param bool $title Title of conf 202 | * @param string $desc Description of 203 | * @param array $metas html meta 204 | * @param string $type type of input textarea or input 205 | * @param bool $help help description 206 | * 207 | * @return void 208 | */ 209 | function _printInputFormPart($confkey, $title = false, $desc = '', $metas = [], $type = 'input', $help = false, $moreHtmlBefore = '', $moreHtmlAfter = '') { 210 | global $var, $bc, $langs, $conf, $db, $inputCount; 211 | $var = ! $var; 212 | _curentInputIndex(true); 213 | $form = new Form($db); 214 | 215 | $defaultMetas = [ 216 | 'name' => _curentInputValue() 217 | ]; 218 | 219 | if($type != 'textarea') { 220 | $defaultMetas['type'] = 'text'; 221 | $defaultMetas['value'] = getDolGlobalString($confkey); 222 | } 223 | 224 | $metas = array_merge($defaultMetas, $metas); 225 | $metascompil = ''; 226 | foreach($metas as $key => $values) { 227 | $metascompil .= ' '.$key.'="'.$values.'" '; 228 | } 229 | 230 | print ''; 231 | print ''; 232 | 233 | if(! empty($help)) { 234 | print $form->textwithtooltip(($title ? $title : $langs->trans($confkey)), $langs->trans($help), 2, 1, img_help(1, '')); 235 | } 236 | else { 237 | print $title ? $title : $langs->trans($confkey); 238 | } 239 | 240 | if(! empty($desc)) { 241 | print '
'.$langs->trans($desc).''; 242 | } 243 | 244 | print ''; 245 | print ' '; 246 | print ''; 247 | 248 | print $moreHtmlBefore; 249 | 250 | print _curentParam($confkey); 251 | 252 | print ''; 253 | if($type == 'textarea') { 254 | print ''; 255 | } 256 | else if($type == 'input') { 257 | print ''; 258 | } 259 | else { 260 | print $type; 261 | } 262 | 263 | print $moreHtmlAfter; 264 | 265 | print ''; 266 | } 267 | 268 | function _curentInputIndex($next = false) { 269 | global $inputCount; 270 | 271 | if(empty($inputCount)) { 272 | $inputCount = 1; 273 | } 274 | 275 | if($next) { 276 | $inputCount++; 277 | } 278 | 279 | return $inputCount; 280 | } 281 | 282 | function _curentParam($confkey) { 283 | return ''; 284 | } 285 | 286 | function _curentInputValue($offset = 0) { 287 | return 'value'.(_curentInputIndex() + $offset); 288 | } 289 | -------------------------------------------------------------------------------- /class/multiclone.class.php: -------------------------------------------------------------------------------- 1 | loadLangs(array('multiclone@multiclone', 'salaries')); 10 | $form = new Form($db); 11 | 12 | $elem = $object->element; 13 | $filter = 's.client IN(1,'.($object->element === 'propal' ? '2,' : '').'3)'; 14 | if (version_compare(DOL_VERSION, '18', '>=')) $filter = '(s.client:IN:1,'.($object->element === 'propal' ? '2,' : '').'3)'; 15 | 16 | if ($elem == 'salary' || $elem == 'chargesociales'){ 17 | $other_question = array('type' => 'other', 'name' => 'userid', 'label' => $langs->trans("SelectUser"), 'value' => $form->select_dolusers($object->fk_user, 'userid', 1)); 18 | } else { 19 | $other_question = array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company($object->socid, 'socid', $filter, '', 0, 0, array(), 0, 'minwidth300')); 20 | } 21 | $formquestion = array( 22 | array('type' => 'other', 'name' => 'cloneqty', 'label' => $langs->trans("CloneQty"), 'value' => ''), 23 | array('type' => 'other', 'name' => 'frequency', 'label' => $langs->trans("CloneFrequency"), 'value' => ''), 24 | $other_question 25 | ); 26 | 27 | $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans("Clone"), $langs->trans("ConfirmClone$elem", $object->ref), 'confirm_multiclone', $formquestion, 'yes', 1); 28 | 29 | return $formconfirm; 30 | } 31 | 32 | static function createFromCloneCustom($socid = 0, $object,$frequency=0) 33 | { 34 | global $user, $hookmanager,$conf; 35 | 36 | $error = 0; 37 | 38 | $object->context['createfromclone'] = 'createfromclone'; 39 | $object->context['createfromclonecustom'] = 'createfromclone'; 40 | 41 | $object->db->begin(); 42 | 43 | // get extrafields so they will be clone 44 | foreach ($object->lines as $line) 45 | $line->fetch_optionals($line->rowid); 46 | 47 | // Load source object 48 | $objFrom = clone $object; 49 | 50 | // Change socid if needed 51 | if (!empty($socid) && $socid != $object->socid) 52 | { 53 | $objsoc = new Societe($object->db); 54 | 55 | if ($objsoc->fetch($socid) > 0) 56 | { 57 | $object->socid = $objsoc->id; 58 | $object->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0); 59 | $object->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0); 60 | $object->fk_project = ''; 61 | $object->fk_delivery_address = ''; 62 | } 63 | 64 | // TODO Change product price if multi-prices 65 | } 66 | 67 | $object->id = 0; 68 | $object->ref = ''; 69 | $object->statut = 0; 70 | 71 | // Clear fields 72 | $object->user_author_id = $user->id; 73 | $object->user_valid = ''; 74 | $object->date = dol_now(); 75 | if($object->element == 'facture' && ! empty($frequency))$object->date = strtotime("+$frequency month", $objFrom->date); 76 | if($object->element == 'commande')$object->date_commande = dol_now(); 77 | $object->date_creation = ''; 78 | $object->date_validation = ''; 79 | $object->ref_client = ''; 80 | 81 | // Create clone 82 | $result = $object->create($user); 83 | $object->add_object_linked($object->element, $objFrom->id); 84 | 85 | if($object->element == 'facture' && getDolGlobalInt('MULTICLONE_VALIDATE_INVOICE')) $object->validate($user); 86 | else if(($object->element == 'propal' && getDolGlobalInt('MULTICLONE_VALIDATE_PROPAL')) || ($object->element == 'commande' && getDolGlobalInt('MULTICLONE_VALIDATE_ORDER'))) $object->valid($user); 87 | 88 | if ($result < 0) 89 | $error++; 90 | 91 | 92 | 93 | unset($object->context['createfromclone']); 94 | 95 | // End 96 | if (!$error) 97 | { 98 | $object->db->commit(); 99 | return $object->id; 100 | } 101 | else 102 | { 103 | $object->db->rollback(); 104 | return -1; 105 | } 106 | } 107 | 108 | /** 109 | * @param Object $object 110 | * @param int $qty 111 | * @param int $frequency 112 | * @param int $socid 113 | * @return void 114 | * @throws Exception 115 | */ 116 | static function multiCreateFromClone($object, $qty, $frequency, $socid) 117 | { 118 | global $db, $langs, $user, $conf; 119 | 120 | $db->begin(); 121 | $compteur = 0; 122 | $error = 0; 123 | $langs->load('multiclone@multiclone'); 124 | 125 | if (getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE') && $qty > getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')) { 126 | setEventMessage($langs->trans('MulticloneMaxAuthorizedValueReached', $qty, getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')), 'errors'); 127 | header("Location: ".$_SERVER["PHP_SELF"]."?id=".$object->id); 128 | exit; 129 | } 130 | 131 | // Récupération des dates devant être clonées en fonction de l'objet 132 | $TDatesToClone = self::getDateToClone($object); 133 | 134 | // Contrainte d'unicité sur la référence fournisseur (la référence fournisseur doit être unique si même tiers et même entité) 135 | if ($object->element == 'invoice_supplier') $ref_supplier = $object->ref_supplier; 136 | 137 | while ($compteur<$qty){ 138 | $compteur++; 139 | switch ($object->element) { 140 | case 'propal': 141 | $propal = $object; 142 | $id_clone = $propal->createFromClone($user); 143 | if ($id_clone > 0) { 144 | $propal_clone = new Propal($db); 145 | $res = $propal_clone->fetch($id_clone); 146 | if ($res < 0 ) { 147 | $error++; 148 | break; 149 | } 150 | 151 | $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); 152 | 153 | $propal_clone->date = $TNewDates[0]; 154 | 155 | //Unset de la date de livraison (la spec ne demande pas que cette date soit prise en compte dans le clone) 156 | $propal_clone->delivery_date = null; 157 | 158 | //On définit le tiers concerné par le/les clones 159 | $propal_clone->socid = $socid; 160 | 161 | if (getDolGlobalInt('MULTICLONE_VALIDATE_PROPAL')) $propal_clone->valid($user); 162 | 163 | $res_update = $propal_clone->update($user); 164 | if ($res_update<0) { 165 | $error++; 166 | break; 167 | } 168 | } else { 169 | $error++; 170 | break; 171 | } 172 | break; 173 | 174 | case 'commande': 175 | $order = $object; 176 | $id_clone = $order->createFromClone($user); 177 | if ($id_clone > 0) { 178 | $order_clone = new Commande($db); 179 | $res = $order_clone->fetch($id_clone); 180 | if ($res < 0 ) { 181 | $error++; 182 | break; 183 | } 184 | 185 | $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); 186 | 187 | $order_clone->date_commande = $TNewDates[0]; 188 | $order_clone->delivery_date = $TNewDates[1] ?? null; 189 | 190 | //On définit le tiers concerné par le/les clones 191 | $order_clone->socid = $socid; 192 | 193 | if (getDolGlobalInt('MULTICLONE_VALIDATE_ORDER')) $order_clone->valid($user); 194 | 195 | $res_update = $order_clone->update($user); 196 | if ($res_update<0) { 197 | $error++; 198 | break; 199 | } 200 | } else { 201 | $error++; 202 | break; 203 | } 204 | break; 205 | 206 | case 'facture': 207 | $facture = $object; 208 | $id_clone = $facture->createFromClone($user, $object->id); 209 | if ($id_clone > 0) { 210 | $facture_clone = new Facture($db); 211 | $res = $facture_clone->fetch($id_clone); 212 | if ($res < 0 ) { 213 | $error++; 214 | break; 215 | } 216 | 217 | $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); 218 | 219 | $facture_clone->date = $TNewDates[0]; 220 | $facture_clone->date_lim_reglement = $TNewDates[1]; 221 | 222 | //On définit le tiers concerné par le/les clones 223 | $facture_clone->socid = $socid; 224 | //Conditions et mode de règlement ne sont pas clonés par la fonction CreateFromClone 225 | $facture_clone->cond_reglement_id = $facture->cond_reglement_id; 226 | $facture_clone->mode_reglement_id = $facture->mode_reglement_id; 227 | 228 | if(getDolGlobalInt('MULTICLONE_VALIDATE_INVOICE')) $facture_clone->validate($user); 229 | 230 | $res_update = $facture_clone->update($user); 231 | if ($res_update<0) { 232 | $error++; 233 | break; 234 | } 235 | } else { 236 | $error++; 237 | break; 238 | } 239 | break; 240 | 241 | case 'invoice_supplier': 242 | $supplier_invoice = $object; 243 | $supplier_invoice->ref_supplier = $ref_supplier.'-'.$compteur; 244 | $id_clone = $supplier_invoice->createFromClone($user, $object->id); 245 | 246 | if ($id_clone > 0) { 247 | $supplier_invoice_clone = new FactureFournisseur($db); 248 | $res = $supplier_invoice_clone->fetch($id_clone); 249 | if ($res < 0 ) { 250 | $error++; 251 | break; 252 | } 253 | 254 | $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); 255 | 256 | $supplier_invoice_clone->date = $TNewDates[0]; 257 | 258 | //On définit le tiers concerné par le/les clones 259 | $supplier_invoice_clone->socid = $socid; 260 | 261 | $res_update = $supplier_invoice_clone->update($user); 262 | if ($res_update<0) { 263 | $error++; 264 | break; 265 | } 266 | } else { 267 | $error++; 268 | break; 269 | } 270 | break; 271 | 272 | case 'salary': 273 | $salary = new Salary($db); 274 | $res = $salary->fetch($object->id); 275 | if ($res < 0 ) { 276 | $error++; 277 | break; 278 | } 279 | 280 | //On vide l'id et la ref (comme le fait l'action confirm_clone du module salary) 281 | //Ces champs seront remplis grâce à la fonction create 282 | $salary->id = $salary->ref = null; 283 | //Nommage des nouveaux salaires en fonction de la quantité demandée 284 | $salary->label = $langs->trans("CopyOf") . ' ' . $object->label . ' (' . $compteur . ')'; 285 | 286 | $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); 287 | 288 | $salary->datesp = $TNewDates[0]; 289 | $salary->dateep = $TNewDates[1]; 290 | 291 | //On définit le salarié concerné par le/les clones 292 | $salary->fk_user = $socid; 293 | 294 | //On crée le clone 295 | $id_clone = $salary->create($user); 296 | if ($id_clone <= 0) { 297 | $error++; 298 | break; 299 | } 300 | break; 301 | 302 | case 'chargesociales': 303 | $charges = new ChargeSociales($db); 304 | $res = $charges->fetch($object->id); 305 | if ($res < 0 ) { 306 | $error++; 307 | break; 308 | } 309 | 310 | //On vide l'id et la ref (comme le fait l'action confirm_clone du module chargesociales) 311 | //Ces champs seront remplis grâce à la fonction create 312 | $charges->id = $charges->ref = null; 313 | //Nommage des nouvelles charges sociales en fonction de la quantité demandée 314 | $charges->label = $object->label; 315 | 316 | $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); 317 | 318 | $charges->date_ech = $TNewDates[0]; 319 | $charges->period = $TNewDates[1]; 320 | 321 | //On définit le salarié concerné par le/les clones 322 | $charges->fk_user = $socid; 323 | 324 | //On crée le clone 325 | $id_clone = $charges->create($user); 326 | if ($id_clone <= 0) { 327 | $error++; 328 | break; 329 | } 330 | break; 331 | 332 | default: 333 | break; 334 | } 335 | } 336 | 337 | if ($error>0){ 338 | $db->rollback(); 339 | setEventMessage($langs->trans("ErrorMulticlone", $db->lasterror()), 'errors'); 340 | } else { 341 | $db->commit(); 342 | $db->close(); 343 | 344 | header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id_clone); 345 | exit; 346 | } 347 | } 348 | 349 | static function setFactureDate($objFrom,$object,$frequency) 350 | { 351 | global $db; 352 | $old_date_lim_reglement = $objFrom->date_lim_reglement; 353 | 354 | $object->date=strtotime("+$frequency month", $objFrom->date); 355 | $new_date_lim_reglement = $object->calculate_date_lim_reglement(); 356 | if ($new_date_lim_reglement > $old_date_lim_reglement) $object->date_lim_reglement = $new_date_lim_reglement; 357 | if ($object->date_lim_reglement < $object->date) $object->date_lim_reglement = $object->date; 358 | 359 | $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture SET datef="'.$db->idate($object->date).'", date_lim_reglement="'. $db->idate($object->date_lim_reglement).'" WHERE rowid='.$object->id; 360 | $resql = $db->query($sql); 361 | 362 | } 363 | 364 | /** 365 | * @param array $TDatesToClone 366 | * @param int $frequency 367 | * @param int $compteur 368 | * @return array 369 | * @throws Exception 370 | */ 371 | static function calcNewDate($TDatesToClone, $frequency, $compteur) 372 | { 373 | //On calcule les nouvelles dates 374 | if (! empty($TDatesToClone)) { 375 | 376 | $TNewDates = array(); 377 | foreach ($TDatesToClone as $i => $dateToClone) { 378 | if (!empty($dateToClone)) { 379 | $object_date_origin[$i] = date('Y-m-d', intval($dateToClone)); 380 | $last_day_of_this_month[$i] = date("Y-m-t", intval($dateToClone)); 381 | 382 | // Utilisation de l'objet DateTime plus performant 383 | $object_date_to_clone[$i] = new DateTime($object_date_origin[$i]); 384 | $object_last_day_of_month[$i] = new DateTime($last_day_of_this_month[$i]); 385 | 386 | if ($object_date_to_clone[$i] == $object_last_day_of_month[$i]) $object_newdate = $object_date_to_clone[$i]->modify('last day of +' . $frequency * $compteur. ' month'); 387 | else $object_newdate = $object_date_to_clone[$i]->modify('+' . $frequency * $compteur. ' month'); 388 | 389 | $TNewDates[] = $object_newdate->getTimestamp(); 390 | } 391 | } 392 | } 393 | 394 | return $TNewDates; 395 | } 396 | 397 | /** 398 | * @param Object $object 399 | * @return array 400 | */ 401 | static function getDateToClone($object) 402 | { 403 | $TDatesToClone = array(); 404 | 405 | switch ($object->element) { 406 | case 'propal' : 407 | $TDatesToClone['origin_date'] = $object->date; 408 | break; 409 | 410 | case 'commande': 411 | $TDatesToClone['origin_date'] = $object->date; 412 | $TDatesToClone['origin_delivery_date'] = $object->delivery_date; 413 | break; 414 | 415 | case 'facture' : 416 | $TDatesToClone['origin_date'] = $object->date; 417 | $TDatesToClone['origin_date_lim_reglement'] = $object->date_lim_reglement; 418 | break; 419 | 420 | case 'invoice_supplier': 421 | $TDatesToClone['origin_date'] = $object->date; 422 | break; 423 | 424 | case 'salary' : 425 | $TDatesToClone['origin_datesp'] = $object->datesp; 426 | $TDatesToClone['origin_dateep'] = $object->dateep; 427 | break; 428 | 429 | case 'chargesociales' : 430 | $TDatesToClone['origin_dateech'] = $object->date_ech; 431 | $TDatesToClone['origin_period'] = $object->periode; 432 | break; 433 | 434 | default: 435 | break; 436 | } 437 | 438 | return $TDatesToClone; 439 | } 440 | } 441 | 442 | -------------------------------------------------------------------------------- /core/modules/modmulticlone.class.php: -------------------------------------------------------------------------------- 1 | 3 | * Copyright (C) 2004-2012 Laurent Destailleur 4 | * Copyright (C) 2005-2012 Regis Houssin 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * \defgroup multiclone Module multiclone 22 | * \brief Example of a module descriptor. 23 | * Such a file must be copied into htdocs/multiclone/core/modules directory. 24 | * \file htdocs/multiclone/core/modules/modmulticlone.class.php 25 | * \ingroup multiclone 26 | * \brief Description and activation file for module multiclone 27 | */ 28 | include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; 29 | 30 | 31 | /** 32 | * Description and activation class for module multiclone 33 | */ 34 | class modmulticlone extends DolibarrModules 35 | { 36 | /** 37 | * Constructor. Define names, constants, directories, boxes, permissions 38 | * 39 | * @param DoliDB $db Database handler 40 | */ 41 | function __construct($db) 42 | { 43 | global $langs,$conf; 44 | 45 | $this->db = $db; 46 | 47 | $this->editor_name = 'ATM Consulting'; 48 | $this->editor_url = 'https://www.atm-consulting.fr'; 49 | 50 | // Id for module (must be unique). 51 | // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id). 52 | $this->numero = 104968; // 104000 to 104999 for ATM CONSULTING 53 | // Key text used to identify module (for permissions, menus, etc...) 54 | $this->rights_class = 'multiclone'; 55 | 56 | // Family can be 'crm','financial','hr','projects','products','ecm','technic','other' 57 | // It is used to group modules in module setup page 58 | $this->family = "ATM Consulting"; 59 | // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) 60 | $this->name = preg_replace('/^mod/i','',get_class($this)); 61 | // Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module) 62 | $this->description = "Permettre de cloner en spécifiant le nombre de clones et la fréquence en mois"; 63 | // Possible values for version are: 'development', 'experimental', 'dolibarr' or version 64 | $this->version = '1.4.4'; 65 | // Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase) 66 | $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); 67 | // Where to store the module in setup page (0=common,1=interface,2=others,3=very specific) 68 | $this->special = 0; 69 | // Name of image file used for this module. 70 | // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' 71 | // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' 72 | $this->picto='multiclone_mod@multiclone'; 73 | 74 | // Defined all module parts (triggers, login, substitutions, menus, css, etc...) 75 | // for default path (eg: /multiclone/core/xxxxx) (0=disable, 1=enable) 76 | // for specific path of parts (eg: /multiclone/core/modules/barcode) 77 | // for specific css file (eg: /multiclone/css/multiclone.css.php) 78 | //$this->module_parts = array( 79 | // 'triggers' => 0, // Set this to 1 if module has its own trigger directory (core/triggers) 80 | // 'login' => 0, // Set this to 1 if module has its own login method directory (core/login) 81 | // 'substitutions' => 0, // Set this to 1 if module has its own substitution function file (core/substitutions) 82 | // 'menus' => 0, // Set this to 1 if module has its own menus handler directory (core/menus) 83 | // 'theme' => 0, // Set this to 1 if module has its own theme directory (theme) 84 | // 'tpl' => 0, // Set this to 1 if module overwrite template dir (core/tpl) 85 | // 'barcode' => 0, // Set this to 1 if module has its own barcode directory (core/modules/barcode) 86 | // 'models' => 0, // Set this to 1 if module has its own models directory (core/modules/xxx) 87 | // 'css' => array('/multiclone/css/multiclone.css.php'), // Set this to relative path of css file if module has its own css file 88 | // 'js' => array('/multiclone/js/multiclone.js'), // Set this to relative path of js file if module must load a js on all pages 89 | // 'hooks' => array('hookcontext1','hookcontext2') // Set here all hooks context managed by module 90 | // 'dir' => array('output' => 'othermodulename'), // To force the default directories names 91 | // 'workflow' => array('WORKFLOW_MODULE1_YOURACTIONTYPE_MODULE2'=>array('enabled'=>'! empty($conf->module1->enabled) && ! empty($conf->module2->enabled)', 'picto'=>'yourpicto@multiclone')) // Set here all workflow context managed by module 92 | // ); 93 | $this->module_parts = array( 94 | 'triggers' => 1, 95 | 'hooks' => array( 96 | 'ordercard', 97 | 'invoicecard', 98 | 'propalcard', 99 | 'salarycard', 100 | 'taxcard', 101 | 'invoicesuppliercard' 102 | ) 103 | ); 104 | 105 | // Data directories to create when module is enabled. 106 | // Example: this->dirs = array("/multiclone/temp"); 107 | $this->dirs = array(); 108 | 109 | // Config pages. Put here list of php page, stored into multiclone/admin directory, to use to setup module. 110 | $this->config_page_url = array("multiclone_setup.php@multiclone"); 111 | 112 | // Dependencies 113 | $this->hidden = false; // A condition to hide module 114 | $this->depends = array(); // List of modules id that must be enabled if this module is enabled 115 | $this->requiredby = array(); // List of modules id to disable if this one is disabled 116 | $this->conflictwith = array(); // List of modules id this module is in conflict with 117 | $this->phpmin = array(7,0); // Minimum version of PHP required by module 118 | $this->need_dolibarr_version = array(16,0); // Minimum version of Dolibarr required by module 119 | $this->langfiles = array("multiclone@multiclone"); 120 | 121 | // Constants 122 | // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) 123 | // Example: $this->const=array(0=>array('MYMODULE_MYNEWCONST1','chaine','myvalue','This is a constant to add',1), 124 | // 1=>array('MYMODULE_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1) 125 | // ); 126 | $this->const = array(); 127 | 128 | // Array to add new pages in new tabs 129 | // Example: $this->tabs = array('objecttype:+tabname1:Title1:multiclone@multiclone:$user->rights->multiclone->read:/multiclone/mynewtab1.php?id=__ID__', // To add a new tab identified by code tabname1 130 | // 'objecttype:+tabname2:Title2:multiclone@multiclone:$user->rights->othermodule->read:/multiclone/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2 131 | // 'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname 132 | // where objecttype can be 133 | // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) 134 | // 'contact' to add a tab in contact view 135 | // 'contract' to add a tab in contract view 136 | // 'group' to add a tab in group view 137 | // 'intervention' to add a tab in intervention view 138 | // 'invoice' to add a tab in customer invoice view 139 | // 'invoice_supplier' to add a tab in supplier invoice view 140 | // 'member' to add a tab in fundation member view 141 | // 'opensurveypoll' to add a tab in opensurvey poll view 142 | // 'order' to add a tab in customer order view 143 | // 'order_supplier' to add a tab in supplier order view 144 | // 'payment' to add a tab in payment view 145 | // 'payment_supplier' to add a tab in supplier payment view 146 | // 'product' to add a tab in product view 147 | // 'propal' to add a tab in propal view 148 | // 'project' to add a tab in project view 149 | // 'stock' to add a tab in stock view 150 | // 'thirdparty' to add a tab in third party view 151 | // 'user' to add a tab in user view 152 | $this->tabs = array(); 153 | 154 | // Dictionaries 155 | if (!isModEnabled('multiclone')) 156 | { 157 | $conf->multiclone=new stdClass(); 158 | $conf->multiclone->enabled=0; 159 | } 160 | $this->dictionaries=array(); 161 | /* Example: 162 | if (! isset($conf->multiclone->enabled)) $conf->multiclone->enabled=0; // This is to avoid warnings 163 | $this->dictionaries=array( 164 | 'langs'=>'multiclone@multiclone', 165 | 'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), // List of tables we want to see into dictonnary editor 166 | 'tablib'=>array("Table1","Table2","Table3"), // Label of tables 167 | 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), // Request to select fields 168 | 'tabsqlsort'=>array("label ASC","label ASC","label ASC"), // Sort order 169 | 'tabfield'=>array("code,label","code,label","code,label"), // List of fields (result of select to show dictionary) 170 | 'tabfieldvalue'=>array("code,label","code,label","code,label"), // List of fields (list of fields to edit a record) 171 | 'tabfieldinsert'=>array("code,label","code,label","code,label"), // List of fields (list of fields for insert) 172 | 'tabrowid'=>array("rowid","rowid","rowid"), // Name of columns with primary key (try to always name it 'rowid') 173 | 'tabcond'=>array($conf->multiclone->enabled,$conf->multiclone->enabled,$conf->multiclone->enabled) // Condition to show each dictionary 174 | ); 175 | */ 176 | 177 | // Boxes 178 | // Add here list of php file(s) stored in core/boxes that contains class to show a box. 179 | $this->boxes = array(); // List of boxes 180 | // Example: 181 | //$this->boxes=array(array(0=>array('file'=>'myboxa.php','note'=>'','enabledbydefaulton'=>'Home'),1=>array('file'=>'myboxb.php','note'=>''),2=>array('file'=>'myboxc.php','note'=>''));); 182 | 183 | // Permissions 184 | $this->rights = array(); // Permission array used by this module 185 | $r=0; 186 | 187 | // Add here list of permission defined by an id, a label, a boolean and two constant strings. 188 | // Example: 189 | // $this->rights[$r][0] = $this->numero . $r; // Permission id (must not be already used) 190 | // $this->rights[$r][1] = 'Permision label'; // Permission label 191 | // $this->rights[$r][3] = 1; // Permission by default for new user (0/1) 192 | // $this->rights[$r][4] = 'level1'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) 193 | // $this->rights[$r][5] = 'level2'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) 194 | // $r++; 195 | /* 196 | $this->rights[$r][0] = $this->numero . $r; // Permission id (must not be already used) 197 | $this->rights[$r][1] = 'multiclone_read'; // Permission label 198 | $this->rights[$r][3] = 1; // Permission by default for new user (0/1) 199 | $this->rights[$r][4] = 'read'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) 200 | $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) 201 | $r++; 202 | 203 | $this->rights[$r][0] = $this->numero . $r; // Permission id (must not be already used) 204 | $this->rights[$r][1] = 'multiclone_write'; // Permission label 205 | $this->rights[$r][3] = 1; // Permission by default for new user (0/1) 206 | $this->rights[$r][4] = 'write'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) 207 | $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) 208 | $r++; 209 | */ 210 | 211 | // Main menu entries 212 | $this->menu = array(); // List of menus to add 213 | $r=0; 214 | 215 | // Add here entries to declare new menus 216 | // 217 | // Example to declare a new Top Menu entry and its Left menu entry: 218 | // $this->menu[$r]=array( 'fk_menu'=>'fk_mainmenu=multiclone', // Put 0 if this is a single top menu or keep fk_mainmenu to give an entry on left 219 | // 'type'=>'top', // This is a Top menu entry 220 | // 'titre'=>'multiclone top menu', 221 | // 'mainmenu'=>'multiclone', 222 | // 'leftmenu'=>'multiclone_left', // This is the name of left menu for the next entries 223 | // 'url'=>'/multiclone/pagetop.php', 224 | // 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 225 | // 'position'=>100, 226 | // 'enabled'=>'$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->multiclone->enabled' if entry must be visible if module is enabled. 227 | // 'perms'=>'1', // Use 'perms'=>'$user->rights->multiclone->level1->level2' if you want your menu with a permission rules 228 | // 'target'=>'', 229 | // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both 230 | // $r++; 231 | // 232 | // Example to declare a Left Menu entry into an existing Top menu entry: 233 | // $this->menu[$r]=array( 'fk_menu'=>'fk_mainmenu=multiclone,fk_leftmenu=multiclone_left', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 234 | // 'type'=>'left', // This is a Left menu entry 235 | // 'titre'=>'multiclone left menu', 236 | // 'mainmenu'=>'multiclone', 237 | // 'leftmenu'=>'multiclone_left', // Goes into left menu previously created by the mainmenu 238 | // 'url'=>'/multiclone/pagelevel2.php', 239 | // 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 240 | // 'position'=>100, 241 | // 'enabled'=>'$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->multiclone->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. 242 | // 'perms'=>'1', // Use 'perms'=>'$user->rights->multiclone->level1->level2' if you want your menu with a permission rules 243 | // 'target'=>'', 244 | // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both 245 | // $r++; 246 | 247 | /* 248 | $this->menu[$r]=array( 249 | 'fk_menu'=>0, // Put 0 if this is a top menu 250 | 'type'=>'top', // This is a Top menu entry 251 | 'titre'=>$langs->trans('TopMenumulticlone'), 252 | 'mainmenu'=>'multiclone', 253 | 'leftmenu'=>'', 254 | 'url'=>'/multiclone/list.php', 255 | 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 256 | 'position'=>100+$r, 257 | 'enabled'=>'$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->missionorder->enabled' if entry must be visible if module is enabled. 258 | 'perms'=>'$user->rights->multiclone->read', // Use 'perms'=>'$user->rights->missionorder->level1->level2' if you want your menu with a permission rules 259 | 'target'=>'', 260 | 'user'=>2 261 | ); 262 | $r++; 263 | 264 | $this->menu[$r]=array( 265 | 'fk_menu'=>'fk_mainmenu=multiclone', // Put 0 if this is a top menu 266 | 'type'=>'left', // This is a Top menu entry 267 | 'titre'=>$langs->trans('TopMenumulticlone'), 268 | 'mainmenu'=>'multiclone', 269 | 'leftmenu'=>'multiclone_left', 270 | 'url'=>'/multiclone/list.php', 271 | 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 272 | 'position'=>100+$r, 273 | 'enabled'=>'$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->missionorder->enabled' if entry must be visible if module is enabled. 274 | 'perms'=>'$user->rights->multiclone->read', // Use 'perms'=>'$user->rights->missionorder->level1->level2' if you want your menu with a permission rules 275 | 'target'=>'', 276 | 'user'=>2 277 | ); 278 | $r++; 279 | 280 | $this->menu[$r]=array( 281 | 'fk_menu'=>'fk_mainmenu=multiclone,fk_leftmenu=multiclone_left', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 282 | 'type'=>'left', // This is a Left menu entry 283 | 'titre'=>$langs->trans('LeftMenumulticloneCreate'), 284 | 'mainmenu'=>'multiclone', 285 | 'leftmenu'=>'multiclone_left_create', 286 | 'url'=>'/multiclone/card.php?action=create', 287 | 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 288 | 'position'=>100+$r, 289 | 'enabled'=> '$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->missionorder->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. 290 | 'perms'=> '$user->rights->multiclone->write', // Use 'perms'=>'$user->rights->missionorder->level1->level2' if you want your menu with a permission rules 291 | 'target'=>'', 292 | 'user'=>2 293 | ); // 0=Menu for internal users, 1=external users, 2=both 294 | $r++; 295 | 296 | 297 | $this->menu[$r]=array( 298 | 'fk_menu'=>'fk_mainmenu=multiclone,fk_leftmenu=multiclone_left', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 299 | 'type'=>'left', // This is a Left menu entry 300 | 'titre'=>$langs->trans('LeftMenumulticloneList'), 301 | 'mainmenu'=>'multiclone', 302 | 'leftmenu'=>'multiclone_left_list', 303 | 'url'=>'/multiclone/list.php', 304 | 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 305 | 'position'=>100+$r, 306 | 'enabled'=> '$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->missionorder->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. 307 | 'perms'=> '$user->rights->multiclone->write', // Use 'perms'=>'$user->rights->missionorder->level1->level2' if you want your menu with a permission rules 308 | 'target'=>'', 309 | 'user'=>2 310 | ); // 0=Menu for internal users, 1=external users, 2=both 311 | $r++; 312 | */ 313 | 314 | // Exports 315 | $r=1; 316 | 317 | // Example: 318 | // $this->export_code[$r]=$this->rights_class.'_'.$r; 319 | // $this->export_label[$r]='CustomersInvoicesAndInvoiceLines'; // Translation key (used only if key ExportDataset_xxx_z not found) 320 | // $this->export_enabled[$r]='1'; // Condition to show export in list (ie: '$user->id==3'). Set to 1 to always show when module is enabled. 321 | // $this->export_permission[$r]=array(array("facture","facture","export")); 322 | // $this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'CompanyName','s.address'=>'Address','s.zip'=>'Zip','s.town'=>'Town','s.fk_pays'=>'Country','s.phone'=>'Phone','s.siren'=>'ProfId1','s.siret'=>'ProfId2','s.ape'=>'ProfId3','s.idprof4'=>'ProfId4','s.code_compta'=>'CustomerAccountancyCode','s.code_compta_fournisseur'=>'SupplierAccountancyCode','f.rowid'=>"InvoiceId",'f.facnumber'=>"InvoiceRef",'f.datec'=>"InvoiceDateCreation",'f.datef'=>"DateInvoice",'f.total'=>"TotalHT",'f.total_ttc'=>"TotalTTC",'f.tva'=>"TotalVAT",'f.paye'=>"InvoicePaid",'f.fk_statut'=>'InvoiceStatus','f.note'=>"InvoiceNote",'fd.rowid'=>'LineId','fd.description'=>"LineDescription",'fd.price'=>"LineUnitPrice",'fd.tva_tx'=>"LineVATRate",'fd.qty'=>"LineQty",'fd.total_ht'=>"LineTotalHT",'fd.total_tva'=>"LineTotalTVA",'fd.total_ttc'=>"LineTotalTTC",'fd.date_start'=>"DateStart",'fd.date_end'=>"DateEnd",'fd.fk_product'=>'ProductId','p.ref'=>'ProductRef'); 323 | // $this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company','s.zip'=>'company','s.town'=>'company','s.fk_pays'=>'company','s.phone'=>'company','s.siren'=>'company','s.siret'=>'company','s.ape'=>'company','s.idprof4'=>'company','s.code_compta'=>'company','s.code_compta_fournisseur'=>'company','f.rowid'=>"invoice",'f.facnumber'=>"invoice",'f.datec'=>"invoice",'f.datef'=>"invoice",'f.total'=>"invoice",'f.total_ttc'=>"invoice",'f.tva'=>"invoice",'f.paye'=>"invoice",'f.fk_statut'=>'invoice','f.note'=>"invoice",'fd.rowid'=>'invoice_line','fd.description'=>"invoice_line",'fd.price'=>"invoice_line",'fd.total_ht'=>"invoice_line",'fd.total_tva'=>"invoice_line",'fd.total_ttc'=>"invoice_line",'fd.tva_tx'=>"invoice_line",'fd.qty'=>"invoice_line",'fd.date_start'=>"invoice_line",'fd.date_end'=>"invoice_line",'fd.fk_product'=>'product','p.ref'=>'product'); 324 | // $this->export_sql_start[$r]='SELECT DISTINCT '; 325 | // $this->export_sql_end[$r] =' FROM ('.MAIN_DB_PREFIX.'facture as f, '.MAIN_DB_PREFIX.'facturedet as fd, '.MAIN_DB_PREFIX.'societe as s)'; 326 | // $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on (fd.fk_product = p.rowid)'; 327 | // $this->export_sql_end[$r] .=' WHERE f.fk_soc = s.rowid AND f.rowid = fd.fk_facture'; 328 | // $this->export_sql_order[$r] .=' ORDER BY s.nom'; 329 | // $r++; 330 | } 331 | 332 | /** 333 | * Function called when module is enabled. 334 | * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. 335 | * It also creates data directories 336 | * 337 | * @param string $options Options when enabling module ('', 'noboxes') 338 | * @return int 1 if OK, 0 if KO 339 | */ 340 | function init($options='') 341 | { 342 | $sql = array(); 343 | 344 | define('INC_FROM_DOLIBARR',true); 345 | 346 | dol_include_once('/multiclone/config.php'); 347 | dol_include_once('/multiclone/script/create-maj-base.php'); 348 | 349 | $result=$this->_load_tables('/multiclone/sql/'); 350 | 351 | return $this->_init($sql, $options); 352 | } 353 | 354 | /** 355 | * Function called when module is disabled. 356 | * Remove from database constants, boxes and permissions from Dolibarr database. 357 | * Data directories are not deleted 358 | * 359 | * @param string $options Options when enabling module ('', 'noboxes') 360 | * @return int 1 if OK, 0 if KO 361 | */ 362 | function remove($options='') 363 | { 364 | $sql = array(); 365 | 366 | return $this->_remove($sql, $options); 367 | } 368 | 369 | } 370 | --------------------------------------------------------------------------------