Passed
Push — master ( 65bdac...4e88da )
by Alxarafe
32:38
created
Helpers/triggers/interface_20_all_Logevents.class.php 1 patch
Indentation   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -31,41 +31,41 @@  discard block
 block discarded – undo
31 31
  */
32 32
 class InterfaceLogevents extends DolibarrTriggers
33 33
 {
34
-	/**
35
-	 * @var string Image of the trigger
36
-	 */
37
-	public $picto = 'technic';
38
-
39
-	public $family = 'core';
40
-
41
-	public $description = "Triggers of this module allows to add security event records inside Dolibarr.";
42
-
43
-	/**
44
-	 * Version of the trigger
45
-	 * @var string
46
-	 */
47
-	public $version = self::VERSION_DOLIBARR;
48
-
49
-	/**
50
-	 * Function called when a Dolibarrr business event is done.
51
-	 * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
52
-	 *
53
-	 * @param string		$action		Event action code
54
-	 * @param Object		$object     Object
55
-	 * @param User			$user       Object user
56
-	 * @param Translate		$langs      Object langs
57
-	 * @param conf			$conf       Object conf
58
-	 * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
59
-	 */
60
-	public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
34
+    /**
35
+     * @var string Image of the trigger
36
+     */
37
+    public $picto = 'technic';
38
+
39
+    public $family = 'core';
40
+
41
+    public $description = "Triggers of this module allows to add security event records inside Dolibarr.";
42
+
43
+    /**
44
+     * Version of the trigger
45
+     * @var string
46
+     */
47
+    public $version = self::VERSION_DOLIBARR;
48
+
49
+    /**
50
+     * Function called when a Dolibarrr business event is done.
51
+     * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
52
+     *
53
+     * @param string		$action		Event action code
54
+     * @param Object		$object     Object
55
+     * @param User			$user       Object user
56
+     * @param Translate		$langs      Object langs
57
+     * @param conf			$conf       Object conf
58
+     * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
59
+     */
60
+    public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
61 61
     {
62
-    	if (! empty($conf->global->MAIN_LOGEVENTS_DISABLE_ALL)) return 0;	// Log events is disabled (hidden features)
62
+        if (! empty($conf->global->MAIN_LOGEVENTS_DISABLE_ALL)) return 0;	// Log events is disabled (hidden features)
63 63
 
64
-    	$key='MAIN_LOGEVENTS_'.$action;
65
-    	//dol_syslog("xxxxxxxxxxx".$key);
66
-    	if (empty($conf->global->$key)) return 0;				// Log events not enabled for this action
64
+        $key='MAIN_LOGEVENTS_'.$action;
65
+        //dol_syslog("xxxxxxxxxxx".$key);
66
+        if (empty($conf->global->$key)) return 0;				// Log events not enabled for this action
67 67
 
68
-    	if (empty($conf->entity)) $conf->entity = $entity;  // forcing of the entity if it's not defined (ex: in login form)
68
+        if (empty($conf->entity)) $conf->entity = $entity;  // forcing of the entity if it's not defined (ex: in login form)
69 69
 
70 70
         $date = dol_now();
71 71
 
@@ -106,7 +106,7 @@  discard block
 block discarded – undo
106 106
             // Initialisation donnees (date,duree,texte,desc)
107 107
             $text=$langs->transnoentities("NewUserCreated",$object->login);
108 108
             $desc=$langs->transnoentities("NewUserCreated",$object->login);
109
-		}
109
+        }
110 110
         elseif ($action == 'USER_MODIFY')
111 111
         {
112 112
             dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
@@ -130,16 +130,16 @@  discard block
 block discarded – undo
130 130
             dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
131 131
             $langs->load("users");
132 132
             // Initialisation donnees (date,duree,texte,desc)
133
-			if ($object->statut == 0)
134
-			{
135
-				$text=$langs->transnoentities("UserEnabled",$object->login);
136
-				$desc=$langs->transnoentities("UserEnabled",$object->login);
137
-			}
138
-			if ($object->statut == 1)
139
-			{
140
-				$text=$langs->transnoentities("UserDisabled",$object->login);
141
-				$desc=$langs->transnoentities("UserDisabled",$object->login);
142
-			}
133
+            if ($object->statut == 0)
134
+            {
135
+                $text=$langs->transnoentities("UserEnabled",$object->login);
136
+                $desc=$langs->transnoentities("UserEnabled",$object->login);
137
+            }
138
+            if ($object->statut == 1)
139
+            {
140
+                $text=$langs->transnoentities("UserDisabled",$object->login);
141
+                $desc=$langs->transnoentities("UserDisabled",$object->login);
142
+            }
143 143
         }
144 144
         elseif ($action == 'USER_DELETE')
145 145
         {
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
             $desc=$langs->transnoentities("UserDeleted",$object->login);
151 151
         }
152 152
 
153
-		// Groupes
153
+        // Groupes
154 154
         elseif ($action == 'GROUP_CREATE')
155 155
         {
156 156
             dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
@@ -158,7 +158,7 @@  discard block
 block discarded – undo
158 158
             // Initialisation donnees (date,duree,texte,desc)
159 159
             $text=$langs->transnoentities("NewGroupCreated",$object->name);
160 160
             $desc=$langs->transnoentities("NewGroupCreated",$object->name);
161
-		}
161
+        }
162 162
         elseif ($action == 'GROUP_MODIFY')
163 163
         {
164 164
             dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
@@ -166,7 +166,7 @@  discard block
 block discarded – undo
166 166
             // Initialisation donnees (date,duree,texte,desc)
167 167
             $text=$langs->transnoentities("GroupModified",$object->name);
168 168
             $desc=$langs->transnoentities("GroupModified",$object->name);
169
-		}
169
+        }
170 170
         elseif ($action == 'GROUP_DELETE')
171 171
         {
172 172
             dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
@@ -174,9 +174,9 @@  discard block
 block discarded – undo
174 174
             // Initialisation donnees (date,duree,texte,desc)
175 175
             $text=$langs->transnoentities("GroupDeleted",$object->name);
176 176
             $desc=$langs->transnoentities("GroupDeleted",$object->name);
177
-		}
177
+        }
178 178
 
179
-		// If not found
179
+        // If not found
180 180
 /*
181 181
         else
182 182
         {
@@ -185,18 +185,18 @@  discard block
 block discarded – undo
185 185
         }
186 186
 */
187 187
 
188
-		// Add more information into desc from the context property
189
-		if (! empty($desc) && ! empty($object->context['audit'])) $desc.=' - '.$object->context['audit'];
188
+        // Add more information into desc from the context property
189
+        if (! empty($desc) && ! empty($object->context['audit'])) $desc.=' - '.$object->context['audit'];
190 190
 
191 191
         // Add entry in event table
192
-		include_once DOL_DOCUMENT_ROOT.'/core/class/events.class.php';
192
+        include_once DOL_DOCUMENT_ROOT.'/core/class/events.class.php';
193 193
 
194
-		$event=new Events($this->db);
194
+        $event=new Events($this->db);
195 195
         $event->type=$action;
196 196
         $event->dateevent=$date;
197 197
         $event->label=$text;
198 198
         $event->description=$desc;
199
-		$event->user_agent=$_SERVER["HTTP_USER_AGENT"];
199
+        $event->user_agent=$_SERVER["HTTP_USER_AGENT"];
200 200
 
201 201
         $result=$event->create($user);
202 202
         if ($result > 0)
Please login to merge, or discard this patch.
Helpers/triggers/interface_50_modAgenda_ActionsAuto.class.php 1 patch
Indentation   +350 added lines, -350 removed lines patch added patch discarded remove patch
@@ -34,58 +34,58 @@  discard block
 block discarded – undo
34 34
  */
35 35
 class InterfaceActionsAuto extends DolibarrTriggers
36 36
 {
37
-	public $family = 'agenda';
38
-	public $description = "Triggers of this module add actions in agenda according to setup made in agenda setup.";
39
-
40
-	/**
41
-	 * Version of the trigger
42
-	 * @var string
43
-	 */
44
-	public $version = self::VERSION_DOLIBARR;
45
-
46
-	/**
47
-	 * @var string Image of the trigger
48
-	 */
49
-	public $picto = 'action';
50
-
51
-	/**
52
-	 * Function called when a Dolibarrr business event is done.
53
-	 * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
54
-	 *
55
-	 * Following properties may be set before calling trigger. The may be completed by this trigger to be used for writing the event into database:
56
-	 *      $object->actiontypecode (translation action code: AC_OTH, ...)
57
-	 *      $object->actionmsg (note, long text)
58
-	 *      $object->actionmsg2 (label, short text)
59
-	 *      $object->sendtoid (id of contact or array of ids)
60
-	 *      $object->socid (id of thirdparty)
61
-	 *      $object->fk_project
62
-	 *      $object->fk_element
63
-	 *      $object->elementtype
64
-	 *
65
-	 * @param string		$action		Event action code
66
-	 * @param Object		$object     Object
67
-	 * @param User		    $user       Object user
68
-	 * @param Translate 	$langs      Object langs
69
-	 * @param conf		    $conf       Object conf
70
-	 * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
71
-	 */
72
-	public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
73
-	{
37
+    public $family = 'agenda';
38
+    public $description = "Triggers of this module add actions in agenda according to setup made in agenda setup.";
39
+
40
+    /**
41
+     * Version of the trigger
42
+     * @var string
43
+     */
44
+    public $version = self::VERSION_DOLIBARR;
45
+
46
+    /**
47
+     * @var string Image of the trigger
48
+     */
49
+    public $picto = 'action';
50
+
51
+    /**
52
+     * Function called when a Dolibarrr business event is done.
53
+     * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
54
+     *
55
+     * Following properties may be set before calling trigger. The may be completed by this trigger to be used for writing the event into database:
56
+     *      $object->actiontypecode (translation action code: AC_OTH, ...)
57
+     *      $object->actionmsg (note, long text)
58
+     *      $object->actionmsg2 (label, short text)
59
+     *      $object->sendtoid (id of contact or array of ids)
60
+     *      $object->socid (id of thirdparty)
61
+     *      $object->fk_project
62
+     *      $object->fk_element
63
+     *      $object->elementtype
64
+     *
65
+     * @param string		$action		Event action code
66
+     * @param Object		$object     Object
67
+     * @param User		    $user       Object user
68
+     * @param Translate 	$langs      Object langs
69
+     * @param conf		    $conf       Object conf
70
+     * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
71
+     */
72
+    public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
73
+    {
74 74
         if (empty($conf->agenda->enabled)) return 0;     // Module not active, we do nothing
75 75
 
76
-		$key = 'MAIN_AGENDA_ACTIONAUTO_'.$action;
76
+        $key = 'MAIN_AGENDA_ACTIONAUTO_'.$action;
77 77
 
78
-		// Do not log events not enabled for this action
79
-		if (empty($conf->global->$key)) {
80
-			return 0;
81
-		}
78
+        // Do not log events not enabled for this action
79
+        if (empty($conf->global->$key)) {
80
+            return 0;
81
+        }
82 82
 
83
-		$langs->load("agenda");
83
+        $langs->load("agenda");
84 84
 
85
-		if (empty($object->actiontypecode)) $object->actiontypecode='AC_OTH_AUTO';
85
+        if (empty($object->actiontypecode)) $object->actiontypecode='AC_OTH_AUTO';
86 86
 
87
-		// Actions
88
-		if ($action == 'COMPANY_CREATE')
87
+        // Actions
88
+        if ($action == 'COMPANY_CREATE')
89 89
         {
90 90
             // Load translation files required by the page
91 91
             $langs->loadLangs(array("agenda","other","companies"));
@@ -94,8 +94,8 @@  discard block
 block discarded – undo
94 94
             $object->actionmsg=$langs->transnoentities("NewCompanyToDolibarr",$object->name);
95 95
             if (! empty($object->prefix)) $object->actionmsg.=" (".$object->prefix.")";
96 96
 
97
-			$object->sendtoid=0;
98
-			$object->socid=$object->id;
97
+            $object->sendtoid=0;
98
+            $object->socid=$object->id;
99 99
         }
100 100
         elseif ($action == 'COMPANY_SENTBYMAIL')
101 101
         {
@@ -106,7 +106,7 @@  discard block
 block discarded – undo
106 106
 
107 107
             // Parameters $object->sendtoid defined by caller
108 108
             //$object->sendtoid=0;
109
-		}
109
+        }
110 110
         elseif ($action == 'CONTRACT_VALIDATE')
111 111
         {
112 112
             // Load translation files required by the page
@@ -116,22 +116,22 @@  discard block
 block discarded – undo
116 116
             $object->actionmsg=$langs->transnoentities("ContractValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
117 117
 
118 118
             $object->sendtoid=0;
119
-		}
120
-		elseif ($action == 'CONTRACT_SENTBYMAIL')
121
-		{
122
-			// Load translation files required by the page
119
+        }
120
+        elseif ($action == 'CONTRACT_SENTBYMAIL')
121
+        {
122
+            // Load translation files required by the page
123 123
             $langs->loadLangs(array("agenda","other","contracts"));
124 124
 
125
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ContractSentByEMail",$object->ref);
126
-			if (empty($object->actionmsg))
127
-			{
128
-				$object->actionmsg=$langs->transnoentities("ContractSentByEMail",$object->ref);
129
-			}
125
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ContractSentByEMail",$object->ref);
126
+            if (empty($object->actionmsg))
127
+            {
128
+                $object->actionmsg=$langs->transnoentities("ContractSentByEMail",$object->ref);
129
+            }
130 130
 
131
-			// Parameters $object->sendtoid defined by caller
132
-			//$object->sendtoid=0;
133
-		}
134
-		elseif ($action == 'PROPAL_VALIDATE')
131
+            // Parameters $object->sendtoid defined by caller
132
+            //$object->sendtoid=0;
133
+        }
134
+        elseif ($action == 'PROPAL_VALIDATE')
135 135
         {
136 136
             // Load translation files required by the page
137 137
             $langs->loadLangs(array("agenda","other","propal"));
@@ -139,8 +139,8 @@  discard block
 block discarded – undo
139 139
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
140 140
             $object->actionmsg=$langs->transnoentities("PropalValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
141 141
 
142
-			$object->sendtoid=0;
143
-		}
142
+            $object->sendtoid=0;
143
+        }
144 144
         elseif ($action == 'PROPAL_SENTBYMAIL')
145 145
         {
146 146
             // Load translation files required by the page
@@ -154,8 +154,8 @@  discard block
 block discarded – undo
154 154
 
155 155
             // Parameters $object->sendtoid defined by caller
156 156
             //$object->sendtoid=0;
157
-		}
158
-		elseif ($action == 'PROPAL_CLOSE_SIGNED')
157
+        }
158
+        elseif ($action == 'PROPAL_CLOSE_SIGNED')
159 159
         {
160 160
             // Load translation files required by the page
161 161
             $langs->loadLangs(array("agenda","other","propal"));
@@ -163,9 +163,9 @@  discard block
 block discarded – undo
163 163
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedSignedInDolibarr",$object->ref);
164 164
             $object->actionmsg=$langs->transnoentities("PropalClosedSignedInDolibarr",$object->ref);
165 165
 
166
-			$object->sendtoid=0;
167
-		}
168
-		elseif ($action == 'PROPAL_CLASSIFY_BILLED')
166
+            $object->sendtoid=0;
167
+        }
168
+        elseif ($action == 'PROPAL_CLASSIFY_BILLED')
169 169
         {
170 170
             // Load translation files required by the page
171 171
             $langs->loadLangs(array("agenda","other","propal"));
@@ -173,9 +173,9 @@  discard block
 block discarded – undo
173 173
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClassifiedBilledInDolibarr",$object->ref);
174 174
             $object->actionmsg=$langs->transnoentities("PropalClassifiedBilledInDolibarr",$object->ref);
175 175
 
176
-			$object->sendtoid=0;
177
-		}
178
-		elseif ($action == 'PROPAL_CLOSE_REFUSED')
176
+            $object->sendtoid=0;
177
+        }
178
+        elseif ($action == 'PROPAL_CLOSE_REFUSED')
179 179
         {
180 180
             // Load translation files required by the page
181 181
             $langs->loadLangs(array("agenda","other","propal"));
@@ -183,9 +183,9 @@  discard block
 block discarded – undo
183 183
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedRefusedInDolibarr",$object->ref);
184 184
             $object->actionmsg=$langs->transnoentities("PropalClosedRefusedInDolibarr",$object->ref);
185 185
 
186
-			$object->sendtoid=0;
187
-		}
188
-		elseif ($action == 'ORDER_VALIDATE')
186
+            $object->sendtoid=0;
187
+        }
188
+        elseif ($action == 'ORDER_VALIDATE')
189 189
         {
190 190
             // Load translation files required by the page
191 191
             $langs->loadLangs(array("agenda","orders"));
@@ -193,9 +193,9 @@  discard block
 block discarded – undo
193 193
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
194 194
             $object->actionmsg=$langs->transnoentities("OrderValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
195 195
 
196
-			$object->sendtoid=0;
197
-		}
198
-		elseif ($action == 'ORDER_CLOSE')
196
+            $object->sendtoid=0;
197
+        }
198
+        elseif ($action == 'ORDER_CLOSE')
199 199
         {
200 200
             // Load translation files required by the page
201 201
             $langs->loadLangs(array("agenda","other","orders"));
@@ -203,9 +203,9 @@  discard block
 block discarded – undo
203 203
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderDeliveredInDolibarr",$object->ref);
204 204
             $object->actionmsg=$langs->transnoentities("OrderDeliveredInDolibarr",$object->ref);
205 205
 
206
-			$object->sendtoid=0;
207
-		}
208
-		elseif ($action == 'ORDER_CLASSIFY_BILLED')
206
+            $object->sendtoid=0;
207
+        }
208
+        elseif ($action == 'ORDER_CLASSIFY_BILLED')
209 209
         {
210 210
             // Load translation files required by the page
211 211
             $langs->loadLangs(array("agenda","other","orders"));
@@ -213,9 +213,9 @@  discard block
 block discarded – undo
213 213
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderBilledInDolibarr",$object->ref);
214 214
             $object->actionmsg=$langs->transnoentities("OrderBilledInDolibarr",$object->ref);
215 215
 
216
-			$object->sendtoid=0;
217
-		}
218
-		elseif ($action == 'ORDER_CANCEL')
216
+            $object->sendtoid=0;
217
+        }
218
+        elseif ($action == 'ORDER_CANCEL')
219 219
         {
220 220
             // Load translation files required by the page
221 221
             $langs->loadLangs(array("agenda","other","orders"));
@@ -223,9 +223,9 @@  discard block
 block discarded – undo
223 223
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderCanceledInDolibarr",$object->ref);
224 224
             $object->actionmsg=$langs->transnoentities("OrderCanceledInDolibarr",$object->ref);
225 225
 
226
-			$object->sendtoid=0;
227
-		}
228
-		elseif ($action == 'ORDER_SENTBYMAIL')
226
+            $object->sendtoid=0;
227
+        }
228
+        elseif ($action == 'ORDER_SENTBYMAIL')
229 229
         {
230 230
             // Load translation files required by the page
231 231
             $langs->loadLangs(array("agenda","other","orders"));
@@ -238,8 +238,8 @@  discard block
 block discarded – undo
238 238
 
239 239
             // Parameters $object->sendtoid defined by caller
240 240
             //$object->sendtoid=0;
241
-		}
242
-		elseif ($action == 'BILL_VALIDATE')
241
+        }
242
+        elseif ($action == 'BILL_VALIDATE')
243 243
         {
244 244
             // Load translation files required by the page
245 245
             $langs->loadLangs(array("agenda","other","bills"));
@@ -247,18 +247,18 @@  discard block
 block discarded – undo
247 247
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
248 248
             $object->actionmsg=$langs->transnoentities("InvoiceValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
249 249
 
250
-			$object->sendtoid=0;
251
-		}
252
-		elseif ($action == 'BILL_UNVALIDATE')
250
+            $object->sendtoid=0;
251
+        }
252
+        elseif ($action == 'BILL_UNVALIDATE')
253 253
         {
254
-           // Load translation files required by the page
254
+            // Load translation files required by the page
255 255
             $langs->loadLangs(array("agenda","other","bills"));
256 256
 
257 257
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceBackToDraftInDolibarr",$object->ref);
258 258
             $object->actionmsg=$langs->transnoentities("InvoiceBackToDraftInDolibarr",$object->ref);
259 259
 
260
-			$object->sendtoid=0;
261
-		}
260
+            $object->sendtoid=0;
261
+        }
262 262
         elseif ($action == 'BILL_SENTBYMAIL')
263 263
         {
264 264
             // Load translation files required by the page
@@ -272,8 +272,8 @@  discard block
 block discarded – undo
272 272
 
273 273
             // Parameters $object->sendtoid defined by caller
274 274
             //$object->sendtoid=0;
275
-		}
276
-		elseif ($action == 'BILL_PAYED')
275
+        }
276
+        elseif ($action == 'BILL_PAYED')
277 277
         {
278 278
             // Load translation files required by the page
279 279
             $langs->loadLangs(array("agenda","other","bills"));
@@ -283,8 +283,8 @@  discard block
 block discarded – undo
283 283
             $object->actionmsg=$langs->transnoentities("InvoicePaidInDolibarr",$object->ref);
284 284
 
285 285
             $object->sendtoid=0;
286
-		}
287
-		elseif ($action == 'BILL_CANCEL')
286
+        }
287
+        elseif ($action == 'BILL_CANCEL')
288 288
         {
289 289
             // Load translation files required by the page
290 290
             $langs->loadLangs(array("agenda","other","bills"));
@@ -293,8 +293,8 @@  discard block
 block discarded – undo
293 293
             $object->actionmsg=$langs->transnoentities("InvoiceCanceledInDolibarr",$object->ref);
294 294
 
295 295
             $object->sendtoid=0;
296
-		}
297
-		elseif ($action == 'FICHINTER_CREATE')
296
+        }
297
+        elseif ($action == 'FICHINTER_CREATE')
298 298
         {
299 299
             // Load translation files required by the page
300 300
             $langs->loadLangs(array("agenda","other","interventions"));
@@ -303,10 +303,10 @@  discard block
 block discarded – undo
303 303
             $object->actionmsg=$langs->transnoentities("InterventionCreatedInDolibarr",$object->ref);
304 304
 
305 305
             $object->sendtoid=0;
306
-			$object->fk_element=0;
307
-			$object->elementtype='';
308
-		}
309
-		elseif ($action == 'FICHINTER_VALIDATE')
306
+            $object->fk_element=0;
307
+            $object->elementtype='';
308
+        }
309
+        elseif ($action == 'FICHINTER_VALIDATE')
310 310
         {
311 311
             // Load translation files required by the page
312 312
             $langs->loadLangs(array("agenda","other","interventions"));
@@ -315,10 +315,10 @@  discard block
 block discarded – undo
315 315
             $object->actionmsg=$langs->transnoentities("InterventionValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
316 316
 
317 317
             $object->sendtoid=0;
318
-			$object->fk_element=0;
319
-			$object->elementtype='';
320
-		}
321
-		elseif ($action == 'FICHINTER_MODIFY')
318
+            $object->fk_element=0;
319
+            $object->elementtype='';
320
+        }
321
+        elseif ($action == 'FICHINTER_MODIFY')
322 322
         {
323 323
             // Load translation files required by the page
324 324
             $langs->loadLangs(array("agenda","other","interventions"));
@@ -327,10 +327,10 @@  discard block
 block discarded – undo
327 327
             $object->actionmsg=$langs->transnoentities("InterventionModifiedInDolibarr",$object->ref);
328 328
 
329 329
             $object->sendtoid=0;
330
-			$object->fk_element=0;
331
-			$object->elementtype='';
332
-		}
333
-		elseif ($action == 'FICHINTER_SENTBYMAIL')
330
+            $object->fk_element=0;
331
+            $object->elementtype='';
332
+        }
333
+        elseif ($action == 'FICHINTER_SENTBYMAIL')
334 334
         {
335 335
             // Load translation files required by the page
336 336
             $langs->loadLangs(array("agenda","other","interventions"));
@@ -338,7 +338,7 @@  discard block
 block discarded – undo
338 338
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionSentByEMail",$object->ref);
339 339
             if (empty($object->actionmsg))
340 340
             {
341
-            	$object->actionmsg=$langs->transnoentities("InterventionSentByEMail",$object->ref);
341
+                $object->actionmsg=$langs->transnoentities("InterventionSentByEMail",$object->ref);
342 342
             }
343 343
 
344 344
             // Parameters $object->sendtoid defined by caller
@@ -349,18 +349,18 @@  discard block
 block discarded – undo
349 349
             // Load translation files required by the page
350 350
             $langs->loadLangs(array("agenda","other","interventions"));
351 351
 
352
-           	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionClassifiedBilledInDolibarr",$object->ref);
353
-           	$object->actionmsg=$langs->transnoentities("InterventionClassifiedBilledInDolibarr",$object->ref);
352
+                if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionClassifiedBilledInDolibarr",$object->ref);
353
+                $object->actionmsg=$langs->transnoentities("InterventionClassifiedBilledInDolibarr",$object->ref);
354 354
 
355 355
             $object->sendtoid=0;
356 356
         }
357
-	    elseif ($action == 'FICHINTER_CLASSIFY_UNBILLED')
357
+        elseif ($action == 'FICHINTER_CLASSIFY_UNBILLED')
358 358
         {
359 359
             // Load translation files required by the page
360 360
             $langs->loadLangs(array("agenda","other","interventions"));
361 361
 
362
-           	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionClassifiedUnbilledInDolibarr",$object->ref);
363
-           	$object->actionmsg=$langs->transnoentities("InterventionClassifiedUnbilledInDolibarr",$object->ref);
362
+                if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionClassifiedUnbilledInDolibarr",$object->ref);
363
+                $object->actionmsg=$langs->transnoentities("InterventionClassifiedUnbilledInDolibarr",$object->ref);
364 364
 
365 365
             $object->sendtoid=0;
366 366
         }
@@ -373,24 +373,24 @@  discard block
 block discarded – undo
373 373
             $object->actionmsg=$langs->transnoentities("InterventionDeletedInDolibarr",$object->ref);
374 374
 
375 375
             $object->sendtoid=0;
376
-			$object->fk_element=0;
377
-			$object->elementtype='';
378
-		}
376
+            $object->fk_element=0;
377
+            $object->elementtype='';
378
+        }
379 379
         elseif ($action == 'SHIPPING_VALIDATE')
380 380
         {
381 381
             // Load translation files required by the page
382 382
             $langs->loadLangs(array("agenda","other","sendings"));
383 383
 
384
-        	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ShippingValidated",($object->newref?$object->newref:$object->ref));
385
-        	if (empty($object->actionmsg))
386
-        	{
387
-        		$object->actionmsg=$langs->transnoentities("ShippingValidated",($object->newref?$object->newref:$object->ref));
388
-        	}
384
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ShippingValidated",($object->newref?$object->newref:$object->ref));
385
+            if (empty($object->actionmsg))
386
+            {
387
+                $object->actionmsg=$langs->transnoentities("ShippingValidated",($object->newref?$object->newref:$object->ref));
388
+            }
389 389
 
390
-        	// Parameters $object->sendtoid defined by caller
391
-        	//$object->sendtoid=0;
390
+            // Parameters $object->sendtoid defined by caller
391
+            //$object->sendtoid=0;
392 392
         }
393
-		elseif ($action == 'SHIPPING_SENTBYMAIL')
393
+        elseif ($action == 'SHIPPING_SENTBYMAIL')
394 394
         {
395 395
             // Load translation files required by the page
396 396
             $langs->loadLangs(array("agenda","other","sendings"));
@@ -403,22 +403,22 @@  discard block
 block discarded – undo
403 403
 
404 404
             // Parameters $object->sendtoid defined by caller
405 405
             //$object->sendtoid=0;
406
-		} elseif ($action == 'RECEPTION_VALIDATE')
406
+        } elseif ($action == 'RECEPTION_VALIDATE')
407 407
         {
408 408
             $langs->load("agenda");
409 409
             $langs->load("other");
410
-        	$langs->load("receptions");
410
+            $langs->load("receptions");
411 411
 
412
-        	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ReceptionValidated",($object->newref?$object->newref:$object->ref));
413
-        	if (empty($object->actionmsg))
414
-        	{
415
-        		$object->actionmsg=$langs->transnoentities("ReceptionValidated",($object->newref?$object->newref:$object->ref));
416
-        	}
412
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ReceptionValidated",($object->newref?$object->newref:$object->ref));
413
+            if (empty($object->actionmsg))
414
+            {
415
+                $object->actionmsg=$langs->transnoentities("ReceptionValidated",($object->newref?$object->newref:$object->ref));
416
+            }
417 417
 
418
-        	// Parameters $object->sendtoid defined by caller
419
-        	//$object->sendtoid=0;
418
+            // Parameters $object->sendtoid defined by caller
419
+            //$object->sendtoid=0;
420 420
         }
421
-		elseif ($action == 'RECEPTION_SENTBYMAIL')
421
+        elseif ($action == 'RECEPTION_SENTBYMAIL')
422 422
         {
423 423
             $langs->load("agenda");
424 424
             $langs->load("other");
@@ -432,52 +432,52 @@  discard block
 block discarded – undo
432 432
 
433 433
             // Parameters $object->sendtoid defined by caller
434 434
             //$object->sendtoid=0;
435
-		}
436
-		elseif ($action == 'PROPOSAL_SUPPLIER_VALIDATE')
437
-		{
438
-			// Load translation files required by the page
435
+        }
436
+        elseif ($action == 'PROPOSAL_SUPPLIER_VALIDATE')
437
+        {
438
+            // Load translation files required by the page
439 439
             $langs->loadLangs(array("agenda","other","propal"));
440 440
 
441
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
442
-			$object->actionmsg=$langs->transnoentities("PropalValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
441
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
442
+            $object->actionmsg=$langs->transnoentities("PropalValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
443 443
 
444
-			$object->sendtoid=0;
445
-		}
446
-		elseif ($action == 'PROPOSAL_SUPPLIER_SENTBYMAIL')
447
-		{
448
-			// Load translation files required by the page
444
+            $object->sendtoid=0;
445
+        }
446
+        elseif ($action == 'PROPOSAL_SUPPLIER_SENTBYMAIL')
447
+        {
448
+            // Load translation files required by the page
449 449
             $langs->loadLangs(array("agenda","other","propal"));
450 450
 
451
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ProposalSentByEMail",$object->ref);
452
-			if (empty($object->actionmsg))
453
-			{
454
-				$object->actionmsg=$langs->transnoentities("ProposalSentByEMail",$object->ref);
455
-			}
456
-
457
-			// Parameters $object->sendtoid defined by caller
458
-			//$object->sendtoid=0;
459
-		}
460
-		elseif ($action == 'PROPOSAL_SUPPLIER_CLOSE_SIGNED')
461
-		{
462
-			// Load translation files required by the page
451
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ProposalSentByEMail",$object->ref);
452
+            if (empty($object->actionmsg))
453
+            {
454
+                $object->actionmsg=$langs->transnoentities("ProposalSentByEMail",$object->ref);
455
+            }
456
+
457
+            // Parameters $object->sendtoid defined by caller
458
+            //$object->sendtoid=0;
459
+        }
460
+        elseif ($action == 'PROPOSAL_SUPPLIER_CLOSE_SIGNED')
461
+        {
462
+            // Load translation files required by the page
463 463
             $langs->loadLangs(array("agenda","other","propal"));
464 464
 
465
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedSignedInDolibarr",$object->ref);
466
-			$object->actionmsg=$langs->transnoentities("PropalClosedSignedInDolibarr",$object->ref);
465
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedSignedInDolibarr",$object->ref);
466
+            $object->actionmsg=$langs->transnoentities("PropalClosedSignedInDolibarr",$object->ref);
467 467
 
468
-			$object->sendtoid=0;
469
-		}
470
-		elseif ($action == 'PROPOSAL_SUPPLIER_CLOSE_REFUSED')
471
-		{
472
-			// Load translation files required by the page
468
+            $object->sendtoid=0;
469
+        }
470
+        elseif ($action == 'PROPOSAL_SUPPLIER_CLOSE_REFUSED')
471
+        {
472
+            // Load translation files required by the page
473 473
             $langs->loadLangs(array("agenda","other","propal"));
474 474
 
475
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedRefusedInDolibarr",$object->ref);
476
-			$object->actionmsg=$langs->transnoentities("PropalClosedRefusedInDolibarr",$object->ref);
475
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedRefusedInDolibarr",$object->ref);
476
+            $object->actionmsg=$langs->transnoentities("PropalClosedRefusedInDolibarr",$object->ref);
477 477
 
478
-			$object->sendtoid=0;
479
-		}
480
-		elseif ($action == 'ORDER_SUPPLIER_CREATE')
478
+            $object->sendtoid=0;
479
+        }
480
+        elseif ($action == 'ORDER_SUPPLIER_CREATE')
481 481
         {
482 482
             // Load translation files required by the page
483 483
             $langs->loadLangs(array("agenda","other","orders"));
@@ -486,8 +486,8 @@  discard block
 block discarded – undo
486 486
             $object->actionmsg=$langs->transnoentities("OrderCreatedInDolibarr",($object->newref?$object->newref:$object->ref));
487 487
 
488 488
             $object->sendtoid=0;
489
-		}
490
-		elseif ($action == 'ORDER_SUPPLIER_VALIDATE')
489
+        }
490
+        elseif ($action == 'ORDER_SUPPLIER_VALIDATE')
491 491
         {
492 492
             // Load translation files required by the page
493 493
             $langs->loadLangs(array("agenda","other","orders"));
@@ -496,28 +496,28 @@  discard block
 block discarded – undo
496 496
             $object->actionmsg=$langs->transnoentities("OrderValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
497 497
 
498 498
             $object->sendtoid=0;
499
-		}
500
-		elseif ($action == 'ORDER_SUPPLIER_APPROVE')
501
-		{
499
+        }
500
+        elseif ($action == 'ORDER_SUPPLIER_APPROVE')
501
+        {
502 502
             // Load translation files required by the page
503 503
             $langs->loadLangs(array("agenda","other","orders"));
504 504
 
505
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderApprovedInDolibarr",$object->ref);
506
-			$object->actionmsg=$langs->transnoentities("OrderApprovedInDolibarr",$object->ref);
505
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderApprovedInDolibarr",$object->ref);
506
+            $object->actionmsg=$langs->transnoentities("OrderApprovedInDolibarr",$object->ref);
507 507
 
508
-			$object->sendtoid=0;
509
-		}
510
-		elseif ($action == 'ORDER_SUPPLIER_REFUSE')
511
-		{
508
+            $object->sendtoid=0;
509
+        }
510
+        elseif ($action == 'ORDER_SUPPLIER_REFUSE')
511
+        {
512 512
             // Load translation files required by the page
513 513
             $langs->loadLangs(array("agenda","other","orders"));
514 514
 
515
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderRefusedInDolibarr",$object->ref);
516
-			$object->actionmsg=$langs->transnoentities("OrderRefusedInDolibarr",$object->ref);
515
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderRefusedInDolibarr",$object->ref);
516
+            $object->actionmsg=$langs->transnoentities("OrderRefusedInDolibarr",$object->ref);
517 517
 
518
-			$object->sendtoid=0;
519
-		}
520
-		elseif ($action == 'ORDER_SUPPLIER_SUBMIT')
518
+            $object->sendtoid=0;
519
+        }
520
+        elseif ($action == 'ORDER_SUPPLIER_SUBMIT')
521 521
         {
522 522
             // Load translation files required by the page
523 523
             $langs->loadLangs(array("agenda","other","orders"));
@@ -526,8 +526,8 @@  discard block
 block discarded – undo
526 526
             $object->actionmsg=$langs->transnoentities("SupplierOrderSubmitedInDolibarr",($object->newref?$object->newref:$object->ref));
527 527
 
528 528
             $object->sendtoid=0;
529
-		}
530
-		elseif ($action == 'ORDER_SUPPLIER_RECEIVE')
529
+        }
530
+        elseif ($action == 'ORDER_SUPPLIER_RECEIVE')
531 531
         {
532 532
             // Load translation files required by the page
533 533
             $langs->loadLangs(array("agenda","other","orders"));
@@ -536,8 +536,8 @@  discard block
 block discarded – undo
536 536
             $object->actionmsg=$langs->transnoentities("SupplierOrderReceivedInDolibarr",($object->newref?$object->newref:$object->ref));
537 537
 
538 538
             $object->sendtoid=0;
539
-		}
540
-		elseif ($action == 'ORDER_SUPPLIER_SENTBYMAIL')
539
+        }
540
+        elseif ($action == 'ORDER_SUPPLIER_SENTBYMAIL')
541 541
         {
542 542
             // Load translation files required by the page
543 543
             $langs->loadLangs(array("agenda","other","bills","orders"));
@@ -551,7 +551,7 @@  discard block
 block discarded – undo
551 551
             // Parameters $object->sendtoid defined by caller
552 552
             //$object->sendtoid=0;
553 553
         }
554
-		elseif ($action == 'ORDER_SUPPLIER_CLASSIFY_BILLED')
554
+        elseif ($action == 'ORDER_SUPPLIER_CLASSIFY_BILLED')
555 555
         {
556 556
             // Load translation files required by the page
557 557
             $langs->loadLangs(array("agenda","other","bills","orders"));
@@ -564,7 +564,7 @@  discard block
 block discarded – undo
564 564
 
565 565
             $object->sendtoid=0;
566 566
         }
567
-		elseif ($action == 'BILL_SUPPLIER_VALIDATE')
567
+        elseif ($action == 'BILL_SUPPLIER_VALIDATE')
568 568
         {
569 569
             // Load translation files required by the page
570 570
             $langs->loadLangs(array("agenda","other","bills"));
@@ -573,8 +573,8 @@  discard block
 block discarded – undo
573 573
             $object->actionmsg=$langs->transnoentities("InvoiceValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
574 574
 
575 575
             $object->sendtoid=0;
576
-		}
577
-		elseif ($action == 'BILL_SUPPLIER_UNVALIDATE')
576
+        }
577
+        elseif ($action == 'BILL_SUPPLIER_UNVALIDATE')
578 578
         {
579 579
             // Load translation files required by the page
580 580
             $langs->loadLangs(array("agenda","other","bills"));
@@ -583,7 +583,7 @@  discard block
 block discarded – undo
583 583
             $object->actionmsg=$langs->transnoentities("InvoiceBackToDraftInDolibarr",$object->ref);
584 584
 
585 585
             $object->sendtoid=0;
586
-		}
586
+        }
587 587
         elseif ($action == 'BILL_SUPPLIER_SENTBYMAIL')
588 588
         {
589 589
             // Load translation files required by the page
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
             // Parameters $object->sendtoid defined by caller
599 599
             //$object->sendtoid=0;
600 600
         }
601
-		elseif ($action == 'BILL_SUPPLIER_PAYED')
601
+        elseif ($action == 'BILL_SUPPLIER_PAYED')
602 602
         {
603 603
             // Load translation files required by the page
604 604
             $langs->loadLangs(array("agenda","other","bills"));
@@ -606,9 +606,9 @@  discard block
 block discarded – undo
606 606
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoicePaidInDolibarr",$object->ref);
607 607
             $object->actionmsg=$langs->transnoentities("InvoicePaidInDolibarr",$object->ref);
608 608
 
609
-			$object->sendtoid=0;
610
-		}
611
-		elseif ($action == 'BILL_SUPPLIER_CANCELED')
609
+            $object->sendtoid=0;
610
+        }
611
+        elseif ($action == 'BILL_SUPPLIER_CANCELED')
612 612
         {
613 613
             // Load translation files required by the page
614 614
             $langs->loadLangs(array("agenda","other","bills"));
@@ -616,8 +616,8 @@  discard block
 block discarded – undo
616 616
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceCanceledInDolibarr",$object->ref);
617 617
             $object->actionmsg=$langs->transnoentities("InvoiceCanceledInDolibarr",$object->ref);
618 618
 
619
-			$object->sendtoid=0;
620
-		}
619
+            $object->sendtoid=0;
620
+        }
621 621
 
622 622
         // Members
623 623
         elseif ($action == 'MEMBER_VALIDATE')
@@ -630,9 +630,9 @@  discard block
 block discarded – undo
630 630
             $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
631 631
             $object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
632 632
 
633
-			$object->sendtoid=0;
633
+            $object->sendtoid=0;
634 634
         }
635
-		elseif ($action == 'MEMBER_MODIFY')
635
+        elseif ($action == 'MEMBER_MODIFY')
636 636
         {
637 637
             // Load translation files required by the page
638 638
             $langs->loadLangs(array("agenda","other","members"));
@@ -643,7 +643,7 @@  discard block
 block discarded – undo
643 643
             $object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
644 644
 
645 645
             $object->sendtoid=0;
646
-		}
646
+        }
647 647
         elseif ($action == 'MEMBER_SUBSCRIPTION_CREATE')
648 648
         {
649 649
             // Load translation files required by the page
@@ -656,38 +656,38 @@  discard block
 block discarded – undo
656 656
             $object->actionmsg.="\n".$langs->transnoentities("Amount").': '.$object->last_subscription_amount;
657 657
             $object->actionmsg.="\n".$langs->transnoentities("Period").': '.dol_print_date($object->last_subscription_date_start,'day').' - '.dol_print_date($object->last_subscription_date_end,'day');
658 658
 
659
-			$object->sendtoid=0;
660
-			if ($object->fk_soc > 0) $object->socid=$object->fk_soc;
659
+            $object->sendtoid=0;
660
+            if ($object->fk_soc > 0) $object->socid=$object->fk_soc;
661 661
         }
662 662
         elseif ($action == 'MEMBER_SUBSCRIPTION_MODIFY')
663 663
         {
664
-        	// Load translation files required by the page
664
+            // Load translation files required by the page
665 665
             $langs->loadLangs(array("agenda","other","members"));
666 666
 
667
-        	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberSubscriptionModifiedInDolibarr",$object->ref,$object->getFullName($langs));
668
-        	$object->actionmsg=$langs->transnoentities("MemberSubscriptionModifiedInDolibarr",$object->ref,$object->getFullName($langs));
669
-        	$object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
670
-        	$object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
671
-        	$object->actionmsg.="\n".$langs->transnoentities("Amount").': '.$object->last_subscription_amount;
672
-        	$object->actionmsg.="\n".$langs->transnoentities("Period").': '.dol_print_date($object->last_subscription_date_start,'day').' - '.dol_print_date($object->last_subscription_date_end,'day');
667
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberSubscriptionModifiedInDolibarr",$object->ref,$object->getFullName($langs));
668
+            $object->actionmsg=$langs->transnoentities("MemberSubscriptionModifiedInDolibarr",$object->ref,$object->getFullName($langs));
669
+            $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
670
+            $object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
671
+            $object->actionmsg.="\n".$langs->transnoentities("Amount").': '.$object->last_subscription_amount;
672
+            $object->actionmsg.="\n".$langs->transnoentities("Period").': '.dol_print_date($object->last_subscription_date_start,'day').' - '.dol_print_date($object->last_subscription_date_end,'day');
673 673
 
674
-        	$object->sendtoid=0;
675
-        	if ($object->fk_soc > 0) $object->socid=$object->fk_soc;
674
+            $object->sendtoid=0;
675
+            if ($object->fk_soc > 0) $object->socid=$object->fk_soc;
676 676
         }
677 677
         elseif ($action == 'MEMBER_SUBSCRIPTION_DELETE')
678 678
         {
679
-        	// Load translation files required by the page
679
+            // Load translation files required by the page
680 680
             $langs->loadLangs(array("agenda","other","members"));
681 681
 
682
-        	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberSubscriptionDeletedInDolibarr",$object->ref,$object->getFullName($langs));
683
-        	$object->actionmsg=$langs->transnoentities("MemberSubscriptionDeletedInDolibarr",$object->ref,$object->getFullName($langs));
684
-        	$object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
685
-        	$object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
686
-        	$object->actionmsg.="\n".$langs->transnoentities("Amount").': '.$object->last_subscription_amount;
687
-        	$object->actionmsg.="\n".$langs->transnoentities("Period").': '.dol_print_date($object->last_subscription_date_start,'day').' - '.dol_print_date($object->last_subscription_date_end,'day');
682
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberSubscriptionDeletedInDolibarr",$object->ref,$object->getFullName($langs));
683
+            $object->actionmsg=$langs->transnoentities("MemberSubscriptionDeletedInDolibarr",$object->ref,$object->getFullName($langs));
684
+            $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
685
+            $object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
686
+            $object->actionmsg.="\n".$langs->transnoentities("Amount").': '.$object->last_subscription_amount;
687
+            $object->actionmsg.="\n".$langs->transnoentities("Period").': '.dol_print_date($object->last_subscription_date_start,'day').' - '.dol_print_date($object->last_subscription_date_end,'day');
688 688
 
689
-        	$object->sendtoid=0;
690
-        	if ($object->fk_soc > 0) $object->socid=$object->fk_soc;
689
+            $object->sendtoid=0;
690
+            if ($object->fk_soc > 0) $object->socid=$object->fk_soc;
691 691
         }
692 692
         elseif ($action == 'MEMBER_RESILIATE')
693 693
         {
@@ -699,7 +699,7 @@  discard block
 block discarded – undo
699 699
             $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
700 700
             $object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
701 701
 
702
-			$object->sendtoid=0;
702
+            $object->sendtoid=0;
703 703
         }
704 704
         elseif ($action == 'MEMBER_DELETE')
705 705
         {
@@ -711,7 +711,7 @@  discard block
 block discarded – undo
711 711
             $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
712 712
             $object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
713 713
 
714
-			$object->sendtoid=0;
714
+            $object->sendtoid=0;
715 715
         }
716 716
 
717 717
         // Projects
@@ -720,11 +720,11 @@  discard block
 block discarded – undo
720 720
             // Load translation files required by the page
721 721
             $langs->loadLangs(array("agenda","other","projects"));
722 722
 
723
-        	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ProjectCreatedInDolibarr",$object->ref);
724
-        	$object->actionmsg=$langs->transnoentities("ProjectCreatedInDolibarr",$object->ref);
725
-        	$object->actionmsg.="\n".$langs->transnoentities("Project").': '.$object->ref;
723
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ProjectCreatedInDolibarr",$object->ref);
724
+            $object->actionmsg=$langs->transnoentities("ProjectCreatedInDolibarr",$object->ref);
725
+            $object->actionmsg.="\n".$langs->transnoentities("Project").': '.$object->ref;
726 726
 
727
-        	$object->sendtoid=0;
727
+            $object->sendtoid=0;
728 728
         }
729 729
         elseif($action == 'PROJECT_VALIDATE')
730 730
         {
@@ -749,74 +749,74 @@  discard block
 block discarded – undo
749 749
             $object->sendtoid=0;
750 750
         }
751 751
 
752
-		// Project tasks
753
-		elseif($action == 'TASK_CREATE')
754
-		{
752
+        // Project tasks
753
+        elseif($action == 'TASK_CREATE')
754
+        {
755 755
             // Load translation files required by the page
756 756
             $langs->loadLangs(array("agenda","other","projects"));
757 757
 
758
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("TaskCreatedInDolibarr",$object->ref);
759
-			$object->actionmsg=$langs->transnoentities("TaskCreatedInDolibarr",$object->ref);
760
-			$object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
758
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("TaskCreatedInDolibarr",$object->ref);
759
+            $object->actionmsg=$langs->transnoentities("TaskCreatedInDolibarr",$object->ref);
760
+            $object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
761 761
 
762
-			$object->sendtoid=0;
763
-		}
762
+            $object->sendtoid=0;
763
+        }
764 764
 
765
-		elseif($action == 'TASK_MODIFY')
766
-		{
765
+        elseif($action == 'TASK_MODIFY')
766
+        {
767 767
             // Load translation files required by the page
768 768
             $langs->loadLangs(array("agenda","other","projects"));
769 769
 
770
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("TaskModifiedInDolibarr",$object->ref);
771
-			$object->actionmsg=$langs->transnoentities("TaskModifieddInDolibarr",$object->ref);
772
-			$object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
770
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("TaskModifiedInDolibarr",$object->ref);
771
+            $object->actionmsg=$langs->transnoentities("TaskModifieddInDolibarr",$object->ref);
772
+            $object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
773 773
 
774
-			$object->sendtoid=0;
775
-		}
774
+            $object->sendtoid=0;
775
+        }
776 776
 
777
-		elseif($action == 'TASK_DELETE')
778
-		{
777
+        elseif($action == 'TASK_DELETE')
778
+        {
779 779
             // Load translation files required by the page
780 780
             $langs->loadLangs(array("agenda","other","projects"));
781 781
 
782
-			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("TaskDeletedInDolibarr",$object->ref);
783
-			$object->actionmsg=$langs->transnoentities("TaskDeletedInDolibarr",$object->ref);
784
-			$object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
785
-
786
-			$object->sendtoid=0;
787
-		}
788
-		// TODO Merge all previous cases into this generic one
789
-		else	// $action = TICKET_CREATE, TICKET_MODIFY, TICKET_DELETE, ...
790
-		{
791
-		    // Note: We are here only if $conf->global->MAIN_AGENDA_ACTIONAUTO_action is on (tested at begining of this function)
792
-		    // Load translation files required by the page
782
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("TaskDeletedInDolibarr",$object->ref);
783
+            $object->actionmsg=$langs->transnoentities("TaskDeletedInDolibarr",$object->ref);
784
+            $object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
785
+
786
+            $object->sendtoid=0;
787
+        }
788
+        // TODO Merge all previous cases into this generic one
789
+        else	// $action = TICKET_CREATE, TICKET_MODIFY, TICKET_DELETE, ...
790
+        {
791
+            // Note: We are here only if $conf->global->MAIN_AGENDA_ACTIONAUTO_action is on (tested at begining of this function)
792
+            // Load translation files required by the page
793 793
             $langs->loadLangs(array("agenda","other"));
794 794
 
795
-		    if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities($action."InDolibarr",$object->ref);
796
-		    if (empty($object->actionmsg))  $object->actionmsg=$langs->transnoentities($action."InDolibarr",$object->ref);
795
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities($action."InDolibarr",$object->ref);
796
+            if (empty($object->actionmsg))  $object->actionmsg=$langs->transnoentities($action."InDolibarr",$object->ref);
797 797
 
798
-		    $object->sendtoid=0;
799
-		}
798
+            $object->sendtoid=0;
799
+        }
800 800
 
801
-		$object->actionmsg = $langs->transnoentities("Author").': '.$user->login."\n".$object->actionmsg;
801
+        $object->actionmsg = $langs->transnoentities("Author").': '.$user->login."\n".$object->actionmsg;
802 802
 
803
-		dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
803
+        dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
804 804
 
805 805
         // Add entry in event table
806
-		$now=dol_now();
806
+        $now=dol_now();
807 807
 
808
-		if (isset($_SESSION['listofnames-'.$object->trackid]))
809
-		{
810
-			$attachs=$_SESSION['listofnames-'.$object->trackid];
811
-			if ($attachs && strpos($action,'SENTBYMAIL'))
812
-			{
808
+        if (isset($_SESSION['listofnames-'.$object->trackid]))
809
+        {
810
+            $attachs=$_SESSION['listofnames-'.$object->trackid];
811
+            if ($attachs && strpos($action,'SENTBYMAIL'))
812
+            {
813 813
                 $object->actionmsg=dol_concatdesc($object->actionmsg, "\n".$langs->transnoentities("AttachedFiles").': '.$attachs);
814
-			}
815
-		}
814
+            }
815
+        }
816 816
 
817 817
         require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
818 818
         require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
819
-		$contactforaction=new Contact($this->db);
819
+        $contactforaction=new Contact($this->db);
820 820
         $societeforaction=new Societe($this->db);
821 821
         // Set contactforaction if there is only 1 contact.
822 822
         if (is_array($object->sendtoid))
@@ -838,87 +838,87 @@  discard block
 block discarded – undo
838 838
         $elementtype = $object->element;
839 839
         if ($object->element == 'subscription')
840 840
         {
841
-        	$elementid = $object->fk_adherent;
842
-        	$elementtype = 'member';
841
+            $elementid = $object->fk_adherent;
842
+            $elementtype = 'member';
843 843
         }
844 844
         //var_dump($societeforaction);var_dump($contactforaction);exit;
845 845
 
846
-		// Insertion action
847
-		require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
848
-		$actioncomm = new ActionComm($this->db);
849
-		$actioncomm->type_code   = $object->actiontypecode;		// Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
850
-		$actioncomm->code        = 'AC_'.$action;
851
-		$actioncomm->label       = $object->actionmsg2;
852
-		$actioncomm->note        = $object->actionmsg;          // TODO Replace with ($actioncomm->email_msgid ? $object->email_content : $object->actionmsg)
853
-		$actioncomm->fk_project  = $projectid;
854
-		$actioncomm->datep       = $now;
855
-		$actioncomm->datef       = $now;
856
-		$actioncomm->durationp   = 0;
857
-		$actioncomm->punctual    = 1;
858
-		$actioncomm->percentage  = -1;   // Not applicable
859
-		$actioncomm->societe     = $societeforaction;
860
-		$actioncomm->contact     = $contactforaction;
861
-		$actioncomm->socid       = $societeforaction->id;
862
-		$actioncomm->contactid   = $contactforaction->id;
863
-		$actioncomm->authorid    = $user->id;   // User saving action
864
-		$actioncomm->userownerid = $user->id;	// Owner of action
846
+        // Insertion action
847
+        require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
848
+        $actioncomm = new ActionComm($this->db);
849
+        $actioncomm->type_code   = $object->actiontypecode;		// Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
850
+        $actioncomm->code        = 'AC_'.$action;
851
+        $actioncomm->label       = $object->actionmsg2;
852
+        $actioncomm->note        = $object->actionmsg;          // TODO Replace with ($actioncomm->email_msgid ? $object->email_content : $object->actionmsg)
853
+        $actioncomm->fk_project  = $projectid;
854
+        $actioncomm->datep       = $now;
855
+        $actioncomm->datef       = $now;
856
+        $actioncomm->durationp   = 0;
857
+        $actioncomm->punctual    = 1;
858
+        $actioncomm->percentage  = -1;   // Not applicable
859
+        $actioncomm->societe     = $societeforaction;
860
+        $actioncomm->contact     = $contactforaction;
861
+        $actioncomm->socid       = $societeforaction->id;
862
+        $actioncomm->contactid   = $contactforaction->id;
863
+        $actioncomm->authorid    = $user->id;   // User saving action
864
+        $actioncomm->userownerid = $user->id;	// Owner of action
865 865
         // Fields defined when action is an email (content should be into object->actionmsg to be added into note, subject into object->actionms2 to be added into label)
866
-		$actioncomm->email_msgid   = $object->email_msgid;
867
-		$actioncomm->email_from    = $object->email_from;
868
-		$actioncomm->email_sender  = $object->email_sender;
869
-		$actioncomm->email_to      = $object->email_to;
870
-		$actioncomm->email_tocc    = $object->email_tocc;
871
-		$actioncomm->email_tobcc   = $object->email_tobcc;
872
-		$actioncomm->email_subject = $object->email_subject;
873
-		$actioncomm->errors_to     = $object->errors_to;
874
-
875
-		// Object linked (if link is for thirdparty, contact, project it is a recording error. We should not have links in link table
876
-		// for such objects because there is already a dedicated field into table llx_actioncomm.
877
-		if (! in_array($elementtype, array('societe','contact','project')))
878
-		{
879
-			$actioncomm->fk_element  = $elementid;
880
-			$actioncomm->elementtype = $elementtype;
881
-		}
882
-
883
-		if (property_exists($object,'attachedfiles') && is_array($object->attachedfiles) && count($object->attachedfiles)>0) {
884
-			$actioncomm->attachedfiles=$object->attachedfiles;
885
-		}
886
-		if (property_exists($object,'sendtouserid') && is_array($object->sendtouserid) && count($object->sendtouserid)>0) {
887
-			$actioncomm->userassigned=$object->sendtouserid;
888
-		}
889
-
890
-		$ret=$actioncomm->create($user);       // User creating action
891
-
892
-		if ($ret > 0 && $conf->global->MAIN_COPY_FILE_IN_EVENT_AUTO)
893
-		{
894
-			if (is_array($object->attachedfiles) && array_key_exists('paths',$object->attachedfiles) && count($object->attachedfiles['paths'])>0) {
895
-				foreach($object->attachedfiles['paths'] as $key=>$filespath) {
896
-					$srcfile = $filespath;
897
-					$destdir = $conf->agenda->dir_output . '/' . $ret;
898
-					$destfile = $destdir . '/' . $object->attachedfiles['names'][$key];
899
-					if (dol_mkdir($destdir) >= 0) {
900
-						require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
901
-						dol_copy($srcfile, $destfile);
902
-					}
903
-				}
904
-			}
905
-		}
906
-
907
-		unset($object->actionmsg); unset($object->actionmsg2); unset($object->actiontypecode);	// When several action are called on same object, we must be sure to not reuse value of first action.
908
-
909
-		if ($ret > 0)
910
-		{
911
-			$_SESSION['LAST_ACTION_CREATED'] = $ret;
912
-			return 1;
913
-		}
914
-		else
915
-		{
866
+        $actioncomm->email_msgid   = $object->email_msgid;
867
+        $actioncomm->email_from    = $object->email_from;
868
+        $actioncomm->email_sender  = $object->email_sender;
869
+        $actioncomm->email_to      = $object->email_to;
870
+        $actioncomm->email_tocc    = $object->email_tocc;
871
+        $actioncomm->email_tobcc   = $object->email_tobcc;
872
+        $actioncomm->email_subject = $object->email_subject;
873
+        $actioncomm->errors_to     = $object->errors_to;
874
+
875
+        // Object linked (if link is for thirdparty, contact, project it is a recording error. We should not have links in link table
876
+        // for such objects because there is already a dedicated field into table llx_actioncomm.
877
+        if (! in_array($elementtype, array('societe','contact','project')))
878
+        {
879
+            $actioncomm->fk_element  = $elementid;
880
+            $actioncomm->elementtype = $elementtype;
881
+        }
882
+
883
+        if (property_exists($object,'attachedfiles') && is_array($object->attachedfiles) && count($object->attachedfiles)>0) {
884
+            $actioncomm->attachedfiles=$object->attachedfiles;
885
+        }
886
+        if (property_exists($object,'sendtouserid') && is_array($object->sendtouserid) && count($object->sendtouserid)>0) {
887
+            $actioncomm->userassigned=$object->sendtouserid;
888
+        }
889
+
890
+        $ret=$actioncomm->create($user);       // User creating action
891
+
892
+        if ($ret > 0 && $conf->global->MAIN_COPY_FILE_IN_EVENT_AUTO)
893
+        {
894
+            if (is_array($object->attachedfiles) && array_key_exists('paths',$object->attachedfiles) && count($object->attachedfiles['paths'])>0) {
895
+                foreach($object->attachedfiles['paths'] as $key=>$filespath) {
896
+                    $srcfile = $filespath;
897
+                    $destdir = $conf->agenda->dir_output . '/' . $ret;
898
+                    $destfile = $destdir . '/' . $object->attachedfiles['names'][$key];
899
+                    if (dol_mkdir($destdir) >= 0) {
900
+                        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
901
+                        dol_copy($srcfile, $destfile);
902
+                    }
903
+                }
904
+            }
905
+        }
906
+
907
+        unset($object->actionmsg); unset($object->actionmsg2); unset($object->actiontypecode);	// When several action are called on same object, we must be sure to not reuse value of first action.
908
+
909
+        if ($ret > 0)
910
+        {
911
+            $_SESSION['LAST_ACTION_CREATED'] = $ret;
912
+            return 1;
913
+        }
914
+        else
915
+        {
916 916
             $error ="Failed to insert event : ".$actioncomm->error." ".join(',',$actioncomm->errors);
917 917
             $this->error=$error;
918 918
             $this->errors=$actioncomm->errors;
919 919
 
920 920
             dol_syslog("interface_modAgenda_ActionsAuto.class.php: ".$this->error, LOG_ERR);
921 921
             return -1;
922
-		}
922
+        }
923 923
     }
924 924
 }
Please login to merge, or discard this patch.
Helpers/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php 1 patch
Indentation   +111 added lines, -111 removed lines patch added patch discarded remove patch
@@ -30,121 +30,121 @@
 block discarded – undo
30 30
  */
31 31
 class InterfaceActionsBlockedLog extends DolibarrTriggers
32 32
 {
33
-	public $family = 'system';
34
-	public $description = "Triggers of this module add action for BlockedLog module.";
35
-
36
-	/**
37
-	 * Version of the trigger
38
-	 * @var string
39
-	 */
40
-	public $version = self::VERSION_DOLIBARR;
41
-
42
-	/**
43
-	 * @var string Image of the trigger
44
-	 */
45
-	public $picto = 'technic';
46
-
47
-	/**
48
-	 * Function called on Dolibarrr payment or invoice event.
49
-	 *
50
-	 * @param string		$action		Event action code
51
-	 * @param Object		$object     Object
52
-	 * @param User		    $user       Object user
53
-	 * @param Translate 	$langs      Object langs
54
-	 * @param conf		    $conf       Object conf
55
-	 * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
56
-	 */
57
-	public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
58
-	{
59
-		if (empty($conf->blockedlog->enabled)) return 0;     // Module not active, we do nothing
60
-
61
-		// Test if event/record is qualified
62
-		$listofqualifiedelement = array('facture', 'don', 'payment', 'payment_donation', 'subscription', 'payment_various', 'cashcontrol');
63
-		if (! in_array($object->element, $listofqualifiedelement)) return 1;
64
-
65
-		dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
66
-
67
-		require_once DOL_DOCUMENT_ROOT.'/blockedlog/class/blockedlog.class.php';
68
-		$b=new BlockedLog($this->db);
69
-
70
-		// Tracked events
71
-		if (! in_array($action, array_keys($b->trackedevents)))
72
-		{
73
-			return 0;
74
-		}
75
-
76
-		// Event/record is qualified
77
-		$qualified = 0;
78
-		$amounts = 0;
79
-		if ($action==='BILL_VALIDATE' || $action==='BILL_DELETE' || $action === 'BILL_SENTBYMAIL'
80
-			|| $action==='BILL_SUPPLIER_VALIDATE' || $action==='BILL_SUPPLIER_DELETE' || $action === 'BILL_SUPPLIER_SENTBYMAIL'
81
-			|| $action==='MEMBER_SUBSCRIPTION_CREATE' || $action==='MEMBER_SUBSCRIPTION_MODIFY' || $action==='MEMBER_SUBSCRIPTION_DELETE'
82
-			|| $action==='DON_VALIDATE' || $action==='DON_MODIFY' || $action==='DON_DELETE'
83
-			|| $action==='CASHCONTROL_VALIDATE'
84
-			|| (in_array($object->element, array('facture','suplier_invoice')) && $action === 'DOC_DOWNLOAD') || (in_array($object->element, array('facture','suplier_invoice')) && $action === 'DOC_PREVIEW')
85
-		)
86
-		{
87
-			$qualified++;
88
-
89
-			if (in_array($action, array(
90
-				'MEMBER_SUBSCRIPTION_CREATE','MEMBER_SUBSCRIPTION_MODIFY','MEMBER_SUBSCRIPTION_DELETE',
91
-				'DON_VALIDATE','DON_MODIFY','DON_DELETE'))) $amounts = (double) $object->amount;
92
-			elseif ($action == 'CASHCONTROL_VALIDATE')
93
-			{
94
-				$amounts = (double) $object->cash + (double) $object->cheque + (double) $object->card;
95
-			}
96
-			else $amounts = (double) $object->total_ttc;
97
-		}
98
-		/*if ($action === 'BILL_PAYED' || $action==='BILL_UNPAYED'
33
+    public $family = 'system';
34
+    public $description = "Triggers of this module add action for BlockedLog module.";
35
+
36
+    /**
37
+     * Version of the trigger
38
+     * @var string
39
+     */
40
+    public $version = self::VERSION_DOLIBARR;
41
+
42
+    /**
43
+     * @var string Image of the trigger
44
+     */
45
+    public $picto = 'technic';
46
+
47
+    /**
48
+     * Function called on Dolibarrr payment or invoice event.
49
+     *
50
+     * @param string		$action		Event action code
51
+     * @param Object		$object     Object
52
+     * @param User		    $user       Object user
53
+     * @param Translate 	$langs      Object langs
54
+     * @param conf		    $conf       Object conf
55
+     * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
56
+     */
57
+    public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
58
+    {
59
+        if (empty($conf->blockedlog->enabled)) return 0;     // Module not active, we do nothing
60
+
61
+        // Test if event/record is qualified
62
+        $listofqualifiedelement = array('facture', 'don', 'payment', 'payment_donation', 'subscription', 'payment_various', 'cashcontrol');
63
+        if (! in_array($object->element, $listofqualifiedelement)) return 1;
64
+
65
+        dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
66
+
67
+        require_once DOL_DOCUMENT_ROOT.'/blockedlog/class/blockedlog.class.php';
68
+        $b=new BlockedLog($this->db);
69
+
70
+        // Tracked events
71
+        if (! in_array($action, array_keys($b->trackedevents)))
72
+        {
73
+            return 0;
74
+        }
75
+
76
+        // Event/record is qualified
77
+        $qualified = 0;
78
+        $amounts = 0;
79
+        if ($action==='BILL_VALIDATE' || $action==='BILL_DELETE' || $action === 'BILL_SENTBYMAIL'
80
+            || $action==='BILL_SUPPLIER_VALIDATE' || $action==='BILL_SUPPLIER_DELETE' || $action === 'BILL_SUPPLIER_SENTBYMAIL'
81
+            || $action==='MEMBER_SUBSCRIPTION_CREATE' || $action==='MEMBER_SUBSCRIPTION_MODIFY' || $action==='MEMBER_SUBSCRIPTION_DELETE'
82
+            || $action==='DON_VALIDATE' || $action==='DON_MODIFY' || $action==='DON_DELETE'
83
+            || $action==='CASHCONTROL_VALIDATE'
84
+            || (in_array($object->element, array('facture','suplier_invoice')) && $action === 'DOC_DOWNLOAD') || (in_array($object->element, array('facture','suplier_invoice')) && $action === 'DOC_PREVIEW')
85
+        )
86
+        {
87
+            $qualified++;
88
+
89
+            if (in_array($action, array(
90
+                'MEMBER_SUBSCRIPTION_CREATE','MEMBER_SUBSCRIPTION_MODIFY','MEMBER_SUBSCRIPTION_DELETE',
91
+                'DON_VALIDATE','DON_MODIFY','DON_DELETE'))) $amounts = (double) $object->amount;
92
+            elseif ($action == 'CASHCONTROL_VALIDATE')
93
+            {
94
+                $amounts = (double) $object->cash + (double) $object->cheque + (double) $object->card;
95
+            }
96
+            else $amounts = (double) $object->total_ttc;
97
+        }
98
+        /*if ($action === 'BILL_PAYED' || $action==='BILL_UNPAYED'
99 99
 		 || $action === 'BILL_SUPPLIER_PAYED' || $action === 'BILL_SUPPLIER_UNPAYED')
100 100
 		{
101 101
 			$qualified++;
102 102
 			$amounts=  (double) $object->total_ttc;
103 103
 		}*/
104
-		if ($action === 'PAYMENT_CUSTOMER_CREATE' || $action === 'PAYMENT_SUPPLIER_CREATE' || $action === 'DONATION_PAYMENT_CREATE'
105
-			|| $action === 'PAYMENT_CUSTOMER_DELETE' || $action === 'PAYMENT_SUPPLIER_DELETE' || $action === 'DONATION_PAYMENT_DELETE')
106
-		{
107
-			$qualified++;
108
-			$amounts = 0;
109
-			if(!empty($object->amounts)) {
110
-				foreach($object->amounts as $amount) {
111
-					$amounts += price2num($amount);
112
-				}
113
-			}
114
-		}
115
-		elseif (strpos($action,'PAYMENT')!==false && ! in_array($action, array('PAYMENT_ADD_TO_BANK')))
116
-		{
117
-			$qualified++;
118
-			$amounts = (double) $object->amount;
119
-		}
120
-
121
-		// Another protection.
122
-		// May be used when event is DOC_DOWNLOAD or DOC_PREVIEW and element is not an invoice
123
-		if (! $qualified)
124
-		{
125
-			return 0; // not implemented action log
126
-		}
127
-
128
-		$result = $b->setObjectData($object, $action, $amounts, $user);		// Set field date_object, ref_object, fk_object, element, object_data
129
-
130
-		if ($result < 0)
131
-		{
132
-			$this->error = $b->error;
133
-			$this->errors = $b->errors;
134
-			return -1;
135
-		}
136
-
137
-		$res = $b->create($user);
138
-
139
-		if ($res < 0)
140
-		{
141
-			$this->error = $b->error;
142
-			$this->errors = $b->errors;
143
-			return -1;
144
-		}
145
-		else
146
-		{
147
-			return 1;
148
-		}
104
+        if ($action === 'PAYMENT_CUSTOMER_CREATE' || $action === 'PAYMENT_SUPPLIER_CREATE' || $action === 'DONATION_PAYMENT_CREATE'
105
+            || $action === 'PAYMENT_CUSTOMER_DELETE' || $action === 'PAYMENT_SUPPLIER_DELETE' || $action === 'DONATION_PAYMENT_DELETE')
106
+        {
107
+            $qualified++;
108
+            $amounts = 0;
109
+            if(!empty($object->amounts)) {
110
+                foreach($object->amounts as $amount) {
111
+                    $amounts += price2num($amount);
112
+                }
113
+            }
114
+        }
115
+        elseif (strpos($action,'PAYMENT')!==false && ! in_array($action, array('PAYMENT_ADD_TO_BANK')))
116
+        {
117
+            $qualified++;
118
+            $amounts = (double) $object->amount;
119
+        }
120
+
121
+        // Another protection.
122
+        // May be used when event is DOC_DOWNLOAD or DOC_PREVIEW and element is not an invoice
123
+        if (! $qualified)
124
+        {
125
+            return 0; // not implemented action log
126
+        }
127
+
128
+        $result = $b->setObjectData($object, $action, $amounts, $user);		// Set field date_object, ref_object, fk_object, element, object_data
129
+
130
+        if ($result < 0)
131
+        {
132
+            $this->error = $b->error;
133
+            $this->errors = $b->errors;
134
+            return -1;
135
+        }
136
+
137
+        $res = $b->create($user);
138
+
139
+        if ($res < 0)
140
+        {
141
+            $this->error = $b->error;
142
+            $this->errors = $b->errors;
143
+            return -1;
144
+        }
145
+        else
146
+        {
147
+            return 1;
148
+        }
149 149
     }
150 150
 }
Please login to merge, or discard this patch.
Helpers/triggers/interface_50_modNotification_Notification.class.php 1 patch
Indentation   +115 added lines, -115 removed lines patch added patch discarded remove patch
@@ -30,119 +30,119 @@
 block discarded – undo
30 30
  */
31 31
 class InterfaceNotification extends DolibarrTriggers
32 32
 {
33
-	public $family = 'notification';
34
-	public $description = "Triggers of this module send email notifications according to Notification module setup.";
35
-
36
-	/**
37
-	 * Version of the trigger
38
-	 * @var string
39
-	 */
40
-	public $version = self::VERSION_DOLIBARR;
41
-
42
-	/**
43
-	 * @var string Image of the trigger
44
-	 */
45
-	public $picto = 'email';
46
-
47
-	// @TODO Defined also into notify.class.php)
48
-	public $listofmanagedevents=array(
49
-		'BILL_VALIDATE',
50
-		'BILL_PAYED',
51
-		'ORDER_VALIDATE',
52
-		'PROPAL_VALIDATE',
53
-		'PROPAL_CLOSE_SIGNED',
54
-		'FICHINTER_VALIDATE',
55
-		'FICHINTER_ADD_CONTACT',
56
-		'ORDER_SUPPLIER_VALIDATE',
57
-		'ORDER_SUPPLIER_APPROVE',
58
-		'ORDER_SUPPLIER_REFUSE',
59
-		'SHIPPING_VALIDATE',
60
-		'EXPENSE_REPORT_VALIDATE',
61
-		'EXPENSE_REPORT_APPROVE',
62
-		'HOLIDAY_VALIDATE',
63
-		'HOLIDAY_APPROVE'
64
-	);
65
-
66
-	/**
67
-	 * Function called when a Dolibarrr business event is done.
68
-	 * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
69
-	 *
70
-	 * @param string		$action		Event action code
71
-	 * @param Object		$object     Object
72
-	 * @param User		    $user       Object user
73
-	 * @param Translate 	$langs      Object langs
74
-	 * @param conf		    $conf       Object conf
75
-	 * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
76
-	 */
77
-	public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
78
-	{
79
-		if (empty($conf->notification->enabled)) return 0;     // Module not active, we do nothing
80
-
81
-		require_once DOL_DOCUMENT_ROOT .'/core/class/notify.class.php';
82
-		$notify = new Notify($this->db);
83
-
84
-		if (! in_array($action, $notify->arrayofnotifsupported)) return 0;
85
-
86
-		dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
87
-
88
-		$notify->send($action, $object);
89
-
90
-		return 1;
91
-	}
92
-
93
-
94
-	/**
95
-	 * Return list of events managed by notification module
96
-	 *
97
-	 * @return      array       Array of events managed by notification module
98
-	 */
99
-	function getListOfManagedEvents()
100
-	{
101
-		global $conf;
102
-
103
-		$ret=array();
104
-
105
-		$sql = "SELECT rowid, code, label, description, elementtype";
106
-		$sql.= " FROM ".MAIN_DB_PREFIX."c_action_trigger";
107
-		$sql.= $this->db->order("rang, elementtype, code");
108
-		dol_syslog("getListOfManagedEvents Get list of notifications", LOG_DEBUG);
109
-		$resql=$this->db->query($sql);
110
-		if ($resql)
111
-		{
112
-			$num=$this->db->num_rows($resql);
113
-			$i=0;
114
-			while ($i < $num)
115
-			{
116
-				$obj=$this->db->fetch_object($resql);
117
-
118
-				$qualified=0;
119
-				// Check is this event is supported by notification module
120
-				if (in_array($obj->code, $this->listofmanagedevents)) $qualified=1;
121
-				// Check if module for this event is active
122
-				if ($qualified)
123
-				{
124
-					//print 'xx'.$obj->code;
125
-					$element=$obj->elementtype;
126
-
127
-					// Exclude events if related module is disabled
128
-					if ($element == 'order_supplier' && empty($conf->fournisseur->enabled)) $qualified=0;
129
-					elseif ($element == 'invoice_supplier' && empty($conf->fournisseur->enabled)) $qualified=0;
130
-					elseif ($element == 'withdraw' && empty($conf->prelevement->enabled)) $qualified=0;
131
-					elseif ($element == 'shipping' && empty($conf->expedition->enabled)) $qualified=0;
132
-					elseif ($element == 'member' && empty($conf->adherent->enabled)) $qualified=0;
133
-					elseif (! in_array($element,array('order_supplier','invoice_supplier','withdraw','shipping','member','expensereport')) && empty($conf->$element->enabled)) $qualified=0;
134
-				}
135
-
136
-				if ($qualified)
137
-				{
138
-					$ret[]=array('rowid'=>$obj->rowid,'code'=>$obj->code,'label'=>$obj->label,'description'=>$obj->description,'elementtype'=>$obj->elementtype);
139
-				}
140
-
141
-				$i++;
142
-			}
143
-		}
144
-		else dol_print_error($this->db);
145
-
146
-		return $ret;
147
-	}
33
+    public $family = 'notification';
34
+    public $description = "Triggers of this module send email notifications according to Notification module setup.";
35
+
36
+    /**
37
+     * Version of the trigger
38
+     * @var string
39
+     */
40
+    public $version = self::VERSION_DOLIBARR;
41
+
42
+    /**
43
+     * @var string Image of the trigger
44
+     */
45
+    public $picto = 'email';
46
+
47
+    // @TODO Defined also into notify.class.php)
48
+    public $listofmanagedevents=array(
49
+        'BILL_VALIDATE',
50
+        'BILL_PAYED',
51
+        'ORDER_VALIDATE',
52
+        'PROPAL_VALIDATE',
53
+        'PROPAL_CLOSE_SIGNED',
54
+        'FICHINTER_VALIDATE',
55
+        'FICHINTER_ADD_CONTACT',
56
+        'ORDER_SUPPLIER_VALIDATE',
57
+        'ORDER_SUPPLIER_APPROVE',
58
+        'ORDER_SUPPLIER_REFUSE',
59
+        'SHIPPING_VALIDATE',
60
+        'EXPENSE_REPORT_VALIDATE',
61
+        'EXPENSE_REPORT_APPROVE',
62
+        'HOLIDAY_VALIDATE',
63
+        'HOLIDAY_APPROVE'
64
+    );
65
+
66
+    /**
67
+     * Function called when a Dolibarrr business event is done.
68
+     * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
69
+     *
70
+     * @param string		$action		Event action code
71
+     * @param Object		$object     Object
72
+     * @param User		    $user       Object user
73
+     * @param Translate 	$langs      Object langs
74
+     * @param conf		    $conf       Object conf
75
+     * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
76
+     */
77
+    public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
78
+    {
79
+        if (empty($conf->notification->enabled)) return 0;     // Module not active, we do nothing
80
+
81
+        require_once DOL_DOCUMENT_ROOT .'/core/class/notify.class.php';
82
+        $notify = new Notify($this->db);
83
+
84
+        if (! in_array($action, $notify->arrayofnotifsupported)) return 0;
85
+
86
+        dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
87
+
88
+        $notify->send($action, $object);
89
+
90
+        return 1;
91
+    }
92
+
93
+
94
+    /**
95
+     * Return list of events managed by notification module
96
+     *
97
+     * @return      array       Array of events managed by notification module
98
+     */
99
+    function getListOfManagedEvents()
100
+    {
101
+        global $conf;
102
+
103
+        $ret=array();
104
+
105
+        $sql = "SELECT rowid, code, label, description, elementtype";
106
+        $sql.= " FROM ".MAIN_DB_PREFIX."c_action_trigger";
107
+        $sql.= $this->db->order("rang, elementtype, code");
108
+        dol_syslog("getListOfManagedEvents Get list of notifications", LOG_DEBUG);
109
+        $resql=$this->db->query($sql);
110
+        if ($resql)
111
+        {
112
+            $num=$this->db->num_rows($resql);
113
+            $i=0;
114
+            while ($i < $num)
115
+            {
116
+                $obj=$this->db->fetch_object($resql);
117
+
118
+                $qualified=0;
119
+                // Check is this event is supported by notification module
120
+                if (in_array($obj->code, $this->listofmanagedevents)) $qualified=1;
121
+                // Check if module for this event is active
122
+                if ($qualified)
123
+                {
124
+                    //print 'xx'.$obj->code;
125
+                    $element=$obj->elementtype;
126
+
127
+                    // Exclude events if related module is disabled
128
+                    if ($element == 'order_supplier' && empty($conf->fournisseur->enabled)) $qualified=0;
129
+                    elseif ($element == 'invoice_supplier' && empty($conf->fournisseur->enabled)) $qualified=0;
130
+                    elseif ($element == 'withdraw' && empty($conf->prelevement->enabled)) $qualified=0;
131
+                    elseif ($element == 'shipping' && empty($conf->expedition->enabled)) $qualified=0;
132
+                    elseif ($element == 'member' && empty($conf->adherent->enabled)) $qualified=0;
133
+                    elseif (! in_array($element,array('order_supplier','invoice_supplier','withdraw','shipping','member','expensereport')) && empty($conf->$element->enabled)) $qualified=0;
134
+                }
135
+
136
+                if ($qualified)
137
+                {
138
+                    $ret[]=array('rowid'=>$obj->rowid,'code'=>$obj->code,'label'=>$obj->label,'description'=>$obj->description,'elementtype'=>$obj->elementtype);
139
+                }
140
+
141
+                $i++;
142
+            }
143
+        }
144
+        else dol_print_error($this->db);
145
+
146
+        return $ret;
147
+    }
148 148
 }
Please login to merge, or discard this patch.
Helpers/triggers/interface_50_modTicket_TicketEmail.class.php 1 patch
Indentation   +219 added lines, -219 removed lines patch added patch discarded remove patch
@@ -107,233 +107,233 @@
 block discarded – undo
107 107
      */
108 108
     public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
109 109
     {
110
-		$ok = 0;
111
-
112
-    	switch ($action) {
113
-    		case 'TICKET_ASSIGNED':
114
-	            dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
115
-
116
-	            if ($object->fk_user_assign > 0 && $object->fk_user_assign != $user->id)
117
-	            {
118
-	                $userstat = new User($this->db);
119
-	                $res = $userstat->fetch($object->fk_user_assign);
120
-	                if ($res > 0)
121
-	                {
122
-	                	if (empty($conf->global->TICKET_DISABLE_ALL_MAILS))
123
-	                	{
124
-	                		// Init to avoid errors
125
-	                		$filepath = array();
126
-	                		$filename = array();
127
-	                		$mimetype = array();
128
-
129
-	                		// Send email to assigned user
130
-		                    $subject = '[' . $conf->global->MAIN_INFO_SOCIETE_NOM . '] ' . $langs->transnoentities('TicketAssignedToYou');
131
-		                    $message = '<p>' . $langs->transnoentities('TicketAssignedEmailBody', $object->track_id, dolGetFirstLastname($user->firstname, $user->lastname)) . "</p>";
132
-		                    $message .= '<ul><li>' . $langs->trans('Title') . ' : ' . $object->subject . '</li>';
133
-		                    $message .= '<li>' . $langs->trans('Type') . ' : ' . $object->type_label . '</li>';
134
-		                    $message .= '<li>' . $langs->trans('Category') . ' : ' . $object->category_label . '</li>';
135
-		                    $message .= '<li>' . $langs->trans('Severity') . ' : ' . $object->severity_label . '</li>';
136
-		                    // Extrafields
137
-		                    if (is_array($object->array_options) && count($object->array_options) > 0) {
138
-		                        foreach ($object->array_options as $key => $value) {
139
-	                                $message .= '<li>' . $langs->trans($key) . ' : ' . $value . '</li>';
140
-		                        }
141
-		                    }
142
-
143
-		                    $message .= '</ul>';
144
-		                    $message .= '<p>' . $langs->trans('Message') . ' : <br>' . $object->message . '</p>';
145
-		                    $message .= '<p><a href="' . dol_buildpath('/ticket/card.php', 2) . '?track_id=' . $object->track_id . '">' . $langs->trans('SeeThisTicketIntomanagementInterface') . '</a></p>';
146
-
147
-		                    $sendto = $userstat->email;
148
-		                    $from = dolGetFirstLastname($user->firstname, $user->lastname) . '<' . $user->email . '>';
149
-
150
-	                        $message = dol_nl2br($message);
151
-
152
-	                        if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
153
-	                            $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
154
-	                            $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
155
-	                        }
156
-	                        include_once DOL_DOCUMENT_ROOT . '/core/class/CMailFile.class.php';
157
-		                    $mailfile = new CMailFile($subject, $sendto, $from, $message, $filepath, $mimetype, $filename, '', '', 0, -1);
158
-		                    if ($mailfile->error) {
159
-	                            setEventMessages($mailfile->error, $mailfile->errors, 'errors');
160
-		                    } else {
161
-		                        $result = $mailfile->sendfile();
162
-		                    }
163
-	                        if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
164
-	                            $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
165
-	                        }
166
-	                	}
110
+        $ok = 0;
111
+
112
+        switch ($action) {
113
+            case 'TICKET_ASSIGNED':
114
+                dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
115
+
116
+                if ($object->fk_user_assign > 0 && $object->fk_user_assign != $user->id)
117
+                {
118
+                    $userstat = new User($this->db);
119
+                    $res = $userstat->fetch($object->fk_user_assign);
120
+                    if ($res > 0)
121
+                    {
122
+                        if (empty($conf->global->TICKET_DISABLE_ALL_MAILS))
123
+                        {
124
+                            // Init to avoid errors
125
+                            $filepath = array();
126
+                            $filename = array();
127
+                            $mimetype = array();
128
+
129
+                            // Send email to assigned user
130
+                            $subject = '[' . $conf->global->MAIN_INFO_SOCIETE_NOM . '] ' . $langs->transnoentities('TicketAssignedToYou');
131
+                            $message = '<p>' . $langs->transnoentities('TicketAssignedEmailBody', $object->track_id, dolGetFirstLastname($user->firstname, $user->lastname)) . "</p>";
132
+                            $message .= '<ul><li>' . $langs->trans('Title') . ' : ' . $object->subject . '</li>';
133
+                            $message .= '<li>' . $langs->trans('Type') . ' : ' . $object->type_label . '</li>';
134
+                            $message .= '<li>' . $langs->trans('Category') . ' : ' . $object->category_label . '</li>';
135
+                            $message .= '<li>' . $langs->trans('Severity') . ' : ' . $object->severity_label . '</li>';
136
+                            // Extrafields
137
+                            if (is_array($object->array_options) && count($object->array_options) > 0) {
138
+                                foreach ($object->array_options as $key => $value) {
139
+                                    $message .= '<li>' . $langs->trans($key) . ' : ' . $value . '</li>';
140
+                                }
141
+                            }
142
+
143
+                            $message .= '</ul>';
144
+                            $message .= '<p>' . $langs->trans('Message') . ' : <br>' . $object->message . '</p>';
145
+                            $message .= '<p><a href="' . dol_buildpath('/ticket/card.php', 2) . '?track_id=' . $object->track_id . '">' . $langs->trans('SeeThisTicketIntomanagementInterface') . '</a></p>';
146
+
147
+                            $sendto = $userstat->email;
148
+                            $from = dolGetFirstLastname($user->firstname, $user->lastname) . '<' . $user->email . '>';
149
+
150
+                            $message = dol_nl2br($message);
151
+
152
+                            if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
153
+                                $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
154
+                                $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
155
+                            }
156
+                            include_once DOL_DOCUMENT_ROOT . '/core/class/CMailFile.class.php';
157
+                            $mailfile = new CMailFile($subject, $sendto, $from, $message, $filepath, $mimetype, $filename, '', '', 0, -1);
158
+                            if ($mailfile->error) {
159
+                                setEventMessages($mailfile->error, $mailfile->errors, 'errors');
160
+                            } else {
161
+                                $result = $mailfile->sendfile();
162
+                            }
163
+                            if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
164
+                                $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
165
+                            }
166
+                        }
167 167
 
168 168
                         $ok = 1;
169
-	                }
170
-	                else
171
-	                {
172
-	                	$this->error = $userstat->error;
173
-	                	$this->errors = $userstat->errors;
174
-	                }
175
-	            }
176
-	            break;
177
-
178
-    		case 'TICKET_CREATE':
179
-	            dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
180
-
181
-	            $langs->load('ticket');
182
-
183
-	            $object->fetch('', $object->track_id);	// Should be useless
184
-
185
-
186
-	            // Send email to notification email
187
-
188
-	            if (empty($conf->global->TICKET_DISABLE_ALL_MAILS) && empty($object->context['disableticketemail']))
189
-	            {
190
-		            $sendto = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
191
-
192
-		            if ($sendto)
193
-					{
194
-						// Init to avoid errors
195
-						$filepath = array();
196
-						$filename = array();
197
-						$mimetype = array();
198
-
199
-						/* Send email to admin */
200
-			            $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNewEmailSubjectAdmin');
201
-			            $message_admin= $langs->transnoentities('TicketNewEmailBodyAdmin', $object->track_id)."\n\n";
202
-			            $message_admin.='<ul><li>'.$langs->trans('Title').' : '.$object->subject.'</li>';
203
-			            $message_admin.='<li>'.$langs->trans('Type').' : '.$object->type_label.'</li>';
204
-			            $message_admin.='<li>'.$langs->trans('Category').' : '.$object->category_label.'</li>';
205
-			            $message_admin.='<li>'.$langs->trans('Severity').' : '.$object->severity_label.'</li>';
206
-			            $message_admin.='<li>'.$langs->trans('From').' : '.( $object->email_from ? $object->email_from : ( $object->fk_user_create > 0 ? $langs->trans('Internal') : '') ).'</li>';
207
-			            // Extrafields
208
-			            if (is_array($object->array_options) && count($object->array_options) > 0) {
209
-			                foreach ($object->array_options as $key => $value) {
210
-			                      $message_admin.='<li>'.$langs->trans($key).' : '.$value.'</li>';
211
-			                }
212
-			            }
213
-			            $message_admin.='</ul>';
214
-
215
-			            if ($object->fk_soc > 0) {
216
-			                      $object->fetch_thirdparty();
217
-			                      $message_admin.='<p>'.$langs->trans('Company'). ' : '.$object->thirdparty->name.'</p>';
218
-			            }
219
-
220
-			            $message_admin.='<p>'.$langs->trans('Message').' : <br>'.$object->message.'</p>';
221
-			            $message_admin.='<p><a href="'.dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id.'">'.$langs->trans('SeeThisTicketIntomanagementInterface').'</a></p>';
222
-
223
-			            $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>';
224
-			            $replyto = $from;
225
-
226
-		                $message_admin = dol_nl2br($message_admin);
227
-
228
-		                if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
229
-		                    $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
230
-		                    $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
231
-		                }
232
-		                include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
233
-			            $mailfile = new CMailFile($subject, $sendto, $from, $message_admin, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1);
234
-			            if ($mailfile->error) {
235
-		                    dol_syslog($mailfile->error, LOG_DEBUG);
236
-			            } else {
237
-			                     $result=$mailfile->sendfile();
238
-			            }
239
-		                if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
240
-		                    $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
241
-		                }
242
-					}
243
-	            }
244
-
245
-				// Send email to customer
246
-
247
-				if (empty($conf->global->TICKET_DISABLE_ALL_MAILS) && empty($object->context['disableticketemail']) && $object->notify_tiers_at_create)
248
-	            {
249
-		            $sendto = '';
250
-		            if (empty($user->socid) && empty($user->email)) {
251
-		                      $object->fetch_thirdparty();
252
-		                      $sendto = $object->thirdparty->email;
253
-		            } else {
254
-		                $sendto = $user->email;
255
-		            }
256
-
257
-		            if ($sendto) {
258
-		            	// Init to avoid errors
259
-		            	$filepath = array();
260
-		            	$filename = array();
261
-		            	$mimetype = array();
262
-
263
-		            	$subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNewEmailSubjectCustomer');
264
-			            $message_customer= $langs->transnoentities('TicketNewEmailBodyCustomer', $object->track_id)."\n\n";
265
-			            $message_customer.='<ul><li>'.$langs->trans('Title').' : '.$object->subject.'</li>';
266
-			            $message_customer.='<li>'.$langs->trans('Type').' : '.$object->type_label.'</li>';
267
-			            $message_customer.='<li>'.$langs->trans('Category').' : '.$object->category_label.'</li>';
268
-			            $message_customer.='<li>'.$langs->trans('Severity').' : '.$object->severity_label.'</li>';
269
-
270
-			            // Extrafields
271
-			            foreach ($this->attributes[$object->table_element]['label'] as $key => $value)
272
-			            {
273
-			            	$enabled = 1;
274
-			            	if ($enabled && isset($this->attributes[$object->table_element]['list'][$key]))
275
-			            	{
276
-			            		$enabled = dol_eval($this->attributes[$object->table_element]['list'][$key], 1);
277
-			            	}
278
-			            	$perms = 1;
279
-			            	if ($perms && isset($this->attributes[$object->table_element]['perms'][$key]))
280
-			            	{
281
-			            		$perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1);
282
-			            	}
283
-
284
-			            	$qualified = true;
285
-			            	if (empty($enabled)) $qualified = false;
286
-			            	if (empty($perms)) $qualified = false;
287
-
288
-			            	if ($qualified) $message_customer.='<li>'.$langs->trans($key).' : '.$value.'</li>';
289
-			            }
290
-
291
-			            $message_customer.='</ul>';
292
-			            $message_customer.='<p>'.$langs->trans('Message').' : <br>'.$object->message.'</p>';
293
-			            $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE?$conf->global->TICKET_URL_PUBLIC_INTERFACE.'/':dol_buildpath('/public/ticket/view.php', 2)).'?track_id='.$object->track_id;
294
-			            $message_customer.='<p>' . $langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer') . ' : <a href="'.$url_public_ticket.'">'.$url_public_ticket.'</a></p>';
295
-			            $message_customer.='<p>'.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmail').'</p>';
296
-
297
-			            $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>';
298
-			            $replyto = $from;
299
-
300
-	                    $message_customer = dol_nl2br($message_customer);
301
-
302
-	                    if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
303
-	                        $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
304
-	                        $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
305
-	                    }
306
-	                    include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
307
-			            $mailfile = new CMailFile($subject, $sendto, $from, $message_customer, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1);
308
-			            if ($mailfile->error) {
309
-	                        dol_syslog($mailfile->error, LOG_DEBUG);
310
-			            } else {
311
-			                      $result=$mailfile->sendfile();
312
-			            }
313
-	                    if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
314
-	                        $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
315
-	                    }
316
-	                }
317
-	            }
169
+                    }
170
+                    else
171
+                    {
172
+                        $this->error = $userstat->error;
173
+                        $this->errors = $userstat->errors;
174
+                    }
175
+                }
176
+                break;
177
+
178
+            case 'TICKET_CREATE':
179
+                dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
180
+
181
+                $langs->load('ticket');
182
+
183
+                $object->fetch('', $object->track_id);	// Should be useless
184
+
185
+
186
+                // Send email to notification email
187
+
188
+                if (empty($conf->global->TICKET_DISABLE_ALL_MAILS) && empty($object->context['disableticketemail']))
189
+                {
190
+                    $sendto = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
191
+
192
+                    if ($sendto)
193
+                    {
194
+                        // Init to avoid errors
195
+                        $filepath = array();
196
+                        $filename = array();
197
+                        $mimetype = array();
198
+
199
+                        /* Send email to admin */
200
+                        $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNewEmailSubjectAdmin');
201
+                        $message_admin= $langs->transnoentities('TicketNewEmailBodyAdmin', $object->track_id)."\n\n";
202
+                        $message_admin.='<ul><li>'.$langs->trans('Title').' : '.$object->subject.'</li>';
203
+                        $message_admin.='<li>'.$langs->trans('Type').' : '.$object->type_label.'</li>';
204
+                        $message_admin.='<li>'.$langs->trans('Category').' : '.$object->category_label.'</li>';
205
+                        $message_admin.='<li>'.$langs->trans('Severity').' : '.$object->severity_label.'</li>';
206
+                        $message_admin.='<li>'.$langs->trans('From').' : '.( $object->email_from ? $object->email_from : ( $object->fk_user_create > 0 ? $langs->trans('Internal') : '') ).'</li>';
207
+                        // Extrafields
208
+                        if (is_array($object->array_options) && count($object->array_options) > 0) {
209
+                            foreach ($object->array_options as $key => $value) {
210
+                                    $message_admin.='<li>'.$langs->trans($key).' : '.$value.'</li>';
211
+                            }
212
+                        }
213
+                        $message_admin.='</ul>';
214
+
215
+                        if ($object->fk_soc > 0) {
216
+                                    $object->fetch_thirdparty();
217
+                                    $message_admin.='<p>'.$langs->trans('Company'). ' : '.$object->thirdparty->name.'</p>';
218
+                        }
219
+
220
+                        $message_admin.='<p>'.$langs->trans('Message').' : <br>'.$object->message.'</p>';
221
+                        $message_admin.='<p><a href="'.dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id.'">'.$langs->trans('SeeThisTicketIntomanagementInterface').'</a></p>';
222
+
223
+                        $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>';
224
+                        $replyto = $from;
225
+
226
+                        $message_admin = dol_nl2br($message_admin);
227
+
228
+                        if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
229
+                            $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
230
+                            $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
231
+                        }
232
+                        include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
233
+                        $mailfile = new CMailFile($subject, $sendto, $from, $message_admin, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1);
234
+                        if ($mailfile->error) {
235
+                            dol_syslog($mailfile->error, LOG_DEBUG);
236
+                        } else {
237
+                                    $result=$mailfile->sendfile();
238
+                        }
239
+                        if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
240
+                            $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
241
+                        }
242
+                    }
243
+                }
244
+
245
+                // Send email to customer
246
+
247
+                if (empty($conf->global->TICKET_DISABLE_ALL_MAILS) && empty($object->context['disableticketemail']) && $object->notify_tiers_at_create)
248
+                {
249
+                    $sendto = '';
250
+                    if (empty($user->socid) && empty($user->email)) {
251
+                                $object->fetch_thirdparty();
252
+                                $sendto = $object->thirdparty->email;
253
+                    } else {
254
+                        $sendto = $user->email;
255
+                    }
256
+
257
+                    if ($sendto) {
258
+                        // Init to avoid errors
259
+                        $filepath = array();
260
+                        $filename = array();
261
+                        $mimetype = array();
262
+
263
+                        $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNewEmailSubjectCustomer');
264
+                        $message_customer= $langs->transnoentities('TicketNewEmailBodyCustomer', $object->track_id)."\n\n";
265
+                        $message_customer.='<ul><li>'.$langs->trans('Title').' : '.$object->subject.'</li>';
266
+                        $message_customer.='<li>'.$langs->trans('Type').' : '.$object->type_label.'</li>';
267
+                        $message_customer.='<li>'.$langs->trans('Category').' : '.$object->category_label.'</li>';
268
+                        $message_customer.='<li>'.$langs->trans('Severity').' : '.$object->severity_label.'</li>';
269
+
270
+                        // Extrafields
271
+                        foreach ($this->attributes[$object->table_element]['label'] as $key => $value)
272
+                        {
273
+                            $enabled = 1;
274
+                            if ($enabled && isset($this->attributes[$object->table_element]['list'][$key]))
275
+                            {
276
+                                $enabled = dol_eval($this->attributes[$object->table_element]['list'][$key], 1);
277
+                            }
278
+                            $perms = 1;
279
+                            if ($perms && isset($this->attributes[$object->table_element]['perms'][$key]))
280
+                            {
281
+                                $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1);
282
+                            }
283
+
284
+                            $qualified = true;
285
+                            if (empty($enabled)) $qualified = false;
286
+                            if (empty($perms)) $qualified = false;
287
+
288
+                            if ($qualified) $message_customer.='<li>'.$langs->trans($key).' : '.$value.'</li>';
289
+                        }
290
+
291
+                        $message_customer.='</ul>';
292
+                        $message_customer.='<p>'.$langs->trans('Message').' : <br>'.$object->message.'</p>';
293
+                        $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE?$conf->global->TICKET_URL_PUBLIC_INTERFACE.'/':dol_buildpath('/public/ticket/view.php', 2)).'?track_id='.$object->track_id;
294
+                        $message_customer.='<p>' . $langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer') . ' : <a href="'.$url_public_ticket.'">'.$url_public_ticket.'</a></p>';
295
+                        $message_customer.='<p>'.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmail').'</p>';
296
+
297
+                        $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>';
298
+                        $replyto = $from;
299
+
300
+                        $message_customer = dol_nl2br($message_customer);
301
+
302
+                        if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
303
+                            $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
304
+                            $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
305
+                        }
306
+                        include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
307
+                        $mailfile = new CMailFile($subject, $sendto, $from, $message_customer, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1);
308
+                        if ($mailfile->error) {
309
+                            dol_syslog($mailfile->error, LOG_DEBUG);
310
+                        } else {
311
+                                    $result=$mailfile->sendfile();
312
+                        }
313
+                        if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
314
+                            $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
315
+                        }
316
+                    }
317
+                }
318 318
                 $ok = 1;
319
-	            break;
319
+                break;
320 320
 
321 321
             case 'TICKET_DELETE':
322
-            	dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
323
-            	break;
322
+                dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
323
+                break;
324 324
 
325
-           	case 'TICKET_MODIFY':
326
-           		dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
327
-           		break;
325
+                case 'TICKET_MODIFY':
326
+                   dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
327
+                    break;
328 328
 
329
-           	case 'TICKET_MARK_READ':
330
-           		dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
331
-           		break;
329
+                case 'TICKET_MARK_READ':
330
+                   dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
331
+                    break;
332 332
 
333
-           	case 'TICKET_CLOSE':
334
-           		dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
335
-           		break;
336
-    	}
333
+                case 'TICKET_CLOSE':
334
+                   dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
335
+                    break;
336
+        }
337 337
 
338 338
 
339 339
         return $ok;
Please login to merge, or discard this patch.
Helpers/triggers/interface_50_modMailmanspip_Mailmanspipsynchro.class.php 1 patch
Indentation   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -29,33 +29,33 @@  discard block
 block discarded – undo
29 29
  */
30 30
 class InterfaceMailmanSpipsynchro extends DolibarrTriggers
31 31
 {
32
-	public $family = 'mailmanspip';
33
-	public $description = "Triggers of this module allows to synchronize Mailman an Spip.";
34
-
35
-	/**
36
-	 * Version of the trigger
37
-	 * @var string
38
-	 */
39
-	public $version = self::VERSION_DOLIBARR;
40
-
41
-	/**
42
-	 * @var string Image of the trigger
43
-	 */
44
-	public $picto = 'technic';
45
-
46
-	/**
47
-	 * Function called when a Dolibarrr business event is done.
48
-	 * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
49
-	 *
50
-	 * @param string		$action		Event action code
51
-	 * @param Object		$object     Object
52
-	 * @param User		    $user       Object user
53
-	 * @param Translate 	$langs      Object langs
54
-	 * @param conf		    $conf       Object conf
55
-	 * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
56
-	 */
57
-	public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
58
-	{
32
+    public $family = 'mailmanspip';
33
+    public $description = "Triggers of this module allows to synchronize Mailman an Spip.";
34
+
35
+    /**
36
+     * Version of the trigger
37
+     * @var string
38
+     */
39
+    public $version = self::VERSION_DOLIBARR;
40
+
41
+    /**
42
+     * @var string Image of the trigger
43
+     */
44
+    public $picto = 'technic';
45
+
46
+    /**
47
+     * Function called when a Dolibarrr business event is done.
48
+     * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
49
+     *
50
+     * @param string		$action		Event action code
51
+     * @param Object		$object     Object
52
+     * @param User		    $user       Object user
53
+     * @param Translate 	$langs      Object langs
54
+     * @param conf		    $conf       Object conf
55
+     * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
56
+     */
57
+    public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
58
+    {
59 59
         if (empty($conf->mailmanspip->enabled)) return 0;     // Module not active, we do nothing
60 60
 
61 61
         require_once DOL_DOCUMENT_ROOT."/mailmanspip/class/mailmanspip.class.php";
@@ -63,39 +63,39 @@  discard block
 block discarded – undo
63 63
 
64 64
         if ($action == 'CATEGORY_LINK')
65 65
         {
66
-        	dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
67
-
68
-        	// We add subscription if we change category (new category may means more mailing-list to subscribe)
69
-        	if (is_object($object->context['linkto']) && method_exists($object->context['linkto'], 'add_to_abo') && $object->context['linkto']->add_to_abo() < 0)
70
-    		{
71
-    			$this->error=$object->context['linkto']->error;
72
-    			$this->errors=$object->context['linkto']->errors;
73
-    			$return=-1;
74
-    		}
75
-			else
76
-			{
77
-				$return=1;
78
-			}
79
-
80
-        	return $return;
66
+            dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
67
+
68
+            // We add subscription if we change category (new category may means more mailing-list to subscribe)
69
+            if (is_object($object->context['linkto']) && method_exists($object->context['linkto'], 'add_to_abo') && $object->context['linkto']->add_to_abo() < 0)
70
+            {
71
+                $this->error=$object->context['linkto']->error;
72
+                $this->errors=$object->context['linkto']->errors;
73
+                $return=-1;
74
+            }
75
+            else
76
+            {
77
+                $return=1;
78
+            }
79
+
80
+            return $return;
81 81
         }
82 82
         elseif ($action == 'CATEGORY_UNLINK')
83 83
         {
84
-        	dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
85
-
86
-        	// We remove subscription if we change category (lessw category may means less mailing-list to subscribe)
87
-        	if (is_object($object->context['unlinkoff']) && method_exists($object->context['unlinkoff'], 'del_to_abo') && $object->context['unlinkoff']->del_to_abo() < 0)
88
-        	{
89
-        		$this->error=$object->context['unlinkoff']->error;
90
-        		$this->errors=$object->context['unlinkoff']->errors;
91
-        		$return=-1;
92
-        	}
93
-        	else
94
-        	{
95
-        		$return=1;
96
-        	}
97
-
98
-        	return $return;
84
+            dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
85
+
86
+            // We remove subscription if we change category (lessw category may means less mailing-list to subscribe)
87
+            if (is_object($object->context['unlinkoff']) && method_exists($object->context['unlinkoff'], 'del_to_abo') && $object->context['unlinkoff']->del_to_abo() < 0)
88
+            {
89
+                $this->error=$object->context['unlinkoff']->error;
90
+                $this->errors=$object->context['unlinkoff']->errors;
91
+                $return=-1;
92
+            }
93
+            else
94
+            {
95
+                $return=1;
96
+            }
97
+
98
+            return $return;
99 99
         }
100 100
 
101 101
         // Members
@@ -103,37 +103,37 @@  discard block
 block discarded – undo
103 103
         {
104 104
             dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
105 105
 
106
-			$return=0;
106
+            $return=0;
107 107
             // Add user into some linked tools (mailman, spip, etc...)
108
-			if (($object->oldcopy->email != $object->email) || ($object->oldcopy->typeid != $object->typeid))	// TODO Do del/add also if type change
109
-			{
110
-				if (is_object($object->oldcopy) && ($object->oldcopy->email != $object->email))    // If email has changed we delete mailman subscription for old email
111
-				{
112
-					if ($object->oldcopy->del_to_abo() < 0)
113
-					{
114
-						if (! empty($object->oldcopy->error)) $this->error=$object->oldcopy->error;
115
-						$this->errors=$object->oldcopy->errors;
116
-						$return=-1;
117
-					}
118
-					else
119
-					{
120
-						$return=1;
121
-					}
122
-				}
123
-    			// We add subscription if new email or new type (new type may means more mailing-list to subscribe)
124
-    			if ($object->add_to_abo() < 0)
125
-    			{
126
-    				 if (! empty($object->error)) $this->error=$object->error;
127
-    				 $this->errors=$object->errors;
128
-    				 $return=-1;
129
-    			}
130
-				else
131
-				{
132
-					$return=1;
133
-				}
134
-			}
135
-
136
-			return $return;
108
+            if (($object->oldcopy->email != $object->email) || ($object->oldcopy->typeid != $object->typeid))	// TODO Do del/add also if type change
109
+            {
110
+                if (is_object($object->oldcopy) && ($object->oldcopy->email != $object->email))    // If email has changed we delete mailman subscription for old email
111
+                {
112
+                    if ($object->oldcopy->del_to_abo() < 0)
113
+                    {
114
+                        if (! empty($object->oldcopy->error)) $this->error=$object->oldcopy->error;
115
+                        $this->errors=$object->oldcopy->errors;
116
+                        $return=-1;
117
+                    }
118
+                    else
119
+                    {
120
+                        $return=1;
121
+                    }
122
+                }
123
+                // We add subscription if new email or new type (new type may means more mailing-list to subscribe)
124
+                if ($object->add_to_abo() < 0)
125
+                {
126
+                        if (! empty($object->error)) $this->error=$object->error;
127
+                        $this->errors=$object->errors;
128
+                        $return=-1;
129
+                }
130
+                else
131
+                {
132
+                    $return=1;
133
+                }
134
+            }
135
+
136
+            return $return;
137 137
         }
138 138
         elseif ($action == 'MEMBER_RESILIATE' || $action == 'MEMBER_DELETE')
139 139
         {
@@ -141,20 +141,20 @@  discard block
 block discarded – undo
141 141
 
142 142
             $return=0;
143 143
             // Remove from external tools (mailman, spip, etc...)
144
-        	if ($object->del_to_abo() < 0)
145
-			{
146
-				if (! empty($object->error)) $this->error=$object->error;
147
-				$this->errors=$object->errors;
148
-				$return=-1;
149
-			}
150
-			else
151
-			{
152
-				$return=1;
153
-			}
154
-
155
-	        return $return;
144
+            if ($object->del_to_abo() < 0)
145
+            {
146
+                if (! empty($object->error)) $this->error=$object->error;
147
+                $this->errors=$object->errors;
148
+                $return=-1;
149
+            }
150
+            else
151
+            {
152
+                $return=1;
153
+            }
154
+
155
+            return $return;
156 156
         }
157 157
 
158
-		return 0;
158
+        return 0;
159 159
     }
160 160
 }
Please login to merge, or discard this patch.
Helpers/triggers/interface_80_modStripe_Stripe.class.php 1 patch
Indentation   +210 added lines, -210 removed lines patch added patch discarded remove patch
@@ -50,221 +50,221 @@
 block discarded – undo
50 50
         $this->db = $db;
51 51
 
52 52
         $this->name = preg_replace('/^Interface/i', '', get_class($this));
53
-	    $this->family = 'stripe';
53
+        $this->family = 'stripe';
54 54
         $this->description = "Triggers of the module Stripe";
55 55
         $this->version = 'dolibarr'; // 'development', 'experimental', 'dolibarr' or version
56 56
         $this->picto = 'stripe@stripe';
57 57
     }
58 58
 
59
-	/**
60
-	 * Trigger name
61
-	 *
62
-	 * @return string Name of trigger file
63
-	 */
64
-	public function getName()
65
-	{
66
-		return $this->name;
67
-	}
68
-
69
-
70
-	/**
71
-	 * Trigger description
72
-	 *
73
-	 * @return string Description of trigger file
74
-	 */
75
-	public function getDesc()
76
-	{
77
-		return $this->description;
78
-	}
79
-
80
-	/**
81
-	 * Trigger version
82
-	 *
83
-	 * @return string Version of trigger file
84
-	 */
85
-	public function getVersion()
86
-	{
87
-		global $langs;
88
-		$langs->load("admin");
89
-
90
-		if ($this->version == 'development') {
91
-			return $langs->trans("Development");
92
-		} elseif ($this->version == 'experimental') {
93
-			return $langs->trans("Experimental");
94
-		} elseif ($this->version == 'dolibarr') {
95
-			return DOL_VERSION;
96
-		} elseif ($this->version) {
97
-			return $this->version;
98
-		} else {
99
-			return $langs->trans("Unknown");
100
-		}
101
-	}
102
-
103
-	/**
104
-	 * Function called when a Dolibarrr business event is done.
105
-	 * All functions "runTrigger" are triggered if file
106
-	 * is inside directory core/triggers
107
-	 *
108
-	 * @param 	string 			$action 	Event action code
109
-	 * @param 	CommonObject 	$object 	Object
110
-	 * @param 	User 			$user 		Object user
111
-	 * @param 	Translate 		$langs 		Object langs
112
-	 * @param 	Conf 			$conf 		Object conf
113
-	 * @return 	int              			<0 if KO, 0 if no triggered ran, >0 if OK
114
-	 */
115
-	public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
116
-	{
117
-		// Put here code you want to execute when a Dolibarr business event occurs.
118
-		// Data and type of action are stored into $object and $action
119
-		global $langs, $db, $conf;
120
-
121
-		// Load translation files required by the page
59
+    /**
60
+     * Trigger name
61
+     *
62
+     * @return string Name of trigger file
63
+     */
64
+    public function getName()
65
+    {
66
+        return $this->name;
67
+    }
68
+
69
+
70
+    /**
71
+     * Trigger description
72
+     *
73
+     * @return string Description of trigger file
74
+     */
75
+    public function getDesc()
76
+    {
77
+        return $this->description;
78
+    }
79
+
80
+    /**
81
+     * Trigger version
82
+     *
83
+     * @return string Version of trigger file
84
+     */
85
+    public function getVersion()
86
+    {
87
+        global $langs;
88
+        $langs->load("admin");
89
+
90
+        if ($this->version == 'development') {
91
+            return $langs->trans("Development");
92
+        } elseif ($this->version == 'experimental') {
93
+            return $langs->trans("Experimental");
94
+        } elseif ($this->version == 'dolibarr') {
95
+            return DOL_VERSION;
96
+        } elseif ($this->version) {
97
+            return $this->version;
98
+        } else {
99
+            return $langs->trans("Unknown");
100
+        }
101
+    }
102
+
103
+    /**
104
+     * Function called when a Dolibarrr business event is done.
105
+     * All functions "runTrigger" are triggered if file
106
+     * is inside directory core/triggers
107
+     *
108
+     * @param 	string 			$action 	Event action code
109
+     * @param 	CommonObject 	$object 	Object
110
+     * @param 	User 			$user 		Object user
111
+     * @param 	Translate 		$langs 		Object langs
112
+     * @param 	Conf 			$conf 		Object conf
113
+     * @return 	int              			<0 if KO, 0 if no triggered ran, >0 if OK
114
+     */
115
+    public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
116
+    {
117
+        // Put here code you want to execute when a Dolibarr business event occurs.
118
+        // Data and type of action are stored into $object and $action
119
+        global $langs, $db, $conf;
120
+
121
+        // Load translation files required by the page
122 122
         $langs->loadLangs(array("members","other","users","mails"));
123 123
 
124
-		require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
125
-		$stripe = new Stripe($db);
126
-
127
-		if (empty($conf->stripe->enabled)) return 0;
128
-
129
-		$ok = 1;
130
-
131
-		$service = 'StripeTest';
132
-		$servicestatus = 0;
133
-		if (! empty($conf->global->STRIPE_LIVE) && ! GETPOST('forcesandbox', 'alpha'))
134
-		{
135
-			$service = 'StripeLive';
136
-			$servicestatus = 1;
137
-		}
138
-
139
-		// If customer is linked to Stripe, we update/delete Stripe too
140
-		if ($action == 'COMPANY_MODIFY') {
141
-			dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
142
-
143
-			$stripeacc = $stripe->getStripeAccount($service);	// No need of network access for this. May return '' if no Oauth defined.
144
-
145
-			if ($object->client != 0) {
146
-				$customer = $stripe->customerStripe($object, $stripeacc, $servicestatus);	// This make a network request
147
-				if ($customer)
148
-				{
149
-					$namecleaned = $object->name ? $object->name : null;
150
-					$vatcleaned = $object->tva_intra ? $object->tva_intra : null;
151
-
152
-					$taxinfo = array('type'=>'vat');
153
-					if ($vatcleaned)
154
-					{
155
-						$taxinfo["tax_id"] = $vatcleaned;
156
-					}
157
-					// We force data to "null" if not defined as expected by Stripe
158
-					if (empty($vatcleaned)) $taxinfo=null;
159
-
160
-					// Detect if we change a Stripe info (email, description, vat id)
161
-					$changerequested = 0;
162
-					if (! empty($object->email) && $object->email != $customer->email) $changerequested++;
163
-					if ($namecleaned != $customer->description) $changerequested++;
164
-					if (! isset($customer->tax_info['tax_id']) && ! is_null($vatcleaned)) $changerequested++;
165
-					elseif (isset($customer->tax_info['tax_id']) && is_null($vatcleaned)) $changerequested++;
166
-					elseif (isset($customer->tax_info['tax_id']) && ! is_null($vatcleaned))
167
-					{
168
-						if ($vatcleaned != $customer->tax_info['tax_id']) $changerequested++;
169
-					}
170
-
171
-					if ($changerequested)
172
-					{
173
-						if (! empty($object->email)) $customer->email = $object->email;
174
-						$customer->description = $namecleaned;
175
-						if (empty($taxinfo)) $customer->tax_info = array('type'=>'vat', 'tax_id'=>null);
176
-						else $customer->tax_info = $taxinfo;
177
-
178
-						$customer->save();
179
-					}
180
-				}
181
-			}
182
-		}
183
-		if ($action == 'COMPANY_DELETE') {
184
-			dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
185
-
186
-			$stripeacc = $stripe->getStripeAccount($service);	// No need of network access for this. May return '' if no Oauth defined.
187
-
188
-			$customer = $stripe->customerStripe($object, $stripeacc, $servicestatus);
189
-			if ($customer)
190
-			{
191
-				$customer->delete();
192
-			}
193
-
194
-			$sql = "DELETE FROM ".MAIN_DB_PREFIX."societe_account";
195
-			$sql.= " WHERE site='stripe' AND fk_soc = " . $object->id;
196
-			$this->db->query($sql);
197
-		}
198
-
199
-		// If payment mode is linked to Stripee, we update/delete Stripe too
200
-		if ($action == 'COMPANYPAYMENTMODE_MODIFY' && $object->type == 'card') {
201
-
202
-			// For creation of credit card, we do not create in Stripe automatically
203
-		}
204
-		if ($action == 'COMPANYPAYMENTMODE_MODIFY' && $object->type == 'card') {
205
-			dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
206
-
207
-			if (! empty($object->stripe_card_ref))
208
-			{
209
-				$stripeacc = $stripe->getStripeAccount($service);				// No need of network access for this. May return '' if no Oauth defined.
210
-				$stripecu = $stripe->getStripeCustomerAccount($object->fk_soc);	// No need of network access for this
211
-
212
-				if ($stripecu)
213
-				{
214
-					// Get customer (required to get a card)
215
-					if (empty($stripeacc)) {				// If the Stripe connect account not set, we use common API usage
216
-						$customer = \Stripe\Customer::retrieve($stripecu);
217
-					} else {
218
-						$customer = \Stripe\Customer::retrieve($stripecu, array("stripe_account" => $stripeacc));
219
-					}
220
-
221
-					if ($customer)
222
-					{
223
-						$card = $stripe->cardStripe($customer, $object, $stripeacc, $servicestatus);
224
-						if ($card) {
225
-							$card->metadata=array('dol_id'=>$object->id, 'dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>(empty($_SERVER['REMOTE_ADDR'])?'':$_SERVER['REMOTE_ADDR']));
226
-							try {
227
-								$card->save($dataforcard);
228
-							}
229
-							catch(Exception $e)
230
-							{
231
-								$ok = -1;
232
-								$this->error = $e->getMessages();
233
-							}
234
-						}
235
-					}
236
-				}
237
-			}
238
-		}
239
-		if ($action == 'COMPANYPAYMENTMODE_DELETE' && $object->type == 'card') {
240
-			dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
241
-
242
-			if (! empty($object->stripe_card_ref))
243
-			{
244
-				$stripeacc = $stripe->getStripeAccount($service);				// No need of network access for this. May return '' if no Oauth defined.
245
-				$stripecu = $stripe->getStripeCustomerAccount($object->fk_soc);	// No need of network access for this
246
-
247
-				if ($stripecu)
248
-				{
249
-					// Get customer (required to get a card)
250
-					if (empty($stripeacc)) {				// If the Stripe connect account not set, we use common API usage
251
-						$customer = \Stripe\Customer::retrieve($stripecu);
252
-					} else {
253
-						$customer = \Stripe\Customer::retrieve($stripecu, array("stripe_account" => $stripeacc));
254
-					}
255
-
256
-					if ($customer)
257
-					{
258
-						$card = $stripe->cardStripe($customer, $object, $stripeacc, $servicestatus);
259
-						if ($card) {
260
-							if (method_exists($card, 'detach')) $card->detach();
261
-							else $card->delete();
262
-						}
263
-					}
264
-				}
265
-			}
266
-		}
267
-
268
-		return $ok;
269
-	}
124
+        require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
125
+        $stripe = new Stripe($db);
126
+
127
+        if (empty($conf->stripe->enabled)) return 0;
128
+
129
+        $ok = 1;
130
+
131
+        $service = 'StripeTest';
132
+        $servicestatus = 0;
133
+        if (! empty($conf->global->STRIPE_LIVE) && ! GETPOST('forcesandbox', 'alpha'))
134
+        {
135
+            $service = 'StripeLive';
136
+            $servicestatus = 1;
137
+        }
138
+
139
+        // If customer is linked to Stripe, we update/delete Stripe too
140
+        if ($action == 'COMPANY_MODIFY') {
141
+            dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
142
+
143
+            $stripeacc = $stripe->getStripeAccount($service);	// No need of network access for this. May return '' if no Oauth defined.
144
+
145
+            if ($object->client != 0) {
146
+                $customer = $stripe->customerStripe($object, $stripeacc, $servicestatus);	// This make a network request
147
+                if ($customer)
148
+                {
149
+                    $namecleaned = $object->name ? $object->name : null;
150
+                    $vatcleaned = $object->tva_intra ? $object->tva_intra : null;
151
+
152
+                    $taxinfo = array('type'=>'vat');
153
+                    if ($vatcleaned)
154
+                    {
155
+                        $taxinfo["tax_id"] = $vatcleaned;
156
+                    }
157
+                    // We force data to "null" if not defined as expected by Stripe
158
+                    if (empty($vatcleaned)) $taxinfo=null;
159
+
160
+                    // Detect if we change a Stripe info (email, description, vat id)
161
+                    $changerequested = 0;
162
+                    if (! empty($object->email) && $object->email != $customer->email) $changerequested++;
163
+                    if ($namecleaned != $customer->description) $changerequested++;
164
+                    if (! isset($customer->tax_info['tax_id']) && ! is_null($vatcleaned)) $changerequested++;
165
+                    elseif (isset($customer->tax_info['tax_id']) && is_null($vatcleaned)) $changerequested++;
166
+                    elseif (isset($customer->tax_info['tax_id']) && ! is_null($vatcleaned))
167
+                    {
168
+                        if ($vatcleaned != $customer->tax_info['tax_id']) $changerequested++;
169
+                    }
170
+
171
+                    if ($changerequested)
172
+                    {
173
+                        if (! empty($object->email)) $customer->email = $object->email;
174
+                        $customer->description = $namecleaned;
175
+                        if (empty($taxinfo)) $customer->tax_info = array('type'=>'vat', 'tax_id'=>null);
176
+                        else $customer->tax_info = $taxinfo;
177
+
178
+                        $customer->save();
179
+                    }
180
+                }
181
+            }
182
+        }
183
+        if ($action == 'COMPANY_DELETE') {
184
+            dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
185
+
186
+            $stripeacc = $stripe->getStripeAccount($service);	// No need of network access for this. May return '' if no Oauth defined.
187
+
188
+            $customer = $stripe->customerStripe($object, $stripeacc, $servicestatus);
189
+            if ($customer)
190
+            {
191
+                $customer->delete();
192
+            }
193
+
194
+            $sql = "DELETE FROM ".MAIN_DB_PREFIX."societe_account";
195
+            $sql.= " WHERE site='stripe' AND fk_soc = " . $object->id;
196
+            $this->db->query($sql);
197
+        }
198
+
199
+        // If payment mode is linked to Stripee, we update/delete Stripe too
200
+        if ($action == 'COMPANYPAYMENTMODE_MODIFY' && $object->type == 'card') {
201
+
202
+            // For creation of credit card, we do not create in Stripe automatically
203
+        }
204
+        if ($action == 'COMPANYPAYMENTMODE_MODIFY' && $object->type == 'card') {
205
+            dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
206
+
207
+            if (! empty($object->stripe_card_ref))
208
+            {
209
+                $stripeacc = $stripe->getStripeAccount($service);				// No need of network access for this. May return '' if no Oauth defined.
210
+                $stripecu = $stripe->getStripeCustomerAccount($object->fk_soc);	// No need of network access for this
211
+
212
+                if ($stripecu)
213
+                {
214
+                    // Get customer (required to get a card)
215
+                    if (empty($stripeacc)) {				// If the Stripe connect account not set, we use common API usage
216
+                        $customer = \Stripe\Customer::retrieve($stripecu);
217
+                    } else {
218
+                        $customer = \Stripe\Customer::retrieve($stripecu, array("stripe_account" => $stripeacc));
219
+                    }
220
+
221
+                    if ($customer)
222
+                    {
223
+                        $card = $stripe->cardStripe($customer, $object, $stripeacc, $servicestatus);
224
+                        if ($card) {
225
+                            $card->metadata=array('dol_id'=>$object->id, 'dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>(empty($_SERVER['REMOTE_ADDR'])?'':$_SERVER['REMOTE_ADDR']));
226
+                            try {
227
+                                $card->save($dataforcard);
228
+                            }
229
+                            catch(Exception $e)
230
+                            {
231
+                                $ok = -1;
232
+                                $this->error = $e->getMessages();
233
+                            }
234
+                        }
235
+                    }
236
+                }
237
+            }
238
+        }
239
+        if ($action == 'COMPANYPAYMENTMODE_DELETE' && $object->type == 'card') {
240
+            dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
241
+
242
+            if (! empty($object->stripe_card_ref))
243
+            {
244
+                $stripeacc = $stripe->getStripeAccount($service);				// No need of network access for this. May return '' if no Oauth defined.
245
+                $stripecu = $stripe->getStripeCustomerAccount($object->fk_soc);	// No need of network access for this
246
+
247
+                if ($stripecu)
248
+                {
249
+                    // Get customer (required to get a card)
250
+                    if (empty($stripeacc)) {				// If the Stripe connect account not set, we use common API usage
251
+                        $customer = \Stripe\Customer::retrieve($stripecu);
252
+                    } else {
253
+                        $customer = \Stripe\Customer::retrieve($stripecu, array("stripe_account" => $stripeacc));
254
+                    }
255
+
256
+                    if ($customer)
257
+                    {
258
+                        $card = $stripe->cardStripe($customer, $object, $stripeacc, $servicestatus);
259
+                        if ($card) {
260
+                            if (method_exists($card, 'detach')) $card->detach();
261
+                            else $card->delete();
262
+                        }
263
+                    }
264
+                }
265
+            }
266
+        }
267
+
268
+        return $ok;
269
+    }
270 270
 }
Please login to merge, or discard this patch.
Helpers/triggers/interface_20_modWorkflow_WorkflowManager.class.php 1 patch
Indentation   +211 added lines, -211 removed lines patch added patch discarded remove patch
@@ -32,39 +32,39 @@  discard block
 block discarded – undo
32 32
 
33 33
 class InterfaceWorkflowManager extends DolibarrTriggers
34 34
 {
35
-	/**
36
-	 * @var string Image of the trigger
37
-	 */
38
-	public $picto = 'technic';
35
+    /**
36
+     * @var string Image of the trigger
37
+     */
38
+    public $picto = 'technic';
39 39
 
40
-	public $family = 'core';
41
-	public $description = "Triggers of this module allows to manage workflows";
40
+    public $family = 'core';
41
+    public $description = "Triggers of this module allows to manage workflows";
42 42
 
43
-	/**
44
-	 * Version of the trigger
45
-	 * @var string
46
-	 */
47
-	public $version = self::VERSION_DOLIBARR;
43
+    /**
44
+     * Version of the trigger
45
+     * @var string
46
+     */
47
+    public $version = self::VERSION_DOLIBARR;
48 48
 
49
-	/**
50
-	 * Function called when a Dolibarrr business event is done.
51
-	 * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
52
-	 *
53
-	 * @param string		$action		Event action code
54
-	 * @param Object		$object     Object
55
-	 * @param User		    $user       Object user
56
-	 * @param Translate 	$langs      Object langs
57
-	 * @param conf		    $conf       Object conf
58
-	 * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
59
-	 */
60
-	public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
49
+    /**
50
+     * Function called when a Dolibarrr business event is done.
51
+     * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
52
+     *
53
+     * @param string		$action		Event action code
54
+     * @param Object		$object     Object
55
+     * @param User		    $user       Object user
56
+     * @param Translate 	$langs      Object langs
57
+     * @param conf		    $conf       Object conf
58
+     * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
59
+     */
60
+    public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
61 61
     {
62 62
         if (empty($conf->workflow->enabled)) return 0;     // Module not active, we do nothing
63 63
 
64 64
         // Proposals to order
65 65
         if ($action == 'PROPAL_CLOSE_SIGNED')
66 66
         {
67
-        	dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
67
+            dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
68 68
             if (! empty($conf->commande->enabled) && ! empty($conf->global->WORKFLOW_PROPAL_AUTOCREATE_ORDER))
69 69
             {
70 70
                 include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
@@ -102,132 +102,132 @@  discard block
 block discarded – undo
102 102
         // Order classify billed proposal
103 103
         if ($action == 'ORDER_CLASSIFY_BILLED')
104 104
         {
105
-        	dol_syslog( "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id );
106
-        	if (! empty($conf->propal->enabled) && ! empty($conf->workflow->enabled) && ! empty($conf->global->WORKFLOW_ORDER_CLASSIFY_BILLED_PROPAL))
107
-        	{
108
-        		$object->fetchObjectLinked('','propal',$object->id,$object->element);
109
-				if (! empty($object->linkedObjects))
110
-				{
111
-				    $totalonlinkedelements=0;
112
-					foreach($object->linkedObjects['propal'] as $element)
113
-					{
114
-					    if ($element->statut == Propal::STATUS_SIGNED || $element->statut == Propal::STATUS_BILLED) $totalonlinkedelements += $element->total_ht;
115
-					}
116
-					dol_syslog( "Amount of linked proposals = ".$totalonlinkedelements.", of order = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
117
-					if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
118
-					{
119
-    					foreach($object->linkedObjects['propal'] as $element)
120
-    					{
121
-    					    $ret=$element->classifyBilled($user);
122
-    					}
123
-					}
124
-				}
125
-        		return $ret;
126
-        	}
105
+            dol_syslog( "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id );
106
+            if (! empty($conf->propal->enabled) && ! empty($conf->workflow->enabled) && ! empty($conf->global->WORKFLOW_ORDER_CLASSIFY_BILLED_PROPAL))
107
+            {
108
+                $object->fetchObjectLinked('','propal',$object->id,$object->element);
109
+                if (! empty($object->linkedObjects))
110
+                {
111
+                    $totalonlinkedelements=0;
112
+                    foreach($object->linkedObjects['propal'] as $element)
113
+                    {
114
+                        if ($element->statut == Propal::STATUS_SIGNED || $element->statut == Propal::STATUS_BILLED) $totalonlinkedelements += $element->total_ht;
115
+                    }
116
+                    dol_syslog( "Amount of linked proposals = ".$totalonlinkedelements.", of order = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
117
+                    if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
118
+                    {
119
+                        foreach($object->linkedObjects['propal'] as $element)
120
+                        {
121
+                            $ret=$element->classifyBilled($user);
122
+                        }
123
+                    }
124
+                }
125
+                return $ret;
126
+            }
127 127
         }
128 128
 
129 129
         // classify billed order & billed propososal
130 130
         if ($action == 'BILL_VALIDATE')
131 131
         {
132
-        	dol_syslog( "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id );
132
+            dol_syslog( "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id );
133 133
 
134
-			// First classify billed the order to allow the proposal classify process
135
-			if (! empty($conf->commande->enabled) && ! empty($conf->workflow->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER))
136
-        	{
137
-        		$object->fetchObjectLinked('','commande',$object->id,$object->element);
138
-        		if (! empty($object->linkedObjects))
139
-        		{
140
-        		    $totalonlinkedelements=0;
141
-        		    foreach($object->linkedObjects['commande'] as $element)
142
-        		    {
143
-        		        if ($element->statut == Commande::STATUS_VALIDATED || $element->statut == Commande::STATUS_SHIPMENTONPROCESS || $element->statut == Commande::STATUS_CLOSED) $totalonlinkedelements += $element->total_ht;
144
-        		    }
145
-        		    dol_syslog( "Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
146
-        		    if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
147
-        		    {
148
-        		        foreach($object->linkedObjects['commande'] as $element)
149
-        		        {
150
-        		            $ret=$element->classifyBilled($user);
151
-        		        }
152
-        		    }
153
-        		}
154
-        		return $ret;
155
-        	}
134
+            // First classify billed the order to allow the proposal classify process
135
+            if (! empty($conf->commande->enabled) && ! empty($conf->workflow->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER))
136
+            {
137
+                $object->fetchObjectLinked('','commande',$object->id,$object->element);
138
+                if (! empty($object->linkedObjects))
139
+                {
140
+                    $totalonlinkedelements=0;
141
+                    foreach($object->linkedObjects['commande'] as $element)
142
+                    {
143
+                        if ($element->statut == Commande::STATUS_VALIDATED || $element->statut == Commande::STATUS_SHIPMENTONPROCESS || $element->statut == Commande::STATUS_CLOSED) $totalonlinkedelements += $element->total_ht;
144
+                    }
145
+                    dol_syslog( "Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
146
+                    if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
147
+                    {
148
+                        foreach($object->linkedObjects['commande'] as $element)
149
+                        {
150
+                            $ret=$element->classifyBilled($user);
151
+                        }
152
+                    }
153
+                }
154
+                return $ret;
155
+            }
156 156
 
157
-			// Second classify billed the proposal.
158
-        	if (! empty($conf->propal->enabled) && ! empty($conf->workflow->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_PROPAL))
159
-        	{
160
-        		$object->fetchObjectLinked('','propal',$object->id,$object->element);
161
-        		if (! empty($object->linkedObjects))
162
-        		{
163
-        		    $totalonlinkedelements=0;
164
-        		    foreach($object->linkedObjects['propal'] as $element)
165
-        		    {
166
-        		        if ($element->statut == Propal::STATUS_SIGNED || $element->statut == Propal::STATUS_BILLED) $totalonlinkedelements += $element->total_ht;
167
-        		    }
168
-        		    dol_syslog( "Amount of linked proposals = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
169
-        		    if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
170
-        		    {
171
-        		        foreach($object->linkedObjects['propal'] as $element)
172
-        		        {
173
-        		            $ret=$element->classifyBilled($user);
174
-        		        }
175
-        		    }
176
-        		}
177
-        		return $ret;
178
-        	}
157
+            // Second classify billed the proposal.
158
+            if (! empty($conf->propal->enabled) && ! empty($conf->workflow->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_PROPAL))
159
+            {
160
+                $object->fetchObjectLinked('','propal',$object->id,$object->element);
161
+                if (! empty($object->linkedObjects))
162
+                {
163
+                    $totalonlinkedelements=0;
164
+                    foreach($object->linkedObjects['propal'] as $element)
165
+                    {
166
+                        if ($element->statut == Propal::STATUS_SIGNED || $element->statut == Propal::STATUS_BILLED) $totalonlinkedelements += $element->total_ht;
167
+                    }
168
+                    dol_syslog( "Amount of linked proposals = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
169
+                    if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
170
+                    {
171
+                        foreach($object->linkedObjects['propal'] as $element)
172
+                        {
173
+                            $ret=$element->classifyBilled($user);
174
+                        }
175
+                    }
176
+                }
177
+                return $ret;
178
+            }
179 179
         }
180 180
 
181 181
         // classify billed order & billed propososal
182 182
         if ($action == 'BILL_SUPPLIER_VALIDATE')
183 183
         {
184
-        	dol_syslog( "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id );
184
+            dol_syslog( "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id );
185 185
 
186
-        	// First classify billed the order to allow the proposal classify process
187
-        	if (! empty($conf->fournisseur->commande->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER))
188
-        	{
189
-        		$object->fetchObjectLinked('','order_supplier',$object->id,$object->element);
190
-        		if (! empty($object->linkedObjects))
191
-        		{
192
-        			$totalonlinkedelements=0;
193
-        			foreach($object->linkedObjects['order_supplier'] as $element)
194
-        			{
195
-        				if ($element->statut == CommandeFournisseur::STATUS_ACCEPTED || $element->statut == CommandeFournisseur::STATUS_ORDERSENT || $element->statut == CommandeFournisseur::STATUS_RECEIVED_PARTIALLY || $element->statut == CommandeFournisseur::STATUS_RECEIVED_COMPLETELY) $totalonlinkedelements += $element->total_ht;
196
-        			}
197
-        			dol_syslog( "Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
198
-        			if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
199
-        			{
200
-        				foreach($object->linkedObjects['order_supplier'] as $element)
201
-        				{
202
-        					$ret=$element->classifyBilled($user);
203
-        				}
204
-        			}
205
-        		}
206
-        		return $ret;
207
-        	}
186
+            // First classify billed the order to allow the proposal classify process
187
+            if (! empty($conf->fournisseur->commande->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER))
188
+            {
189
+                $object->fetchObjectLinked('','order_supplier',$object->id,$object->element);
190
+                if (! empty($object->linkedObjects))
191
+                {
192
+                    $totalonlinkedelements=0;
193
+                    foreach($object->linkedObjects['order_supplier'] as $element)
194
+                    {
195
+                        if ($element->statut == CommandeFournisseur::STATUS_ACCEPTED || $element->statut == CommandeFournisseur::STATUS_ORDERSENT || $element->statut == CommandeFournisseur::STATUS_RECEIVED_PARTIALLY || $element->statut == CommandeFournisseur::STATUS_RECEIVED_COMPLETELY) $totalonlinkedelements += $element->total_ht;
196
+                    }
197
+                    dol_syslog( "Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
198
+                    if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
199
+                    {
200
+                        foreach($object->linkedObjects['order_supplier'] as $element)
201
+                        {
202
+                            $ret=$element->classifyBilled($user);
203
+                        }
204
+                    }
205
+                }
206
+                return $ret;
207
+            }
208 208
 
209
-        	// Second classify billed the proposal.
210
-        	if (! empty($conf->supplier_proposal->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_SUPPLIER_PROPOSAL))
211
-        	{
212
-        		$object->fetchObjectLinked('','supplier_proposal',$object->id,$object->element);
213
-        		if (! empty($object->linkedObjects))
214
-        		{
215
-        			$totalonlinkedelements=0;
216
-        			foreach($object->linkedObjects['supplier_proposal'] as $element)
217
-        			{
218
-        				if ($element->statut == SupplierProposal::STATUS_SIGNED || $element->statut == SupplierProposal::STATUS_BILLED) $totalonlinkedelements += $element->total_ht;
219
-        			}
220
-        			dol_syslog( "Amount of linked supplier proposals = ".$totalonlinkedelements.", of supplier invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
221
-        			if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
222
-        			{
223
-        				foreach($object->linkedObjects['supplier_proposal'] as $element)
224
-        				{
225
-        					$ret=$element->classifyBilled($user);
226
-        				}
227
-        			}
228
-        		}
229
-        		return $ret;
230
-        	}
209
+            // Second classify billed the proposal.
210
+            if (! empty($conf->supplier_proposal->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_SUPPLIER_PROPOSAL))
211
+            {
212
+                $object->fetchObjectLinked('','supplier_proposal',$object->id,$object->element);
213
+                if (! empty($object->linkedObjects))
214
+                {
215
+                    $totalonlinkedelements=0;
216
+                    foreach($object->linkedObjects['supplier_proposal'] as $element)
217
+                    {
218
+                        if ($element->statut == SupplierProposal::STATUS_SIGNED || $element->statut == SupplierProposal::STATUS_BILLED) $totalonlinkedelements += $element->total_ht;
219
+                    }
220
+                    dol_syslog( "Amount of linked supplier proposals = ".$totalonlinkedelements.", of supplier invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht) );
221
+                    if ( ($totalonlinkedelements == $object->total_ht) || (! empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) )
222
+                    {
223
+                        foreach($object->linkedObjects['supplier_proposal'] as $element)
224
+                        {
225
+                            $ret=$element->classifyBilled($user);
226
+                        }
227
+                    }
228
+                }
229
+                return $ret;
230
+            }
231 231
         }
232 232
 
233 233
         // Invoice classify billed order
@@ -260,88 +260,88 @@  discard block
 block discarded – undo
260 260
 
261 261
         if ($action=='SHIPPING_VALIDATE')
262 262
         {
263
-        	dol_syslog( "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id );
263
+            dol_syslog( "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id );
264 264
 
265
-        	if (! empty($conf->commande->enabled) && ! empty($conf->expedition->enabled) && ! empty($conf->workflow->enabled) && ! empty($conf->global->WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING))
266
-        	{
267
-        		$qtyshipped=array();
268
-        		$qtyordred=array();
269
-        		require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
265
+            if (! empty($conf->commande->enabled) && ! empty($conf->expedition->enabled) && ! empty($conf->workflow->enabled) && ! empty($conf->global->WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING))
266
+            {
267
+                $qtyshipped=array();
268
+                $qtyordred=array();
269
+                require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
270 270
 
271
-        		//find all shippement on order origin
272
-        		$order = new Commande($this->db);
273
-        		$ret=$order->fetch($object->origin_id);
274
-        		if ($ret<0) {
275
-        			$this->error=$order->error; $this->errors=$order->errors;
276
-        			return $ret;
277
-        		}
278
-        		$ret=$order->fetchObjectLinked($order->id,'commande',null,'shipping');
279
-        		if ($ret<0) {
280
-        			$this->error=$order->error; $this->errors=$order->errors;
281
-        			return $ret;
282
-        		}
283
-        		//Build array of quantity shipped by product for an order
284
-        		if (is_array($order->linkedObjects) && count($order->linkedObjects)>0) {
285
-        			foreach($order->linkedObjects as $type=>$shipping_array) {
286
-        				if ($type=='shipping' && is_array($shipping_array) && count($shipping_array)>0) {
287
-        					foreach ($shipping_array as $shipping) {
288
-		        				if (is_array($shipping->lines) && count($shipping->lines)>0) {
289
-		        					foreach($shipping->lines as $shippingline) {
290
-		        						$qtyshipped[$shippingline->fk_product]+=$shippingline->qty;
291
-		        					}
292
-		        				}
293
-	        				}
294
-        				}
295
-        			}
296
-        		}
271
+                //find all shippement on order origin
272
+                $order = new Commande($this->db);
273
+                $ret=$order->fetch($object->origin_id);
274
+                if ($ret<0) {
275
+                    $this->error=$order->error; $this->errors=$order->errors;
276
+                    return $ret;
277
+                }
278
+                $ret=$order->fetchObjectLinked($order->id,'commande',null,'shipping');
279
+                if ($ret<0) {
280
+                    $this->error=$order->error; $this->errors=$order->errors;
281
+                    return $ret;
282
+                }
283
+                //Build array of quantity shipped by product for an order
284
+                if (is_array($order->linkedObjects) && count($order->linkedObjects)>0) {
285
+                    foreach($order->linkedObjects as $type=>$shipping_array) {
286
+                        if ($type=='shipping' && is_array($shipping_array) && count($shipping_array)>0) {
287
+                            foreach ($shipping_array as $shipping) {
288
+                                if (is_array($shipping->lines) && count($shipping->lines)>0) {
289
+                                    foreach($shipping->lines as $shippingline) {
290
+                                        $qtyshipped[$shippingline->fk_product]+=$shippingline->qty;
291
+                                    }
292
+                                }
293
+                            }
294
+                        }
295
+                    }
296
+                }
297 297
 
298
-        		//Build array of quantity ordered by product
299
-        		if (is_array($order->lines) && count($order->lines)>0) {
300
-        			foreach($order->lines as $orderline) {
301
-        				$qtyordred[$orderline->fk_product]+=$orderline->qty;
302
-        			}
303
-        		}
304
-        		//dol_syslog(var_export($qtyordred,true),LOG_DEBUG);
305
-        		//dol_syslog(var_export($qtyshipped,true),LOG_DEBUG);
306
-        		//Compare array
307
-        		$diff_array=array_diff_assoc($qtyordred,$qtyshipped);
308
-        		if (count($diff_array)==0) {
309
-        			//No diff => mean everythings is shipped
310
-        			$ret=$object->setStatut(Commande::STATUS_CLOSED, $object->origin_id, $object->origin);
311
-        			if ($ret<0) {
312
-        				$this->error=$object->error; $this->errors=$object->errors;
313
-        				return $ret;
314
-        			}
315
-        		}
316
-        	}
298
+                //Build array of quantity ordered by product
299
+                if (is_array($order->lines) && count($order->lines)>0) {
300
+                    foreach($order->lines as $orderline) {
301
+                        $qtyordred[$orderline->fk_product]+=$orderline->qty;
302
+                    }
303
+                }
304
+                //dol_syslog(var_export($qtyordred,true),LOG_DEBUG);
305
+                //dol_syslog(var_export($qtyshipped,true),LOG_DEBUG);
306
+                //Compare array
307
+                $diff_array=array_diff_assoc($qtyordred,$qtyshipped);
308
+                if (count($diff_array)==0) {
309
+                    //No diff => mean everythings is shipped
310
+                    $ret=$object->setStatut(Commande::STATUS_CLOSED, $object->origin_id, $object->origin);
311
+                    if ($ret<0) {
312
+                        $this->error=$object->error; $this->errors=$object->errors;
313
+                        return $ret;
314
+                    }
315
+                }
316
+            }
317 317
         }
318
-		 // classify billed reception
318
+            // classify billed reception
319 319
         if ($action == 'BILL_SUPPLIER_VALIDATE')
320 320
         {
321
-        	dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id, LOG_DEBUG);
321
+            dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id, LOG_DEBUG);
322 322
 
323
-        	if (! empty($conf->reception->enabled) && ! empty($conf->global->WORKFLOW_BILL_ON_RECEPTION))
324
-        	{
325
-        		$object->fetchObjectLinked('','reception',$object->id,$object->element);
326
-        		if (! empty($object->linkedObjects))
327
-        		{
328
-        		    $totalonlinkedelements=0;
329
-        		    foreach($object->linkedObjects['reception'] as $element)
330
-        		    {
331
-        		        if ($element->statut == Reception::STATUS_VALIDATED) $totalonlinkedelements += $element->total_ht;
332
-        		    }
333
-        		    dol_syslog("Amount of linked proposals = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht), LOG_DEBUG);
334
-        		    if ($totalonlinkedelements == $object->total_ht)
335
-        		    {
336
-        		        foreach($object->linkedObjects['reception'] as $element)
337
-        		        {
338
-        		            $ret=$element->set_billed();
339
-        		        }
340
-        		    }
341
-        		}
342
-        		return $ret;
343
-        	}
344
-		}
323
+            if (! empty($conf->reception->enabled) && ! empty($conf->global->WORKFLOW_BILL_ON_RECEPTION))
324
+            {
325
+                $object->fetchObjectLinked('','reception',$object->id,$object->element);
326
+                if (! empty($object->linkedObjects))
327
+                {
328
+                    $totalonlinkedelements=0;
329
+                    foreach($object->linkedObjects['reception'] as $element)
330
+                    {
331
+                        if ($element->statut == Reception::STATUS_VALIDATED) $totalonlinkedelements += $element->total_ht;
332
+                    }
333
+                    dol_syslog("Amount of linked proposals = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht), LOG_DEBUG);
334
+                    if ($totalonlinkedelements == $object->total_ht)
335
+                    {
336
+                        foreach($object->linkedObjects['reception'] as $element)
337
+                        {
338
+                            $ret=$element->set_billed();
339
+                        }
340
+                    }
341
+                }
342
+                return $ret;
343
+            }
344
+        }
345 345
 
346 346
         return 0;
347 347
     }
Please login to merge, or discard this patch.
Base/CommonObject.php 1 patch
Indentation   +7086 added lines, -7086 removed lines patch added patch discarded remove patch
@@ -20,7382 +20,7382 @@
 block discarded – undo
20 20
 
21 21
 abstract class CommonObject
22 22
 {
23
-	/**
23
+    /**
24 24
      * @var int The object identifier
25 25
      */
26
-	public $id;
27
-
28
-	/**
29
-	 * @var string 		Error string
30
-	 * @see             errors
31
-	 */
32
-	public $error;
33
-
34
-	/**
35
-	 * @var string[]	Array of error strings
36
-	 */
37
-	public $errors=array();
38
-
39
-	/**
40
-	 * @var string ID to identify managed object
41
-	 */
42
-	public $element;
43
-
44
-	/**
45
-	 * @var string Name of table without prefix where object is stored
46
-	 */
47
-	public $table_element;
48
-
49
-	/**
50
-	 * @var int    Name of subtable line
51
-	 */
52
-	public $table_element_line='';
53
-
54
-	/**
55
-	 * @var string		Key value used to track if data is coming from import wizard
56
-	 */
57
-	public $import_key;
58
-
59
-	/**
60
-	 * @var mixed		Contains data to manage extrafields
61
-	 */
62
-	public $array_options=array();
63
-
64
-	/**
65
-	 * @var int[][]		Array of linked objects ids. Loaded by ->fetchObjectLinked
66
-	 */
67
-	public $linkedObjectsIds;
68
-
69
-	/**
70
-	 * @var mixed		Array of linked objects. Loaded by ->fetchObjectLinked
71
-	 */
72
-	public $linkedObjects;
73
-
74
-	/**
75
-	 * @var Object      To store a cloned copy of object before to edit it and keep track of old properties
76
-	 */
77
-	public $oldcopy;
78
-
79
-	/**
80
-	 * @var string		Column name of the ref field.
81
-	 */
82
-	protected $table_ref_field = '';
83
-
84
-
85
-
86
-	// Following vars are used by some objects only. We keep this property here in CommonObject to be able to provide common method using them.
87
-
88
-	/**
89
-	 * @var array<string,mixed>		Can be used to pass information when only object is provided to method
90
-	 */
91
-	public $context=array();
92
-
93
-	/**
94
-	 * @var string		Contains canvas name if record is an alternative canvas record
95
-	 */
96
-	public $canvas;
97
-
98
-	/**
99
-	 * @var Project The related project
100
-	 * @see fetch_projet()
101
-	 */
102
-	public $project;
103
-
104
-	/**
105
-	 * @var int The related project ID
106
-	 * @see setProject(), project
107
-	 */
108
-	public $fk_project;
109
-
110
-	/**
111
-	 * @deprecated
112
-	 * @see project
113
-	 */
114
-	public $projet;
115
-
116
-	/**
117
-	 * @var Contact a related contact
118
-	 * @see fetch_contact()
119
-	 */
120
-	public $contact;
121
-
122
-	/**
123
-	 * @var int The related contact ID
124
-	 * @see fetch_contact()
125
-	 */
126
-	public $contact_id;
127
-
128
-	/**
129
-	 * @var Societe A related thirdparty
130
-	 * @see fetch_thirdparty()
131
-	 */
132
-	public $thirdparty;
133
-
134
-	/**
135
-	 * @var User A related user
136
-	 * @see fetch_user()
137
-	 */
138
-	public $user;
139
-
140
-	/**
141
-	 * @var string 	The type of originating object ('commande', 'facture', ...)
142
-	 * @see fetch_origin()
143
-	 */
144
-	public $origin;
145
-
146
-	/**
147
-	 * @var int 	The id of originating object
148
-	 * @see fetch_origin()
149
-	 */
150
-	public $origin_id;
151
-
152
-	/**
153
-	 * @var string The object's reference
154
-	 */
155
-	public $ref;
156
-
157
-	/**
158
-	 * @var string The object's previous reference
159
-	 */
160
-	public $ref_previous;
161
-
162
-	/**
163
-	 * @var string The object's next reference
164
-	 */
165
-	public $ref_next;
166
-
167
-	/**
168
-	 * @var string An external reference for the object
169
-	 */
170
-	public $ref_ext;
171
-
172
-	/**
173
-	 * @var int The object's status
174
-	 * @see setStatut()
175
-	 */
176
-	public $statut;
177
-
178
-	/**
179
-	 * @var string
180
-	 * @see getFullAddress()
181
-	 */
182
-	public $country;
183
-
184
-	/**
185
-	 * @var int
186
-	 * @see getFullAddress(), country
187
-	 */
188
-	public $country_id;
189
-
190
-	/**
191
-	 * @var string
192
-	 * @see getFullAddress(), isInEEC(), country
193
-	 */
194
-    public $country_code;
26
+    public $id;
195 27
 
196 28
     /**
197
-	 * @var string
198
-	 * @see getFullAddress()
199
-	 */
200
-	public $state;
201
-
202
-	/**
203
-	 * @var int
204
-	 * @see getFullAddress(), state
205
-	 */
206
-	public $state_id;
29
+     * @var string 		Error string
30
+     * @see             errors
31
+     */
32
+    public $error;
207 33
 
208
-	/**
209
-	 * @var string
210
-	 * @see getFullAddress(), state
211
-	 */
212
-    public $state_code;
34
+    /**
35
+     * @var string[]	Array of error strings
36
+     */
37
+    public $errors=array();
213 38
 
214 39
     /**
215
-	 * @var string
216
-	 * @see getFullAddress(), region
217
-	 */
218
-	public $region;
40
+     * @var string ID to identify managed object
41
+     */
42
+    public $element;
219 43
 
220
-	/**
221
-	 * @var string
222
-	 * @see getFullAddress(), region
223
-	 */
224
-    public $region_code;
44
+    /**
45
+     * @var string Name of table without prefix where object is stored
46
+     */
47
+    public $table_element;
225 48
 
226
-	/**
227
-	 * @var int
228
-	 * @see fetch_barcode()
229
-	 */
230
-	public $barcode_type;
231
-
232
-	/**
233
-	 * @var string
234
-	 * @see fetch_barcode(), barcode_type
235
-	 */
236
-	public $barcode_type_code;
237
-
238
-	/**
239
-	 * @var string
240
-	 * @see fetch_barcode(), barcode_type
241
-	 */
242
-	public $barcode_type_label;
243
-
244
-	/**
245
-	 * @var string
246
-	 * @see fetch_barcode(), barcode_type
247
-	 */
248
-	public $barcode_type_coder;
249
-
250
-	/**
251
-	 * @var int Payment method ID (cheque, cash, ...)
252
-	 * @see setPaymentMethods()
253
-	 */
254
-	public $mode_reglement_id;
255
-
256
-	/**
257
-	 * @var int Payment terms ID
258
-	 * @see setPaymentTerms()
259
-	 */
260
-	public $cond_reglement_id;
261
-
262
-	/**
263
-	 * @var int Payment terms ID
264
-	 * @deprecated Kept for compatibility
265
-	 * @see cond_reglement_id;
266
-	 */
267
-	public $cond_reglement;
268
-
269
-	/**
270
-	 * @var int Delivery address ID
271
-	 * @deprecated
272
-	 * @see setDeliveryAddress()
273
-	 */
274
-	public $fk_delivery_address;
275
-
276
-	/**
277
-	 * @var int Shipping method ID
278
-	 * @see setShippingMethod()
279
-	 */
280
-	public $shipping_method_id;
281
-
282
-	/**
283
-	 * @var string
284
-	 * @see SetDocModel()
285
-	 */
286
-	public $modelpdf;
287
-
288
-	/**
289
-	 * @var int Bank account ID
290
-	 * @see SetBankAccount()
291
-	 */
292
-	public $fk_account;
293
-
294
-	/**
295
-	 * @var string Public note
296
-	 * @see update_note()
297
-	 */
298
-	public $note_public;
299
-
300
-	/**
301
-	 * @var string Private note
302
-	 * @see update_note()
303
-	 */
304
-	public $note_private;
305
-
306
-	/**
307
-	 * @deprecated
308
-	 * @see note_public
309
-	 */
310
-	public $note;
311
-
312
-	/**
313
-	 * @var float Total amount before taxes
314
-	 * @see update_price()
315
-	 */
316
-	public $total_ht;
317
-
318
-	/**
319
-	 * @var float Total VAT amount
320
-	 * @see update_price()
321
-	 */
322
-	public $total_tva;
323
-
324
-	/**
325
-	 * @var float Total local tax 1 amount
326
-	 * @see update_price()
327
-	 */
328
-	public $total_localtax1;
329
-
330
-	/**
331
-	 * @var float Total local tax 2 amount
332
-	 * @see update_price()
333
-	 */
334
-	public $total_localtax2;
335
-
336
-	/**
337
-	 * @var float Total amount with taxes
338
-	 * @see update_price()
339
-	 */
340
-	public $total_ttc;
341
-
342
-	/**
343
-	 * @var CommonObjectLine[]
344
-	 */
345
-	public $lines;
346
-
347
-	/**
348
-	 * @var mixed		Contains comments
349
-	 * @see fetchComments()
350
-	 */
351
-	public $comments=array();
352
-
353
-	/**
354
-	 * @var int
355
-	 * @see setIncoterms()
356
-	 */
357
-	public $fk_incoterms;
358
-
359
-	/**
360
-	 * @var string
361
-	 * @see SetIncoterms()
362
-	 */
363
-	public $libelle_incoterms;
364
-
365
-	/**
366
-	 * @var string
367
-	 * @see display_incoterms()
368
-	 */
369
-	public $location_incoterms;
370
-
371
-	public $name;
372
-	public $lastname;
373
-	public $firstname;
374
-	public $civility_id;
375
-
376
-	// Dates
377
-	public $date_creation;			// Date creation
378
-	public $date_validation;		// Date validation
379
-	public $date_modification;		// Date last change (tms field)
380
-
381
-
382
-
383
-	// No constructor as it is an abstract class
384
-
385
-	/**
386
-	 * Check an object id/ref exists
387
-	 * If you don't need/want to instantiate object and just need to know if object exists, use this method instead of fetch
388
-	 *
389
-	 *  @param	string	$element   	String of element ('product', 'facture', ...)
390
-	 *  @param	int		$id      	Id of object
391
-	 *  @param  string	$ref     	Ref of object to check
392
-	 *  @param	string	$ref_ext	Ref ext of object to check
393
-	 *  @return int     			<0 if KO, 0 if OK but not found, >0 if OK and exists
394
-	 */
395
-	static function isExistingObject($element, $id, $ref='', $ref_ext='')
396
-	{
397
-		global $db,$conf;
398
-
399
-		$sql = "SELECT rowid, ref, ref_ext";
400
-		$sql.= " FROM ".MAIN_DB_PREFIX.$element;
401
-		$sql.= " WHERE entity IN (".getEntity($element).")" ;
402
-
403
-		if ($id > 0) $sql.= " AND rowid = ".$db->escape($id);
404
-		else if ($ref) $sql.= " AND ref = '".$db->escape($ref)."'";
405
-		else if ($ref_ext) $sql.= " AND ref_ext = '".$db->escape($ref_ext)."'";
406
-		else {
407
-			$error='ErrorWrongParameters';
408
-			dol_print_error(get_class()."::isExistingObject ".$error, LOG_ERR);
409
-			return -1;
410
-		}
411
-		if ($ref || $ref_ext) $sql.= " AND entity = ".$conf->entity;
412
-
413
-		dol_syslog(get_class()."::isExistingObject", LOG_DEBUG);
414
-		$resql = $db->query($sql);
415
-		if ($resql)
416
-		{
417
-			$num=$db->num_rows($resql);
418
-			if ($num > 0) return 1;
419
-			else return 0;
420
-		}
421
-		return -1;
422
-	}
423
-
424
-	/**
425
-	 * Method to output saved errors
426
-	 *
427
-	 * @return	string		String with errors
428
-	 */
429
-	function errorsToString()
430
-	{
431
-		return $this->error.(is_array($this->errors)?(($this->error!=''?', ':'').join(', ',$this->errors)):'');
432
-	}
433
-
434
-	/**
435
-	 *	Return full name (civility+' '+name+' '+lastname)
436
-	 *
437
-	 *	@param	Translate	$langs			Language object for translation of civility (used only if option is 1)
438
-	 *	@param	int			$option			0=No option, 1=Add civility
439
-	 * 	@param	int			$nameorder		-1=Auto, 0=Lastname+Firstname, 1=Firstname+Lastname, 2=Firstname
440
-	 * 	@param	int			$maxlen			Maximum length
441
-	 * 	@return	string						String with full name
442
-	 */
443
-	function getFullName($langs,$option=0,$nameorder=-1,$maxlen=0)
444
-	{
445
-		//print "lastname=".$this->lastname." name=".$this->name." nom=".$this->nom."<br>\n";
446
-		$lastname=$this->lastname;
447
-		$firstname=$this->firstname;
448
-		if (empty($lastname))  $lastname=(isset($this->lastname)?$this->lastname:(isset($this->name)?$this->name:(isset($this->nom)?$this->nom:(isset($this->societe)?$this->societe:(isset($this->company)?$this->company:'')))));
449
-
450
-		$ret='';
451
-		if ($option && $this->civility_id)
452
-		{
453
-			if ($langs->transnoentitiesnoconv("Civility".$this->civility_id)!="Civility".$this->civility_id) $ret.=$langs->transnoentitiesnoconv("Civility".$this->civility_id).' ';
454
-			else $ret.=$this->civility_id.' ';
455
-		}
456
-
457
-		$ret.=dolGetFirstLastname($firstname, $lastname, $nameorder);
458
-
459
-		return dol_trunc($ret,$maxlen);
460
-	}
461
-
462
-	/**
463
-	 * 	Return full address of contact
464
-	 *
465
-	 * 	@param		int			$withcountry		1=Add country into address string
466
-	 *  @param		string		$sep				Separator to use to build string
467
-	 *  @param		int		    $withregion			1=Add region into address string
468
-	 *	@return		string							Full address string
469
-	 */
470
-	function getFullAddress($withcountry=0, $sep="\n", $withregion=0)
471
-	{
472
-		if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country)))
473
-		{
474
-			require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
475
-			$tmparray=getCountry($this->country_id,'all');
476
-			$this->country_code=$tmparray['code'];
477
-			$this->country     =$tmparray['label'];
478
-		}
49
+    /**
50
+     * @var int    Name of subtable line
51
+     */
52
+    public $table_element_line='';
479 53
 
480
-        if ($withregion && $this->state_id && (empty($this->state_code) || empty($this->state) || empty($this->region) || empty($this->region_cpde)))
481
-    	{
482
-    		require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
483
-    		$tmparray=getState($this->state_id,'all',0,1);
484
-			$this->state_code   =$tmparray['code'];
485
-			$this->state        =$tmparray['label'];
486
-			$this->region_code  =$tmparray['region_code'];
487
-			$this->region       =$tmparray['region'];
488
-        }
489
-
490
-		return dol_format_address($this, $withcountry, $sep);
491
-	}
492
-
493
-
494
-	/**
495
-	 * 	Return full address for banner
496
-	 *
497
-	 * 	@param		string		$htmlkey            HTML id to make banner content unique
498
-	 *  @param      Object      $object				Object (thirdparty, thirdparty of contact for contact, null for a member)
499
-	 *	@return		string							Full address string
500
-	 */
501
-	function getBannerAddress($htmlkey, $object)
502
-	{
503
-		global $conf, $langs;
504
-
505
-		$countriesusingstate=array('AU','US','IN','GB','ES','UK','TR');    // See also option MAIN_FORCE_STATE_INTO_ADDRESS
506
-
507
-		$contactid=0;
508
-		$thirdpartyid=0;
509
-		if ($this->element == 'societe')
510
-		{
511
-			$thirdpartyid=$this->id;
512
-		}
513
-		if ($this->element == 'contact')
514
-		{
515
-			$contactid=$this->id;
516
-			$thirdpartyid=$object->fk_soc;
517
-		}
518
-		if ($this->element == 'user')
519
-		{
520
-			$contactid=$this->contact_id;
521
-			$thirdpartyid=$object->fk_soc;
522
-		}
523
-
524
-		$out='<!-- BEGIN part to show address block -->';
525
-
526
-		$outdone=0;
527
-		$coords = $this->getFullAddress(1,', ',$conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT);
528
-		if ($coords)
529
-		{
530
-			if (! empty($conf->use_javascript_ajax))
531
-			{
532
-				$namecoords = $this->getFullName($langs,1).'<br>'.$coords;
533
-				// hideonsmatphone because copyToClipboard call jquery dialog that does not work with jmobile
534
-				$out.='<a href="#" class="hideonsmartphone" onclick="return copyToClipboard(\''.dol_escape_js($namecoords).'\',\''.dol_escape_js($langs->trans("HelpCopyToClipboard")).'\');">';
535
-				$out.=img_picto($langs->trans("Address"), 'object_address.png');
536
-				$out.='</a> ';
537
-			}
538
-			$out.=dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', '); $outdone++;
539
-			$outdone++;
540
-		}
541
-
542
-		if (! in_array($this->country_code,$countriesusingstate) && empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS)   // If MAIN_FORCE_STATE_INTO_ADDRESS is on, state is already returned previously with getFullAddress
543
-				&& empty($conf->global->SOCIETE_DISABLE_STATE) && $this->state)
544
-		{
545
-            if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 && $this->region) {
546
-                $out.=($outdone?' - ':'').$this->region.' - '.$this->state;
547
-            }
548
-            else {
549
-                $out.=($outdone?' - ':'').$this->state;
550
-            }
551
-			$outdone++;
552
-		}
553
-
554
-		if (! empty($this->phone) || ! empty($this->phone_pro) || ! empty($this->phone_mobile) || ! empty($this->phone_perso) || ! empty($this->fax) || ! empty($this->office_phone) || ! empty($this->user_mobile) || ! empty($this->office_fax)) $out.=($outdone?'<br>':'');
555
-		if (! empty($this->phone) && empty($this->phone_pro)) {		// For objects that store pro phone into ->phone
556
-			$out.=dol_print_phone($this->phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
557
-		}
558
-		if (! empty($this->phone_pro)) {
559
-			$out.=dol_print_phone($this->phone_pro,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
560
-		}
561
-		if (! empty($this->phone_mobile)) {
562
-			$out.=dol_print_phone($this->phone_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
563
-		}
564
-		if (! empty($this->phone_perso)) {
565
-			$out.=dol_print_phone($this->phone_perso,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePerso")); $outdone++;
566
-		}
567
-		if (! empty($this->office_phone)) {
568
-			$out.=dol_print_phone($this->office_phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
569
-		}
570
-		if (! empty($this->user_mobile)) {
571
-			$out.=dol_print_phone($this->user_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
572
-		}
573
-		if (! empty($this->fax)) {
574
-			$out.=dol_print_phone($this->fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
575
-		}
576
-		if (! empty($this->office_fax)) {
577
-			$out.=dol_print_phone($this->office_fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
578
-		}
579
-
580
-		$out.='<div style="clear: both;"></div>';
581
-		$outdone=0;
582
-		if (! empty($this->email))
583
-		{
584
-			$out.=dol_print_email($this->email,$this->id,$object->id,'AC_EMAIL',0,0,1);
585
-			$outdone++;
586
-		}
587
-		if (! empty($this->url))
588
-		{
589
-			$out.=dol_print_url($this->url,'_goout',0,1);
590
-			$outdone++;
591
-		}
592
-		$out.='<div style="clear: both;">';
593
-		if (! empty($conf->socialnetworks->enabled))
594
-		{
595
-			if ($this->skype) $out.=dol_print_socialnetworks($this->skype,$this->id,$object->id,'skype');
596
-			$outdone++;
597
-			if ($this->jabberid) $out.=dol_print_socialnetworks($this->jabberid,$this->id,$object->id,'jabber');
598
-			$outdone++;
599
-			if ($this->twitter) $out.=dol_print_socialnetworks($this->twitter,$this->id,$object->id,'twitter');
600
-			$outdone++;
601
-			if ($this->facebook) $out.=dol_print_socialnetworks($this->facebook,$this->id,$object->id,'facebook');
602
-			$outdone++;
603
-		}
604
-		$out.='</div>';
605
-
606
-		$out.='<!-- END Part to show address block -->';
607
-
608
-		return $out;
609
-	}
610
-
611
-	/**
612
-	 * Return the link of last main doc file for direct public download.
613
-	 *
614
-	 * @param	string	$modulepart			Module related to document
615
-	 * @param	int		$initsharekey		Init the share key if it was not yet defined
616
-	 * @param	int		$relativelink		0=Return full external link, 1=Return link relative to root of file
617
-	 * @return	string						Link or empty string if there is no download link
618
-	 */
619
-	function getLastMainDocLink($modulepart, $initsharekey=0, $relativelink=0)
620
-	{
621
-		global $user, $dolibarr_main_url_root;
622
-
623
-		if (empty($this->last_main_doc))
624
-		{
625
-			return '';		// No way to known which document name to use
626
-		}
627
-
628
-		include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
629
-		$ecmfile=new EcmFiles($this->db);
630
-		$result = $ecmfile->fetch(0, '', $this->last_main_doc);
631
-		if ($result < 0)
632
-		{
633
-			$this->error = $ecmfile->error;
634
-			$this->errors = $ecmfile->errors;
635
-			return -1;
636
-		}
637
-
638
-		if (empty($ecmfile->id))
639
-		{
640
-			// Add entry into index
641
-			if ($initsharekey)
642
-			{
643
-				require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
644
-				// TODO We can't, we dont' have full path of file, only last_main_doc adn ->element, so we must rebuild full path first
645
-				/*
646
-				$ecmfile->filepath = $rel_dir;
647
-				$ecmfile->filename = $filename;
648
-				$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
649
-				$ecmfile->fullpath_orig = '';
650
-				$ecmfile->gen_or_uploaded = 'generated';
651
-				$ecmfile->description = '';    // indexed content
652
-				$ecmfile->keyword = '';        // keyword content
653
-				$ecmfile->share = getRandomPassword(true);
654
-				$result = $ecmfile->create($user);
655
-				if ($result < 0)
656
-				{
657
-					$this->error = $ecmfile->error;
658
-					$this->errors = $ecmfile->errors;
659
-				}
660
-				*/
661
-			}
662
-			else return '';
663
-		}
664
-		elseif (empty($ecmfile->share))
665
-		{
666
-			// Add entry into index
667
-			if ($initsharekey)
668
-			{
669
-				require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
670
-				$ecmfile->share = getRandomPassword(true);
671
-				$ecmfile->update($user);
672
-			}
673
-			else return '';
674
-		}
675
-
676
-		// Define $urlwithroot
677
-		$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
678
-		$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain name found into config file
679
-		//$urlwithroot=DOL_MAIN_URL_ROOT;					// This is to use same domain name than current
680
-
681
-		$forcedownload=0;
682
-
683
-		$paramlink='';
684
-		//if (! empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart;		// For sharing with hash (so public files), modulepart is not required.
685
-		//if (! empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; 					// For sharing with hash (so public files), entity is not required.
686
-		//$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath);								// No need of name of file for public link, we will use the hash
687
-		if (! empty($ecmfile->share)) $paramlink.=($paramlink?'&':'').'hashp='.$ecmfile->share;			// Hash for public share
688
-		if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1';
689
-
690
-		if ($relativelink)
691
-		{
692
-			$linktoreturn='document.php'.($paramlink?'?'.$paramlink:'');
693
-		}
694
-		else
695
-		{
696
-			$linktoreturn=$urlwithroot.'/document.php'.($paramlink?'?'.$paramlink:'');
697
-		}
698
-
699
-		// Here $ecmfile->share is defined
700
-		return $linktoreturn;
701
-	}
54
+    /**
55
+     * @var string		Key value used to track if data is coming from import wizard
56
+     */
57
+    public $import_key;
702 58
 
59
+    /**
60
+     * @var mixed		Contains data to manage extrafields
61
+     */
62
+    public $array_options=array();
703 63
 
704
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
705
-	/**
706
-	 *  Add a link between element $this->element and a contact
707
-	 *
708
-	 *  @param	int		$fk_socpeople       Id of thirdparty contact (if source = 'external') or id of user (if souce = 'internal') to link
709
-	 *  @param 	int		$type_contact 		Type of contact (code or id). Must be id or code found into table llx_c_type_contact. For example: SALESREPFOLL
710
-	 *  @param  string	$source             external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
711
-	 *  @param  int		$notrigger			Disable all triggers
712
-	 *  @return int                 		<0 if KO, >0 if OK
713
-	 */
714
-	function add_contact($fk_socpeople, $type_contact, $source='external',$notrigger=0)
715
-	{
716
-        // phpcs:enable
717
-		global $user,$langs;
718
-
719
-
720
-		dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger");
721
-
722
-		// Check parameters
723
-		if ($fk_socpeople <= 0)
724
-		{
725
-			$langs->load("errors");
726
-			$this->error=$langs->trans("ErrorWrongValueForParameterX","1");
727
-			dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
728
-			return -1;
729
-		}
730
-		if (! $type_contact)
731
-		{
732
-			$langs->load("errors");
733
-			$this->error=$langs->trans("ErrorWrongValueForParameterX","2");
734
-			dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
735
-			return -2;
736
-		}
737
-
738
-		$id_type_contact=0;
739
-		if (is_numeric($type_contact))
740
-		{
741
-			$id_type_contact=$type_contact;
742
-		}
743
-		else
744
-		{
745
-			// We look for id type_contact
746
-			$sql = "SELECT tc.rowid";
747
-			$sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
748
-			$sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
749
-			$sql.= " AND tc.source='".$this->db->escape($source)."'";
750
-			$sql.= " AND tc.code='".$this->db->escape($type_contact)."' AND tc.active=1";
751
-			//print $sql;
752
-			$resql=$this->db->query($sql);
753
-			if ($resql)
754
-			{
755
-				$obj = $this->db->fetch_object($resql);
756
-				if ($obj) $id_type_contact=$obj->rowid;
757
-			}
758
-		}
759
-
760
-		if ($id_type_contact == 0)
761
-		{
762
-			$this->error='CODE_NOT_VALID_FOR_THIS_ELEMENT';
763
-			dol_syslog("CODE_NOT_VALID_FOR_THIS_ELEMENT: Code type of contact '".$type_contact."' does not exists or is not active for element ".$this->element.", we can ignore it");
764
-			return -3;
765
-		}
766
-
767
-		$datecreate = dol_now();
768
-
769
-		// Socpeople must have already been added by some trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error
770
-		$TListeContacts=$this->liste_contact(-1, $source);
771
-		$already_added=false;
772
-		if(!empty($TListeContacts)) {
773
-			foreach($TListeContacts as $array_contact) {
774
-				if($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) {
775
-					$already_added=true;
776
-					break;
777
-				}
778
-			}
779
-		}
64
+    /**
65
+     * @var int[][]		Array of linked objects ids. Loaded by ->fetchObjectLinked
66
+     */
67
+    public $linkedObjectsIds;
780 68
 
781
-		if(!$already_added) {
69
+    /**
70
+     * @var mixed		Array of linked objects. Loaded by ->fetchObjectLinked
71
+     */
72
+    public $linkedObjects;
782 73
 
783
-			$this->db->begin();
74
+    /**
75
+     * @var Object      To store a cloned copy of object before to edit it and keep track of old properties
76
+     */
77
+    public $oldcopy;
784 78
 
785
-			// Insert into database
786
-			$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_contact";
787
-			$sql.= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) ";
788
-			$sql.= " VALUES (".$this->id.", ".$fk_socpeople." , " ;
789
-			$sql.= "'".$this->db->idate($datecreate)."'";
790
-			$sql.= ", 4, ". $id_type_contact;
791
-			$sql.= ")";
79
+    /**
80
+     * @var string		Column name of the ref field.
81
+     */
82
+    protected $table_ref_field = '';
792 83
 
793
-			$resql=$this->db->query($sql);
794
-			if ($resql)
795
-			{
796
-				if (! $notrigger)
797
-				{
798
-					$result=$this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user);
799
-					if ($result < 0)
800
-					{
801
-						$this->db->rollback();
802
-						return -1;
803
-					}
804
-				}
805 84
 
806
-				$this->db->commit();
807
-				return 1;
808
-			}
809
-			else
810
-			{
811
-				if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
812
-				{
813
-					$this->error=$this->db->errno();
814
-					$this->db->rollback();
815
-					echo 'err rollback';
816
-					return -2;
817
-				}
818
-				else
819
-				{
820
-					$this->error=$this->db->error();
821
-					$this->db->rollback();
822
-					return -1;
823
-				}
824
-			}
825
-		} else return 0;
826
-	}
827 85
 
828
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
829
-	/**
830
-	 *    Copy contact from one element to current
831
-	 *
832
-	 *    @param    CommonObject    $objFrom    Source element
833
-	 *    @param    string          $source     Nature of contact ('internal' or 'external')
834
-	 *    @return   int                         >0 if OK, <0 if KO
835
-	 */
836
-	function copy_linked_contact($objFrom, $source='internal')
837
-	{
838
-        // phpcs:enable
839
-		$contacts = $objFrom->liste_contact(-1, $source);
840
-		foreach($contacts as $contact)
841
-		{
842
-			if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0)
843
-			{
844
-				$this->error=$this->db->lasterror();
845
-				return -1;
846
-			}
847
-		}
848
-		return 1;
849
-	}
86
+    // Following vars are used by some objects only. We keep this property here in CommonObject to be able to provide common method using them.
850 87
 
851
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
852
-	/**
853
-	 *      Update a link to contact line
854
-	 *
855
-	 *      @param	int		$rowid              Id of line contact-element
856
-	 * 		@param	int		$statut	            New status of link
857
-	 *      @param  int		$type_contact_id    Id of contact type (not modified if 0)
858
-	 *      @param  int		$fk_socpeople	    Id of soc_people to update (not modified if 0)
859
-	 *      @return int                 		<0 if KO, >= 0 if OK
860
-	 */
861
-	function update_contact($rowid, $statut, $type_contact_id=0, $fk_socpeople=0)
862
-	{
863
-        // phpcs:enable
864
-		// Insert into database
865
-		$sql = "UPDATE ".MAIN_DB_PREFIX."element_contact set";
866
-		$sql.= " statut = ".$statut;
867
-		if ($type_contact_id) $sql.= ", fk_c_type_contact = '".$type_contact_id ."'";
868
-		if ($fk_socpeople) $sql.= ", fk_socpeople = '".$fk_socpeople ."'";
869
-		$sql.= " where rowid = ".$rowid;
870
-		$resql=$this->db->query($sql);
871
-		if ($resql)
872
-		{
873
-			return 0;
874
-		}
875
-		else
876
-		{
877
-			$this->error=$this->db->lasterror();
878
-			return -1;
879
-		}
880
-	}
88
+    /**
89
+     * @var array<string,mixed>		Can be used to pass information when only object is provided to method
90
+     */
91
+    public $context=array();
881 92
 
882
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
883
-	/**
884
-	 *    Delete a link to contact line
885
-	 *
886
-	 *    @param	int		$rowid			Id of contact link line to delete
887
-	 *    @param	int		$notrigger		Disable all triggers
888
-	 *    @return   int						>0 if OK, <0 if KO
889
-	 */
890
-	function delete_contact($rowid, $notrigger=0)
891
-	{
892
-        // phpcs:enable
893
-		global $user;
93
+    /**
94
+     * @var string		Contains canvas name if record is an alternative canvas record
95
+     */
96
+    public $canvas;
894 97
 
98
+    /**
99
+     * @var Project The related project
100
+     * @see fetch_projet()
101
+     */
102
+    public $project;
895 103
 
896
-		$this->db->begin();
104
+    /**
105
+     * @var int The related project ID
106
+     * @see setProject(), project
107
+     */
108
+    public $fk_project;
897 109
 
898
-		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
899
-		$sql.= " WHERE rowid =".$rowid;
110
+    /**
111
+     * @deprecated
112
+     * @see project
113
+     */
114
+    public $projet;
900 115
 
901
-		dol_syslog(get_class($this)."::delete_contact", LOG_DEBUG);
902
-		if ($this->db->query($sql))
903
-		{
904
-			if (! $notrigger)
905
-			{
906
-				$result=$this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user);
907
-				if ($result < 0) { $this->db->rollback(); return -1; }
908
-			}
909
-
910
-			$this->db->commit();
911
-			return 1;
912
-		}
913
-		else
914
-		{
915
-			$this->error=$this->db->lasterror();
916
-			$this->db->rollback();
917
-			return -1;
918
-		}
919
-	}
116
+    /**
117
+     * @var Contact a related contact
118
+     * @see fetch_contact()
119
+     */
120
+    public $contact;
920 121
 
921
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
922
-	/**
923
-	 *    Delete all links between an object $this and all its contacts
924
-	 *
925
-	 *	  @param	string	$source		'' or 'internal' or 'external'
926
-	 *	  @param	string	$code		Type of contact (code or id)
927
-	 *    @return   int					>0 if OK, <0 if KO
928
-	 */
929
-	function delete_linked_contact($source='',$code='')
930
-	{
931
-        // phpcs:enable
932
-		$temp = array();
933
-		$typeContact = $this->liste_type_contact($source,'',0,0,$code);
934
-
935
-		foreach($typeContact as $key => $value)
936
-		{
937
-			array_push($temp,$key);
938
-		}
939
-		$listId = implode(",", $temp);
940
-
941
-		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
942
-		$sql.= " WHERE element_id = ".$this->id;
943
-		if ($listId)
944
-			$sql.= " AND fk_c_type_contact IN (".$listId.")";
945
-
946
-		dol_syslog(get_class($this)."::delete_linked_contact", LOG_DEBUG);
947
-		if ($this->db->query($sql))
948
-		{
949
-			return 1;
950
-		}
951
-		else
952
-		{
953
-			$this->error=$this->db->lasterror();
954
-			return -1;
955
-		}
956
-	}
122
+    /**
123
+     * @var int The related contact ID
124
+     * @see fetch_contact()
125
+     */
126
+    public $contact_id;
957 127
 
958
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
959
-	/**
960
-	 *    Get array of all contacts for an object
961
-	 *
962
-	 *    @param	int			$statut		Status of links to get (-1=all)
963
-	 *    @param	string		$source		Source of contact: external or thirdparty (llx_socpeople) or internal (llx_user)
964
-	 *    @param	int         $list       0:Return array contains all properties, 1:Return array contains just id
965
-	 *    @param    string      $code       Filter on this code of contact type ('SHIPPING', 'BILLING', ...)
966
-	 *    @return	array|int		        Array of contacts, -1 if error
967
-	 */
968
-	function liste_contact($statut=-1,$source='external',$list=0,$code='')
969
-	{
970
-        // phpcs:enable
971
-		global $langs;
972
-
973
-		$tab=array();
974
-
975
-		$sql = "SELECT ec.rowid, ec.statut as statuslink, ec.fk_socpeople as id, ec.fk_c_type_contact";    // This field contains id of llx_socpeople or id of llx_user
976
-		if ($source == 'internal') $sql.=", '-1' as socid, t.statut as statuscontact, t.login, t.photo";
977
-		if ($source == 'external' || $source == 'thirdparty') $sql.=", t.fk_soc as socid, t.statut as statuscontact";
978
-		$sql.= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email";
979
-		$sql.= ", tc.source, tc.element, tc.code, tc.libelle";
980
-		$sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
981
-		$sql.= ", ".MAIN_DB_PREFIX."element_contact ec";
982
-		if ($source == 'internal') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
983
-		if ($source == 'external'|| $source == 'thirdparty') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
984
-		$sql.= " WHERE ec.element_id =".$this->id;
985
-		$sql.= " AND ec.fk_c_type_contact=tc.rowid";
986
-		$sql.= " AND tc.element='".$this->db->escape($this->element)."'";
987
-		if ($code) $sql.= " AND tc.code = '".$this->db->escape($code)."'";
988
-		if ($source == 'internal') $sql.= " AND tc.source = 'internal'";
989
-		if ($source == 'external' || $source == 'thirdparty') $sql.= " AND tc.source = 'external'";
990
-		$sql.= " AND tc.active=1";
991
-		if ($statut >= 0) $sql.= " AND ec.statut = '".$statut."'";
992
-		$sql.=" ORDER BY t.lastname ASC";
993
-
994
-		dol_syslog(get_class($this)."::liste_contact", LOG_DEBUG);
995
-		$resql=$this->db->query($sql);
996
-		if ($resql)
997
-		{
998
-			$num=$this->db->num_rows($resql);
999
-			$i=0;
1000
-			while ($i < $num)
1001
-			{
1002
-				$obj = $this->db->fetch_object($resql);
128
+    /**
129
+     * @var Societe A related thirdparty
130
+     * @see fetch_thirdparty()
131
+     */
132
+    public $thirdparty;
1003 133
 
1004
-				if (! $list)
1005
-				{
1006
-					$transkey="TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
1007
-					$libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1008
-					$tab[$i]=array('source'=>$obj->source,'socid'=>$obj->socid,'id'=>$obj->id,
1009
-								   'nom'=>$obj->lastname,      // For backward compatibility
1010
-								   'civility'=>$obj->civility, 'lastname'=>$obj->lastname, 'firstname'=>$obj->firstname, 'email'=>$obj->email, 'login'=>$obj->login, 'photo'=>$obj->photo, 'statuscontact'=>$obj->statuscontact,
1011
-								   'rowid'=>$obj->rowid, 'code'=>$obj->code, 'libelle'=>$libelle_type, 'status'=>$obj->statuslink, 'fk_c_type_contact'=>$obj->fk_c_type_contact);
1012
-				}
1013
-				else
1014
-				{
1015
-					$tab[$i]=$obj->id;
1016
-				}
134
+    /**
135
+     * @var User A related user
136
+     * @see fetch_user()
137
+     */
138
+    public $user;
1017 139
 
1018
-				$i++;
1019
-			}
1020
-
1021
-			return $tab;
1022
-		}
1023
-		else
1024
-		{
1025
-			$this->error=$this->db->lasterror();
1026
-			dol_print_error($this->db);
1027
-			return -1;
1028
-		}
1029
-	}
1030
-
1031
-
1032
-	/**
1033
-	 * 		Update status of a contact linked to object
1034
-	 *
1035
-	 * 		@param	int		$rowid		Id of link between object and contact
1036
-	 * 		@return	int					<0 if KO, >=0 if OK
1037
-	 */
1038
-	function swapContactStatus($rowid)
1039
-	{
1040
-		$sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,";
1041
-		$sql.= " tc.code, tc.libelle";
1042
-		//$sql.= ", s.fk_soc";
1043
-		$sql.= " FROM (".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as tc)";
1044
-		//$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as s ON ec.fk_socpeople=s.rowid";	// Si contact de type external, alors il est lie a une societe
1045
-		$sql.= " WHERE ec.rowid =".$rowid;
1046
-		$sql.= " AND ec.fk_c_type_contact=tc.rowid";
1047
-		$sql.= " AND tc.element = '".$this->db->escape($this->element)."'";
1048
-
1049
-		dol_syslog(get_class($this)."::swapContactStatus", LOG_DEBUG);
1050
-		$resql=$this->db->query($sql);
1051
-		if ($resql)
1052
-		{
1053
-			$obj = $this->db->fetch_object($resql);
1054
-			$newstatut = ($obj->statut == 4) ? 5 : 4;
1055
-			$result = $this->update_contact($rowid, $newstatut);
1056
-			$this->db->free($resql);
1057
-			return $result;
1058
-		}
1059
-		else
1060
-		{
1061
-			$this->error=$this->db->error();
1062
-			dol_print_error($this->db);
1063
-			return -1;
1064
-		}
1065
-	}
140
+    /**
141
+     * @var string 	The type of originating object ('commande', 'facture', ...)
142
+     * @see fetch_origin()
143
+     */
144
+    public $origin;
1066 145
 
1067
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1068
-	/**
1069
-	 *      Return array with list of possible values for type of contacts
1070
-	 *
1071
-	 *      @param	string	$source     'internal', 'external' or 'all'
1072
-	 *      @param	string	$order		Sort order by : 'position', 'code', 'rowid'...
1073
-	 *      @param  int		$option     0=Return array id->label, 1=Return array code->label
1074
-	 *      @param  int		$activeonly 0=all status of contact, 1=only the active
1075
-	 *		@param	string	$code		Type of contact (Example: 'CUSTOMER', 'SERVICE')
1076
-	 *      @return array       		Array list of type of contacts (id->label if option=0, code->label if option=1)
1077
-	 */
1078
-	function liste_type_contact($source='internal', $order='position', $option=0, $activeonly=0, $code='')
1079
-	{
1080
-        // phpcs:enable
1081
-		global $langs;
1082
-
1083
-		if (empty($order)) $order='position';
1084
-		if ($order == 'position') $order.=',code';
1085
-
1086
-		$tab = array();
1087
-		$sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position";
1088
-		$sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
1089
-		$sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
1090
-		if ($activeonly == 1) $sql.= " AND tc.active=1"; // only the active types
1091
-		if (! empty($source) && $source != 'all') $sql.= " AND tc.source='".$this->db->escape($source)."'";
1092
-		if (! empty($code)) $sql.= " AND tc.code='".$this->db->escape($code)."'";
1093
-		$sql.= $this->db->order($order,'ASC');
1094
-
1095
-		//print "sql=".$sql;
1096
-		$resql=$this->db->query($sql);
1097
-		if ($resql)
1098
-		{
1099
-			$num=$this->db->num_rows($resql);
1100
-			$i=0;
1101
-			while ($i < $num)
1102
-			{
1103
-				$obj = $this->db->fetch_object($resql);
1104
-
1105
-				$transkey="TypeContact_".$this->element."_".$source."_".$obj->code;
1106
-				$libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1107
-				if (empty($option)) $tab[$obj->rowid]=$libelle_type;
1108
-				else $tab[$obj->code]=$libelle_type;
1109
-				$i++;
1110
-			}
1111
-			return $tab;
1112
-		}
1113
-		else
1114
-		{
1115
-			$this->error=$this->db->lasterror();
1116
-			//dol_print_error($this->db);
1117
-			return null;
1118
-		}
1119
-	}
1120
-
1121
-	/**
1122
-	 *      Return id of contacts for a source and a contact code.
1123
-	 *      Example: contact client de facturation ('external', 'BILLING')
1124
-	 *      Example: contact client de livraison ('external', 'SHIPPING')
1125
-	 *      Example: contact interne suivi paiement ('internal', 'SALESREPFOLL')
1126
-	 *
1127
-	 *		@param	string	$source		'external' or 'internal'
1128
-	 *		@param	string	$code		'BILLING', 'SHIPPING', 'SALESREPFOLL', ...
1129
-	 *		@param	int		$status		limited to a certain status
1130
-	 *      @return array       		List of id for such contacts
1131
-	 */
1132
-	function getIdContact($source,$code,$status=0)
1133
-	{
1134
-		global $conf;
1135
-
1136
-		$result=array();
1137
-		$i=0;
1138
-		//cas particulier pour les expeditions
1139
-		if($this->element=='shipping' && $this->origin_id != 0) {
1140
-			$id=$this->origin_id;
1141
-			$element='commande';
1142
-        } else if($this->element=='reception' && $this->origin_id != 0) {
1143
-            $id=$this->origin_id;
1144
-            $element='order_supplier';
1145
-		} else {
1146
-			$id=$this->id;
1147
-			$element=$this->element;
1148
-		}
1149
-
1150
-		$sql = "SELECT ec.fk_socpeople";
1151
-		$sql.= " FROM ".MAIN_DB_PREFIX."element_contact as ec,";
1152
-		if ($source == 'internal') $sql.= " ".MAIN_DB_PREFIX."user as c,";
1153
-		if ($source == 'external') $sql.= " ".MAIN_DB_PREFIX."socpeople as c,";
1154
-		$sql.= " ".MAIN_DB_PREFIX."c_type_contact as tc";
1155
-		$sql.= " WHERE ec.element_id = ".$id;
1156
-		$sql.= " AND ec.fk_socpeople = c.rowid";
1157
-		if ($source == 'internal') $sql.= " AND c.entity IN (".getEntity('user').")";
1158
-		if ($source == 'external') $sql.= " AND c.entity IN (".getEntity('societe').")";
1159
-		$sql.= " AND ec.fk_c_type_contact = tc.rowid";
1160
-		$sql.= " AND tc.element = '".$element."'";
1161
-		$sql.= " AND tc.source = '".$source."'";
1162
-		$sql.= " AND tc.code = '".$code."'";
1163
-		$sql.= " AND tc.active = 1";
1164
-		if ($status) $sql.= " AND ec.statut = ".$status;
1165
-
1166
-		dol_syslog(get_class($this)."::getIdContact", LOG_DEBUG);
1167
-		$resql=$this->db->query($sql);
1168
-		if ($resql)
1169
-		{
1170
-			while ($obj = $this->db->fetch_object($resql))
1171
-			{
1172
-				$result[$i]=$obj->fk_socpeople;
1173
-				$i++;
1174
-			}
1175
-		}
1176
-		else
1177
-		{
1178
-			$this->error=$this->db->error();
1179
-			return null;
1180
-		}
1181
-
1182
-		return $result;
1183
-	}
146
+    /**
147
+     * @var int 	The id of originating object
148
+     * @see fetch_origin()
149
+     */
150
+    public $origin_id;
1184 151
 
1185
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1186
-	/**
1187
-	 *		Load object contact with id=$this->contactid into $this->contact
1188
-	 *
1189
-	 *		@param	int		$contactid      Id du contact. Use this->contactid if empty.
1190
-	 *		@return	int						<0 if KO, >0 if OK
1191
-	 */
1192
-	function fetch_contact($contactid=null)
1193
-	{
1194
-        // phpcs:enable
1195
-		if (empty($contactid)) $contactid=$this->contactid;
152
+    /**
153
+     * @var string The object's reference
154
+     */
155
+    public $ref;
1196 156
 
1197
-		if (empty($contactid)) return 0;
157
+    /**
158
+     * @var string The object's previous reference
159
+     */
160
+    public $ref_previous;
1198 161
 
1199
-		require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1200
-		$contact = new Contact($this->db);
1201
-		$result=$contact->fetch($contactid);
1202
-		$this->contact = $contact;
1203
-		return $result;
1204
-	}
162
+    /**
163
+     * @var string The object's next reference
164
+     */
165
+    public $ref_next;
1205 166
 
1206
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1207
-	/**
1208
-	 *    	Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty
1209
-	 *
1210
-	 *		@param		int		$force_thirdparty_id	Force thirdparty id
1211
-	 *		@return		int								<0 if KO, >0 if OK
1212
-	 */
1213
-	function fetch_thirdparty($force_thirdparty_id=0)
1214
-	{
1215
-        // phpcs:enable
1216
-		global $conf;
167
+    /**
168
+     * @var string An external reference for the object
169
+     */
170
+    public $ref_ext;
1217 171
 
1218
-		if (empty($this->socid) && empty($this->fk_soc) && empty($this->fk_thirdparty) && empty($force_thirdparty_id))
1219
-			return 0;
172
+    /**
173
+     * @var int The object's status
174
+     * @see setStatut()
175
+     */
176
+    public $statut;
1220 177
 
1221
-		require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
178
+    /**
179
+     * @var string
180
+     * @see getFullAddress()
181
+     */
182
+    public $country;
1222 183
 
1223
-		$idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : $this->fk_thirdparty);
1224
-		if ($force_thirdparty_id)
1225
-			$idtofetch = $force_thirdparty_id;
184
+    /**
185
+     * @var int
186
+     * @see getFullAddress(), country
187
+     */
188
+    public $country_id;
1226 189
 
1227
-		if ($idtofetch) {
1228
-			$thirdparty = new Societe($this->db);
1229
-			$result = $thirdparty->fetch($idtofetch);
1230
-			$this->thirdparty = $thirdparty;
190
+    /**
191
+     * @var string
192
+     * @see getFullAddress(), isInEEC(), country
193
+     */
194
+    public $country_code;
1231 195
 
1232
-			// Use first price level if level not defined for third party
1233
-			if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) {
1234
-				$this->thirdparty->price_level = 1;
1235
-			}
196
+    /**
197
+     * @var string
198
+     * @see getFullAddress()
199
+     */
200
+    public $state;
1236 201
 
1237
-			return $result;
1238
-		} else
1239
-			return -1;
1240
-	}
202
+    /**
203
+     * @var int
204
+     * @see getFullAddress(), state
205
+     */
206
+    public $state_id;
1241 207
 
208
+    /**
209
+     * @var string
210
+     * @see getFullAddress(), state
211
+     */
212
+    public $state_code;
1242 213
 
1243
-	/**
1244
-	 * Looks for an object with ref matching the wildcard provided
1245
-	 * It does only work when $this->table_ref_field is set
1246
-	 *
1247
-	 * @param string $ref Wildcard
1248
-	 * @return int >1 = OK, 0 = Not found or table_ref_field not defined, <0 = KO
1249
-	 */
1250
-	public function fetchOneLike($ref)
1251
-	{
1252
-		if (!$this->table_ref_field) {
1253
-			return 0;
1254
-		}
214
+    /**
215
+     * @var string
216
+     * @see getFullAddress(), region
217
+     */
218
+    public $region;
1255 219
 
1256
-		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE '.$this->table_ref_field.' LIKE "'.$this->db->escape($ref).'" LIMIT 1';
220
+    /**
221
+     * @var string
222
+     * @see getFullAddress(), region
223
+     */
224
+    public $region_code;
1257 225
 
1258
-		$query = $this->db->query($sql);
226
+    /**
227
+     * @var int
228
+     * @see fetch_barcode()
229
+     */
230
+    public $barcode_type;
1259 231
 
1260
-		if (!$this->db->num_rows($query)) {
1261
-			return 0;
1262
-		}
232
+    /**
233
+     * @var string
234
+     * @see fetch_barcode(), barcode_type
235
+     */
236
+    public $barcode_type_code;
1263 237
 
1264
-		$result = $this->db->fetch_object($query);
238
+    /**
239
+     * @var string
240
+     * @see fetch_barcode(), barcode_type
241
+     */
242
+    public $barcode_type_label;
1265 243
 
1266
-		return $this->fetch($result->rowid);
1267
-	}
244
+    /**
245
+     * @var string
246
+     * @see fetch_barcode(), barcode_type
247
+     */
248
+    public $barcode_type_coder;
1268 249
 
1269
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1270
-	/**
1271
-	 *	Load data for barcode into properties ->barcode_type*
1272
-	 *	Properties ->barcode_type that is id of barcode. Type is used to find other properties, but
1273
-	 *  if it is not defined, ->element must be defined to know default barcode type.
1274
-	 *
1275
-	 *	@return		int			<0 if KO, 0 if can't guess type of barcode (ISBN, EAN13...), >0 if OK (all barcode properties loaded)
1276
-	 */
1277
-	function fetch_barcode()
1278
-	{
1279
-        // phpcs:enable
1280
-		global $conf;
250
+    /**
251
+     * @var int Payment method ID (cheque, cash, ...)
252
+     * @see setPaymentMethods()
253
+     */
254
+    public $mode_reglement_id;
1281 255
 
1282
-		dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
256
+    /**
257
+     * @var int Payment terms ID
258
+     * @see setPaymentTerms()
259
+     */
260
+    public $cond_reglement_id;
1283 261
 
1284
-		$idtype=$this->barcode_type;
1285
-		if (empty($idtype) && $idtype != '0')	// If type of barcode no set, we try to guess. If set to '0' it means we forced to have type remain not defined
1286
-		{
1287
-			if ($this->element == 'product')      $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1288
-			else if ($this->element == 'societe') $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1289
-			else dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1290
-		}
262
+    /**
263
+     * @var int Payment terms ID
264
+     * @deprecated Kept for compatibility
265
+     * @see cond_reglement_id;
266
+     */
267
+    public $cond_reglement;
1291 268
 
1292
-		if ($idtype > 0)
1293
-		{
1294
-			if (empty($this->barcode_type) || empty($this->barcode_type_code) || empty($this->barcode_type_label) || empty($this->barcode_type_coder))    // If data not already loaded
1295
-			{
1296
-				$sql = "SELECT rowid, code, libelle as label, coder";
1297
-				$sql.= " FROM ".MAIN_DB_PREFIX."c_barcode_type";
1298
-				$sql.= " WHERE rowid = ".$idtype;
1299
-				dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1300
-				$resql = $this->db->query($sql);
1301
-				if ($resql)
1302
-				{
1303
-					$obj = $this->db->fetch_object($resql);
1304
-					$this->barcode_type       = $obj->rowid;
1305
-					$this->barcode_type_code  = $obj->code;
1306
-					$this->barcode_type_label = $obj->label;
1307
-					$this->barcode_type_coder = $obj->coder;
1308
-					return 1;
1309
-				}
1310
-				else
1311
-				{
1312
-					dol_print_error($this->db);
1313
-					return -1;
1314
-				}
1315
-			}
1316
-		}
1317
-		return 0;
1318
-	}
269
+    /**
270
+     * @var int Delivery address ID
271
+     * @deprecated
272
+     * @see setDeliveryAddress()
273
+     */
274
+    public $fk_delivery_address;
1319 275
 
1320
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1321
-	/**
1322
-	 *		Load the project with id $this->fk_project into this->project
1323
-	 *
1324
-	 *		@return		int			<0 if KO, >=0 if OK
1325
-	 */
1326
-	function fetch_projet()
1327
-	{
1328
-        // phpcs:enable
1329
-		include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
276
+    /**
277
+     * @var int Shipping method ID
278
+     * @see setShippingMethod()
279
+     */
280
+    public $shipping_method_id;
1330 281
 
1331
-		if (empty($this->fk_project) && ! empty($this->fk_projet)) $this->fk_project = $this->fk_projet;	// For backward compatibility
1332
-		if (empty($this->fk_project)) return 0;
282
+    /**
283
+     * @var string
284
+     * @see SetDocModel()
285
+     */
286
+    public $modelpdf;
1333 287
 
1334
-		$project = new Project($this->db);
1335
-		$result = $project->fetch($this->fk_project);
288
+    /**
289
+     * @var int Bank account ID
290
+     * @see SetBankAccount()
291
+     */
292
+    public $fk_account;
1336 293
 
1337
-		$this->projet = $project;	// deprecated
1338
-		$this->project = $project;
1339
-		return $result;
1340
-	}
294
+    /**
295
+     * @var string Public note
296
+     * @see update_note()
297
+     */
298
+    public $note_public;
1341 299
 
1342
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1343
-	/**
1344
-	 *		Load the product with id $this->fk_product into this->product
1345
-	 *
1346
-	 *		@return		int			<0 if KO, >=0 if OK
1347
-	 */
1348
-	function fetch_product()
1349
-	{
1350
-        // phpcs:enable
1351
-		include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
300
+    /**
301
+     * @var string Private note
302
+     * @see update_note()
303
+     */
304
+    public $note_private;
1352 305
 
1353
-		if (empty($this->fk_product)) return 0;
306
+    /**
307
+     * @deprecated
308
+     * @see note_public
309
+     */
310
+    public $note;
1354 311
 
1355
-		$product = new Product($this->db);
1356
-		$result = $product->fetch($this->fk_product);
312
+    /**
313
+     * @var float Total amount before taxes
314
+     * @see update_price()
315
+     */
316
+    public $total_ht;
1357 317
 
1358
-		$this->product = $product;
1359
-		return $result;
1360
-	}
318
+    /**
319
+     * @var float Total VAT amount
320
+     * @see update_price()
321
+     */
322
+    public $total_tva;
1361 323
 
1362
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1363
-	/**
1364
-	 *		Load the user with id $userid into this->user
1365
-	 *
1366
-	 *		@param	int		$userid 		Id du contact
1367
-	 *		@return	int						<0 if KO, >0 if OK
1368
-	 */
1369
-	function fetch_user($userid)
1370
-	{
1371
-        // phpcs:enable
1372
-		$user = new User($this->db);
1373
-		$result=$user->fetch($userid);
1374
-		$this->user = $user;
1375
-		return $result;
1376
-	}
324
+    /**
325
+     * @var float Total local tax 1 amount
326
+     * @see update_price()
327
+     */
328
+    public $total_localtax1;
1377 329
 
1378
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1379
-	/**
1380
-	 *	Read linked origin object
1381
-	 *
1382
-	 *	@return		void
1383
-	 */
1384
-	function fetch_origin()
1385
-	{
1386
-        // phpcs:enable
1387
-		if ($this->origin == 'shipping') $this->origin = 'expedition';
1388
-		if ($this->origin == 'delivery') $this->origin = 'livraison';
1389
-        if ($this->origin == 'order_supplier') $this->origin = 'commandeFournisseur';
330
+    /**
331
+     * @var float Total local tax 2 amount
332
+     * @see update_price()
333
+     */
334
+    public $total_localtax2;
1390 335
 
1391
-		$origin = $this->origin;
336
+    /**
337
+     * @var float Total amount with taxes
338
+     * @see update_price()
339
+     */
340
+    public $total_ttc;
1392 341
 
1393
-		$classname = ucfirst($origin);
1394
-		$this->$origin = new $classname($this->db);
1395
-		$this->$origin->fetch($this->origin_id);
1396
-	}
342
+    /**
343
+     * @var CommonObjectLine[]
344
+     */
345
+    public $lines;
1397 346
 
1398
-	/**
1399
-     *  Load object from specific field
1400
-     *
1401
-     *  @param	string	$table		Table element or element line
1402
-     *  @param	string	$field		Field selected
1403
-     *  @param	string	$key		Import key
1404
-     *  @param	string	$element	Element name
1405
-     *	@return	int					<0 if KO, >0 if OK
347
+    /**
348
+     * @var mixed		Contains comments
349
+     * @see fetchComments()
1406 350
      */
1407
-	function fetchObjectFrom($table, $field, $key, $element = null)
1408
-	{
1409
-		global $conf;
1410
-
1411
-		$result=false;
1412
-
1413
-		$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table;
1414
-		$sql.= " WHERE ".$field." = '".$key."'";
1415
-		if (! empty($element)) {
1416
-			$sql.= " AND entity IN (".getEntity($element).")";
1417
-		} else {
1418
-			$sql.= " AND entity = ".$conf->entity;
1419
-		}
1420
-
1421
-		dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
1422
-		$resql = $this->db->query($sql);
1423
-		if ($resql)
1424
-		{
1425
-			$row = $this->db->fetch_row($resql);
1426
-			// Test for avoid error -1
1427
-			if ($row[0] > 0) {
1428
-				$result = $this->fetch($row[0]);
1429
-			}
1430
-		}
1431
-
1432
-		return $result;
1433
-	}
1434
-
1435
-	/**
1436
-	 *	Getter generic. Load value from a specific field
1437
-	 *
1438
-	 *	@param	string	$table		Table of element or element line
1439
-	 *	@param	int		$id			Element id
1440
-	 *	@param	string	$field		Field selected
1441
-	 *	@return	int					<0 if KO, >0 if OK
1442
-	 */
1443
-	function getValueFrom($table, $id, $field)
1444
-	{
1445
-		$result=false;
1446
-		if (!empty($id) && !empty($field) && !empty($table)) {
1447
-			$sql = "SELECT ".$field." FROM ".MAIN_DB_PREFIX.$table;
1448
-			$sql.= " WHERE rowid = ".$id;
1449
-
1450
-			dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
1451
-			$resql = $this->db->query($sql);
1452
-			if ($resql)
1453
-			{
1454
-				$row = $this->db->fetch_row($resql);
1455
-				$result = $row[0];
1456
-			}
1457
-		}
1458
-		return $result;
1459
-	}
1460
-
1461
-	/**
1462
-	 *	Setter generic. Update a specific field into database.
1463
-	 *  Warning: Trigger is run only if param trigkey is provided.
1464
-	 *
1465
-	 *	@param	string		$field			Field to update
1466
-	 *	@param	mixed		$value			New value
1467
-	 *	@param	string		$table			To force other table element or element line (should not be used)
1468
-	 *	@param	int			$id				To force other object id (should not be used)
1469
-	 *	@param	string		$format			Data format ('text', 'date'). 'text' is used if not defined
1470
-	 *	@param	string		$id_field		To force rowid field name. 'rowid' is used if not defined
1471
-	 *	@param	User|string	$fuser			Update the user of last update field with this user. If not provided, current user is used except if value is 'none'
1472
-	 *  @param  string      $trigkey    	Trigger key to run (in most cases something like 'XXX_MODIFY')
1473
-	 *  @param	string		$fk_user_field	Name of field to save user id making change
1474
-	 *	@return	int							<0 if KO, >0 if OK
1475
-	 *  @see updateExtraField
1476
-	 */
1477
-	function setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='', $fk_user_field='fk_user_modif')
1478
-	{
1479
-		global $user,$langs,$conf;
1480
-
1481
-		if (empty($table)) 	  $table=$this->table_element;
1482
-		if (empty($id))    	  $id=$this->id;
1483
-		if (empty($format))   $format='text';
1484
-		if (empty($id_field)) $id_field='rowid';
1485
-
1486
-		$error=0;
1487
-
1488
-		$this->db->begin();
1489
-
1490
-		// Special case
1491
-		if ($table == 'product' && $field == 'note_private') $field='note';
1492
-		if (in_array($table, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) $fk_user_field = 'fk_user_mod';
1493
-
1494
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET ";
1495
-
1496
-		if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'";
1497
-		else if ($format == 'int') $sql.= $field." = ".$this->db->escape($value);
1498
-		else if ($format == 'date') $sql.= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
1499
-
1500
-		if ($fk_user_field)
1501
-		{
1502
-			if (! empty($fuser) && is_object($fuser)) $sql.=", ".$fk_user_field." = ".$fuser->id;
1503
-			elseif (empty($fuser) || $fuser != 'none') $sql.=", ".$fk_user_field." = ".$user->id;
1504
-		}
1505
-
1506
-		$sql.= " WHERE ".$id_field." = ".$id;
1507
-
1508
-		dol_syslog(get_class($this)."::".__FUNCTION__."", LOG_DEBUG);
1509
-		$resql = $this->db->query($sql);
1510
-		if ($resql)
1511
-		{
1512
-			if ($trigkey)
1513
-			{
1514
-				// call trigger with updated object values
1515
-				if (empty($this->fields) && method_exists($this, 'fetch'))
1516
-				{
1517
-					$result = $this->fetch($id);
1518
-				}
1519
-				else
1520
-				{
1521
-					$result = $this->fetchCommon($id);
1522
-				}
1523
-				if ($result >= 0) $result=$this->call_trigger($trigkey, (! empty($fuser) && is_object($fuser)) ? $fuser : $user);   // This may set this->errors
1524
-				if ($result < 0) $error++;
1525
-			}
351
+    public $comments=array();
1526 352
 
1527
-			if (! $error)
1528
-			{
1529
-				if (property_exists($this, $field)) $this->$field = $value;
1530
-				$this->db->commit();
1531
-				return 1;
1532
-			}
1533
-			else
1534
-			{
1535
-				$this->db->rollback();
1536
-				return -2;
1537
-			}
1538
-		}
1539
-		else
1540
-		{
1541
-			$this->error=$this->db->lasterror();
1542
-			$this->db->rollback();
1543
-			return -1;
1544
-		}
1545
-	}
353
+    /**
354
+     * @var int
355
+     * @see setIncoterms()
356
+     */
357
+    public $fk_incoterms;
1546 358
 
1547
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1548
-	/**
1549
-	 *      Load properties id_previous and id_next by comparing $fieldid with $this->ref
1550
-	 *
1551
-	 *      @param	string	$filter		Optional filter. Example: " AND (t.field1 = 'aa' OR t.field2 = 'bb')"
1552
-	 *	 	@param  string	$fieldid   	Name of field to use for the select MAX and MIN
1553
-	 *		@param	int		$nodbprefix	Do not include DB prefix to forge table name
1554
-	 *      @return int         		<0 if KO, >0 if OK
1555
-	 */
1556
-	function load_previous_next_ref($filter, $fieldid, $nodbprefix=0)
1557
-	{
1558
-        // phpcs:enable
1559
-		global $conf, $user;
1560
-
1561
-		if (! $this->table_element)
1562
-		{
1563
-			dol_print_error('',get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
1564
-			return -1;
1565
-		}
1566
-		if ($fieldid == 'none') return 1;
1567
-
1568
-		// Security on socid
1569
-		$socid = 0;
1570
-		if ($user->societe_id > 0) $socid = $user->societe_id;
1571
-
1572
-		// this->ismultientitymanaged contains
1573
-		// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
1574
-		$alias = 's';
1575
-		if ($this->element == 'societe') $alias = 'te';
1576
-
1577
-		$sql = "SELECT MAX(te.".$fieldid.")";
1578
-		$sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1579
-		if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1580
-			$sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1581
-		}
1582
-		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to entity
1583
-		else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to socid
1584
-		else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid";	// If we need to link to societe to limit select to socid
1585
-		if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid)  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
1586
-		$sql.= " WHERE te.".$fieldid." < '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1587
-		if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1588
-		if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1589
-		if (! empty($filter))
1590
-		{
1591
-			if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1592
-			$sql.=$filter;
1593
-		}
1594
-		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to entity
1595
-		else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to socid
1596
-		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1597
-			if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1598
-				if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1599
-					$sql.= " AND te.entity IS NOT NULL"; // Show all users
1600
-				} else {
1601
-					$sql.= " AND ug.fk_user = te.rowid";
1602
-					$sql.= " AND ug.entity IN (".getEntity($this->element).")";
1603
-				}
1604
-			} else {
1605
-				$sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1606
-			}
1607
-		}
1608
-		if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1609
-		if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1610
-		if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1611
-		//print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1612
-
1613
-		$result = $this->db->query($sql);
1614
-		if (! $result)
1615
-		{
1616
-			$this->error=$this->db->lasterror();
1617
-			return -1;
1618
-		}
1619
-		$row = $this->db->fetch_row($result);
1620
-		$this->ref_previous = $row[0];
1621
-
1622
-
1623
-		$sql = "SELECT MIN(te.".$fieldid.")";
1624
-		$sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1625
-		if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1626
-			$sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1627
-		}
1628
-		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to entity
1629
-		else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to socid
1630
-		else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid";	// If we need to link to societe to limit select to socid
1631
-		if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
1632
-		$sql.= " WHERE te.".$fieldid." > '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1633
-		if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1634
-		if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1635
-		if (! empty($filter))
1636
-		{
1637
-			if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1638
-			$sql.=$filter;
1639
-		}
1640
-		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to entity
1641
-		else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to socid
1642
-		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1643
-			if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1644
-				if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1645
-					$sql.= " AND te.entity IS NOT NULL"; // Show all users
1646
-				} else {
1647
-					$sql.= " AND ug.fk_user = te.rowid";
1648
-					$sql.= " AND ug.entity IN (".getEntity($this->element).")";
1649
-				}
1650
-			} else {
1651
-				$sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1652
-			}
1653
-		}
1654
-		if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1655
-		if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1656
-		if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1657
-		//print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1658
-		// Rem: Bug in some mysql version: SELECT MIN(rowid) FROM llx_socpeople WHERE rowid > 1 when one row in database with rowid=1, returns 1 instead of null
1659
-
1660
-		$result = $this->db->query($sql);
1661
-		if (! $result)
1662
-		{
1663
-			$this->error=$this->db->lasterror();
1664
-			return -2;
1665
-		}
1666
-		$row = $this->db->fetch_row($result);
1667
-		$this->ref_next = $row[0];
1668
-
1669
-		return 1;
1670
-	}
1671
-
1672
-
1673
-	/**
1674
-	 *      Return list of id of contacts of object
1675
-	 *
1676
-	 *      @param	string	$source     Source of contact: external (llx_socpeople) or internal (llx_user) or thirdparty (llx_societe)
1677
-	 *      @return array				Array of id of contacts (if source=external or internal)
1678
-	 * 									Array of id of third parties with at least one contact on object (if source=thirdparty)
1679
-	 */
1680
-	function getListContactId($source='external')
1681
-	{
1682
-		$contactAlreadySelected = array();
1683
-		$tab = $this->liste_contact(-1,$source);
1684
-		$num=count($tab);
1685
-		$i = 0;
1686
-		while ($i < $num)
1687
-		{
1688
-			if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
1689
-			else  $contactAlreadySelected[$i] = $tab[$i]['id'];
1690
-			$i++;
1691
-		}
1692
-		return $contactAlreadySelected;
1693
-	}
1694
-
1695
-
1696
-	/**
1697
-	 *	Link element with a project
1698
-	 *
1699
-	 *	@param     	int		$projectid		Project id to link element to
1700
-	 *	@return		int						<0 if KO, >0 if OK
1701
-	 */
1702
-	function setProject($projectid)
1703
-	{
1704
-		if (! $this->table_element)
1705
-		{
1706
-			dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined",LOG_ERR);
1707
-			return -1;
1708
-		}
1709
-
1710
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1711
-		if ($this->table_element == 'actioncomm')
1712
-		{
1713
-			if ($projectid) $sql.= ' SET fk_project = '.$projectid;
1714
-			else $sql.= ' SET fk_project = NULL';
1715
-			$sql.= ' WHERE id = '.$this->id;
1716
-		}
1717
-		else
1718
-		{
1719
-			if ($projectid) $sql.= ' SET fk_projet = '.$projectid;
1720
-			else $sql.= ' SET fk_projet = NULL';
1721
-			$sql.= ' WHERE rowid = '.$this->id;
1722
-		}
1723
-
1724
-		dol_syslog(get_class($this)."::setProject", LOG_DEBUG);
1725
-		if ($this->db->query($sql))
1726
-		{
1727
-			$this->fk_project = $projectid;
1728
-			return 1;
1729
-		}
1730
-		else
1731
-		{
1732
-			dol_print_error($this->db);
1733
-			return -1;
1734
-		}
1735
-	}
1736
-
1737
-	/**
1738
-	 *  Change the payments methods
1739
-	 *
1740
-	 *  @param		int		$id		Id of new payment method
1741
-	 *  @return		int				>0 if OK, <0 if KO
1742
-	 */
1743
-	function setPaymentMethods($id)
1744
-	{
1745
-		dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
1746
-		if ($this->statut >= 0 || $this->element == 'societe')
1747
-		{
1748
-			// TODO uniformize field name
1749
-			$fieldname = 'fk_mode_reglement';
1750
-			if ($this->element == 'societe') $fieldname = 'mode_reglement';
1751
-			if (get_class($this) == 'Fournisseur') $fieldname = 'mode_reglement_supplier';
1752
-
1753
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1754
-			$sql .= ' SET '.$fieldname.' = '.$id;
1755
-			$sql .= ' WHERE rowid='.$this->id;
1756
-
1757
-			if ($this->db->query($sql))
1758
-			{
1759
-				$this->mode_reglement_id = $id;
1760
-				// for supplier
1761
-				if (get_class($this) == 'Fournisseur') $this->mode_reglement_supplier_id = $id;
1762
-				return 1;
1763
-			}
1764
-			else
1765
-			{
1766
-				dol_syslog(get_class($this).'::setPaymentMethods Erreur '.$sql.' - '.$this->db->error());
1767
-				$this->error=$this->db->error();
1768
-				return -1;
1769
-			}
1770
-		}
1771
-		else
1772
-		{
1773
-			dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
1774
-			$this->error='Status of the object is incompatible '.$this->statut;
1775
-			return -2;
1776
-		}
1777
-	}
1778
-
1779
-	/**
1780
-	 *  Change the multicurrency code
1781
-	 *
1782
-	 *  @param		string	$code	multicurrency code
1783
-	 *  @return		int				>0 if OK, <0 if KO
1784
-	 */
1785
-	function setMulticurrencyCode($code)
1786
-	{
1787
-		dol_syslog(get_class($this).'::setMulticurrencyCode('.$id.')');
1788
-		if ($this->statut >= 0 || $this->element == 'societe')
1789
-		{
1790
-			$fieldname = 'multicurrency_code';
1791
-
1792
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1793
-			$sql .= ' SET '.$fieldname." = '".$this->db->escape($code)."'";
1794
-			$sql .= ' WHERE rowid='.$this->id;
1795
-
1796
-			if ($this->db->query($sql))
1797
-			{
1798
-				$this->multicurrency_code = $code;
359
+    /**
360
+     * @var string
361
+     * @see SetIncoterms()
362
+     */
363
+    public $libelle_incoterms;
1799 364
 
1800
-				list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
1801
-				if ($rate) $this->setMulticurrencyRate($rate,2);
365
+    /**
366
+     * @var string
367
+     * @see display_incoterms()
368
+     */
369
+    public $location_incoterms;
1802 370
 
1803
-				return 1;
1804
-			}
1805
-			else
1806
-			{
1807
-				dol_syslog(get_class($this).'::setMulticurrencyCode Erreur '.$sql.' - '.$this->db->error());
1808
-				$this->error=$this->db->error();
1809
-				return -1;
1810
-			}
1811
-		}
1812
-		else
1813
-		{
1814
-			dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
1815
-			$this->error='Status of the object is incompatible '.$this->statut;
1816
-			return -2;
1817
-		}
1818
-	}
1819
-
1820
-	/**
1821
-	 *  Change the multicurrency rate
1822
-	 *
1823
-	 *  @param		double	$rate	multicurrency rate
1824
-	 *  @param		int		$mode	mode 1 : amounts in company currency will be recalculated, mode 2 : amounts in foreign currency
1825
-	 *  @return		int				>0 if OK, <0 if KO
1826
-	 */
1827
-	function setMulticurrencyRate($rate, $mode=1)
1828
-	{
1829
-		dol_syslog(get_class($this).'::setMulticurrencyRate('.$id.')');
1830
-		if ($this->statut >= 0 || $this->element == 'societe')
1831
-		{
1832
-			$fieldname = 'multicurrency_tx';
1833
-
1834
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1835
-			$sql .= ' SET '.$fieldname.' = '.$rate;
1836
-			$sql .= ' WHERE rowid='.$this->id;
1837
-
1838
-			if ($this->db->query($sql))
1839
-			{
1840
-				$this->multicurrency_tx = $rate;
371
+    public $name;
372
+    public $lastname;
373
+    public $firstname;
374
+    public $civility_id;
1841 375
 
1842
-				// Update line price
1843
-				if (!empty($this->lines))
1844
-				{
1845
-					foreach ($this->lines as &$line)
1846
-					{
1847
-						if($mode == 1) {
1848
-							$line->subprice = 0;
1849
-						}
376
+    // Dates
377
+    public $date_creation;			// Date creation
378
+    public $date_validation;		// Date validation
379
+    public $date_modification;		// Date last change (tms field)
1850 380
 
1851
-						switch ($this->element) {
1852
-							case 'propal':
1853
-								$this->updateline(
1854
-									$line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1855
-									($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1856
-									$line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start,
1857
-									$line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1858
-								);
1859
-								break;
1860
-							case 'commande':
1861
-								$this->updateline(
1862
-									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1863
-									$line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end,
1864
-									$line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1865
-									$line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1866
-								);
1867
-								break;
1868
-							case 'facture':
1869
-								$this->updateline(
1870
-									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1871
-									$line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits,
1872
-									$line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1873
-									$line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice
1874
-								);
1875
-								break;
1876
-							case 'supplier_proposal':
1877
-								$this->updateline(
1878
-									$line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1879
-									($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1880
-									$line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->array_options,
1881
-									$line->ref_fourn, $line->multicurrency_subprice
1882
-								);
1883
-								break;
1884
-							case 'order_supplier':
1885
-								$this->updateline(
1886
-									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1887
-									$line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, false,
1888
-									$line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1889
-								);
1890
-								break;
1891
-							case 'invoice_supplier':
1892
-								$this->updateline(
1893
-									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->tva_tx, $line->localtax1_tx,
1894
-									$line->localtax2_tx, $line->qty, 0, 'HT', $line->info_bits, $line->product_type, $line->remise_percent, false,
1895
-									$line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1896
-								);
1897
-								break;
1898
-							default:
1899
-								dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
1900
-								break;
1901
-						}
1902
-					}
1903
-				}
1904 381
 
1905
-				return 1;
1906
-			}
1907
-			else
1908
-			{
1909
-				dol_syslog(get_class($this).'::setMulticurrencyRate Erreur '.$sql.' - '.$this->db->error());
1910
-				$this->error=$this->db->error();
1911
-				return -1;
1912
-			}
1913
-		}
1914
-		else
1915
-		{
1916
-			dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
1917
-			$this->error='Status of the object is incompatible '.$this->statut;
1918
-			return -2;
1919
-		}
1920
-	}
1921
-
1922
-	/**
1923
-	 *  Change the payments terms
1924
-	 *
1925
-	 *  @param		int		$id		Id of new payment terms
1926
-	 *  @return		int				>0 if OK, <0 if KO
1927
-	 */
1928
-	function setPaymentTerms($id)
1929
-	{
1930
-		dol_syslog(get_class($this).'::setPaymentTerms('.$id.')');
1931
-		if ($this->statut >= 0 || $this->element == 'societe')
1932
-		{
1933
-			// TODO uniformize field name
1934
-			$fieldname = 'fk_cond_reglement';
1935
-			if ($this->element == 'societe') $fieldname = 'cond_reglement';
1936
-			if (get_class($this) == 'Fournisseur') $fieldname = 'cond_reglement_supplier';
1937
-
1938
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1939
-			$sql .= ' SET '.$fieldname.' = '.$id;
1940
-			$sql .= ' WHERE rowid='.$this->id;
1941
-
1942
-			if ($this->db->query($sql))
1943
-			{
1944
-				$this->cond_reglement_id = $id;
1945
-				// for supplier
1946
-				if (get_class($this) == 'Fournisseur') $this->cond_reglement_supplier_id = $id;
1947
-				$this->cond_reglement = $id;	// for compatibility
1948
-				return 1;
1949
-			}
1950
-			else
1951
-			{
1952
-				dol_syslog(get_class($this).'::setPaymentTerms Erreur '.$sql.' - '.$this->db->error());
1953
-				$this->error=$this->db->error();
1954
-				return -1;
1955
-			}
1956
-		}
1957
-		else
1958
-		{
1959
-			dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
1960
-			$this->error='Status of the object is incompatible '.$this->statut;
1961
-			return -2;
1962
-		}
1963
-	}
1964
-
1965
-	/**
1966
-	 *	Define delivery address
1967
-	 *  @deprecated
1968
-	 *
1969
-	 *	@param      int		$id		Address id
1970
-	 *	@return     int				<0 si ko, >0 si ok
1971
-	 */
1972
-	function setDeliveryAddress($id)
1973
-	{
1974
-		$fieldname = 'fk_delivery_address';
1975
-		if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address';
1976
-
1977
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ".$fieldname." = ".$id;
1978
-		$sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1979
-
1980
-		if ($this->db->query($sql))
1981
-		{
1982
-			$this->fk_delivery_address = $id;
1983
-			return 1;
1984
-		}
1985
-		else
1986
-		{
1987
-			$this->error=$this->db->error();
1988
-			dol_syslog(get_class($this).'::setDeliveryAddress Erreur '.$sql.' - '.$this->error);
1989
-			return -1;
1990
-		}
1991
-	}
1992
-
1993
-
1994
-	/**
1995
-	 *  Change the shipping method
1996
-	 *
1997
-	 *  @param      int     $shipping_method_id     Id of shipping method
1998
-     *  @param      bool    $notrigger              false=launch triggers after, true=disable triggers
1999
-     *  @param      User	$userused               Object user
2000
-	 *
2001
-	 *  @return     int              1 if OK, 0 if KO
2002
-	 */
2003
-	function setShippingMethod($shipping_method_id, $notrigger=false, $userused=null)
2004
-	{
2005
-        global $user;
2006 382
 
2007
-        if (empty($userused)) $userused=$user;
383
+    // No constructor as it is an abstract class
2008 384
 
2009
-        $error = 0;
385
+    /**
386
+     * Check an object id/ref exists
387
+     * If you don't need/want to instantiate object and just need to know if object exists, use this method instead of fetch
388
+     *
389
+     *  @param	string	$element   	String of element ('product', 'facture', ...)
390
+     *  @param	int		$id      	Id of object
391
+     *  @param  string	$ref     	Ref of object to check
392
+     *  @param	string	$ref_ext	Ref ext of object to check
393
+     *  @return int     			<0 if KO, 0 if OK but not found, >0 if OK and exists
394
+     */
395
+    static function isExistingObject($element, $id, $ref='', $ref_ext='')
396
+    {
397
+        global $db,$conf;
398
+
399
+        $sql = "SELECT rowid, ref, ref_ext";
400
+        $sql.= " FROM ".MAIN_DB_PREFIX.$element;
401
+        $sql.= " WHERE entity IN (".getEntity($element).")" ;
402
+
403
+        if ($id > 0) $sql.= " AND rowid = ".$db->escape($id);
404
+        else if ($ref) $sql.= " AND ref = '".$db->escape($ref)."'";
405
+        else if ($ref_ext) $sql.= " AND ref_ext = '".$db->escape($ref_ext)."'";
406
+        else {
407
+            $error='ErrorWrongParameters';
408
+            dol_print_error(get_class()."::isExistingObject ".$error, LOG_ERR);
409
+            return -1;
410
+        }
411
+        if ($ref || $ref_ext) $sql.= " AND entity = ".$conf->entity;
2010 412
 
2011
-		if (! $this->table_element) {
2012
-			dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined",LOG_ERR);
2013
-			return -1;
2014
-		}
413
+        dol_syslog(get_class()."::isExistingObject", LOG_DEBUG);
414
+        $resql = $db->query($sql);
415
+        if ($resql)
416
+        {
417
+            $num=$db->num_rows($resql);
418
+            if ($num > 0) return 1;
419
+            else return 0;
420
+        }
421
+        return -1;
422
+    }
2015 423
 
2016
-        $this->db->begin();
424
+    /**
425
+     * Method to output saved errors
426
+     *
427
+     * @return	string		String with errors
428
+     */
429
+    function errorsToString()
430
+    {
431
+        return $this->error.(is_array($this->errors)?(($this->error!=''?', ':'').join(', ',$this->errors)):'');
432
+    }
2017 433
 
2018
-		if ($shipping_method_id<0) $shipping_method_id='NULL';
2019
-		dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
434
+    /**
435
+     *	Return full name (civility+' '+name+' '+lastname)
436
+     *
437
+     *	@param	Translate	$langs			Language object for translation of civility (used only if option is 1)
438
+     *	@param	int			$option			0=No option, 1=Add civility
439
+     * 	@param	int			$nameorder		-1=Auto, 0=Lastname+Firstname, 1=Firstname+Lastname, 2=Firstname
440
+     * 	@param	int			$maxlen			Maximum length
441
+     * 	@return	string						String with full name
442
+     */
443
+    function getFullName($langs,$option=0,$nameorder=-1,$maxlen=0)
444
+    {
445
+        //print "lastname=".$this->lastname." name=".$this->name." nom=".$this->nom."<br>\n";
446
+        $lastname=$this->lastname;
447
+        $firstname=$this->firstname;
448
+        if (empty($lastname))  $lastname=(isset($this->lastname)?$this->lastname:(isset($this->name)?$this->name:(isset($this->nom)?$this->nom:(isset($this->societe)?$this->societe:(isset($this->company)?$this->company:'')))));
2020 449
 
2021
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2022
-		$sql.= " SET fk_shipping_method = ".$shipping_method_id;
2023
-		$sql.= " WHERE rowid=".$this->id;
2024
-        $resql = $this->db->query($sql);
2025
-		if (! $resql) {
2026
-			dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2027
-			$this->error = $this->db->lasterror();
2028
-			$error++;
2029
-        } else {
2030
-            if (!$notrigger)
2031
-            {
2032
-                // Call trigger
2033
-                $this->context=array('shippingmethodupdate'=>1);
2034
-                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2035
-                if ($result < 0) $error++;
2036
-                // End call trigger
2037
-            }
450
+        $ret='';
451
+        if ($option && $this->civility_id)
452
+        {
453
+            if ($langs->transnoentitiesnoconv("Civility".$this->civility_id)!="Civility".$this->civility_id) $ret.=$langs->transnoentitiesnoconv("Civility".$this->civility_id).' ';
454
+            else $ret.=$this->civility_id.' ';
2038 455
         }
2039
-        if ($error)
456
+
457
+        $ret.=dolGetFirstLastname($firstname, $lastname, $nameorder);
458
+
459
+        return dol_trunc($ret,$maxlen);
460
+    }
461
+
462
+    /**
463
+     * 	Return full address of contact
464
+     *
465
+     * 	@param		int			$withcountry		1=Add country into address string
466
+     *  @param		string		$sep				Separator to use to build string
467
+     *  @param		int		    $withregion			1=Add region into address string
468
+     *	@return		string							Full address string
469
+     */
470
+    function getFullAddress($withcountry=0, $sep="\n", $withregion=0)
471
+    {
472
+        if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country)))
2040 473
         {
2041
-            $this->db->rollback();
2042
-            return -1;
2043
-        } else {
2044
-            $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id;
2045
-            $this->db->commit();
2046
-            return 1;
474
+            require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
475
+            $tmparray=getCountry($this->country_id,'all');
476
+            $this->country_code=$tmparray['code'];
477
+            $this->country     =$tmparray['label'];
2047 478
         }
2048
-	}
2049
-
2050
-
2051
-	/**
2052
-	 *  Change the warehouse
2053
-	 *
2054
-	 *  @param      int     $warehouse_id     Id of warehouse
2055
-	 *  @return     int              1 if OK, 0 if KO
2056
-	 */
2057
-	function setWarehouse($warehouse_id)
2058
-	{
2059
-		if (! $this->table_element) {
2060
-			dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined",LOG_ERR);
2061
-			return -1;
2062
-		}
2063
-		if ($warehouse_id<0) $warehouse_id='NULL';
2064
-		dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2065
-
2066
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2067
-		$sql.= " SET fk_warehouse = ".$warehouse_id;
2068
-		$sql.= " WHERE rowid=".$this->id;
2069
-
2070
-		if ($this->db->query($sql)) {
2071
-			$this->warehouse_id = ($warehouse_id=='NULL')?null:$warehouse_id;
2072
-			return 1;
2073
-		} else {
2074
-			dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2075
-			$this->error=$this->db->error();
2076
-			return 0;
2077
-		}
2078
-	}
2079
-
2080
-
2081
-	/**
2082
-	 *		Set last model used by doc generator
2083
-	 *
2084
-	 *		@param		User	$user		User object that make change
2085
-	 *		@param		string	$modelpdf	Modele name
2086
-	 *		@return		int					<0 if KO, >0 if OK
2087
-	 */
2088
-	function setDocModel($user, $modelpdf)
2089
-	{
2090
-		if (! $this->table_element)
2091
-		{
2092
-			dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined",LOG_ERR);
2093
-			return -1;
2094
-		}
2095
-
2096
-		$newmodelpdf=dol_trunc($modelpdf,255);
2097
-
2098
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2099
-		$sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
2100
-		$sql.= " WHERE rowid = ".$this->id;
2101
-		// if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
2102
-		// if ($this->element == 'propal')  $sql.= " AND fk_statut = 0";
2103
-
2104
-		dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
2105
-		$resql=$this->db->query($sql);
2106
-		if ($resql)
2107
-		{
2108
-			$this->modelpdf=$modelpdf;
2109
-			return 1;
2110
-		}
2111
-		else
2112
-		{
2113
-			dol_print_error($this->db);
2114
-			return 0;
2115
-		}
2116
-	}
2117
-
2118
-
2119
-	/**
2120
-	 *  Change the bank account
2121
-	 *
2122
-	 *  @param		int		$fk_account		Id of bank account
2123
-	 *  @param      bool    $notrigger      false=launch triggers after, true=disable triggers
2124
-	 *  @param      User	$userused		Object user
2125
-	 *  @return		int				1 if OK, 0 if KO
2126
-	 */
2127
-	function setBankAccount($fk_account, $notrigger=false, $userused=null)
2128
-	{
2129
-        global $user;
2130 479
 
2131
-        if (empty($userused)) $userused=$user;
480
+        if ($withregion && $this->state_id && (empty($this->state_code) || empty($this->state) || empty($this->region) || empty($this->region_cpde)))
481
+        {
482
+            require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
483
+            $tmparray=getState($this->state_id,'all',0,1);
484
+            $this->state_code   =$tmparray['code'];
485
+            $this->state        =$tmparray['label'];
486
+            $this->region_code  =$tmparray['region_code'];
487
+            $this->region       =$tmparray['region'];
488
+        }
2132 489
 
2133
-        $error = 0;
490
+        return dol_format_address($this, $withcountry, $sep);
491
+    }
2134 492
 
2135
-		if (! $this->table_element) {
2136
-			dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined",LOG_ERR);
2137
-			return -1;
2138
-		}
2139
-        $this->db->begin();
2140 493
 
2141
-		if ($fk_account<0) $fk_account='NULL';
2142
-		dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
494
+    /**
495
+     * 	Return full address for banner
496
+     *
497
+     * 	@param		string		$htmlkey            HTML id to make banner content unique
498
+     *  @param      Object      $object				Object (thirdparty, thirdparty of contact for contact, null for a member)
499
+     *	@return		string							Full address string
500
+     */
501
+    function getBannerAddress($htmlkey, $object)
502
+    {
503
+        global $conf, $langs;
2143 504
 
2144
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2145
-		$sql.= " SET fk_account = ".$fk_account;
2146
-		$sql.= " WHERE rowid=".$this->id;
505
+        $countriesusingstate=array('AU','US','IN','GB','ES','UK','TR');    // See also option MAIN_FORCE_STATE_INTO_ADDRESS
2147 506
 
2148
-        $resql = $this->db->query($sql);
2149
-        if (! $resql)
507
+        $contactid=0;
508
+        $thirdpartyid=0;
509
+        if ($this->element == 'societe')
2150 510
         {
2151
-            dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
2152
-            $this->error = $this->db->lasterror();
2153
-            $error++;
511
+            $thirdpartyid=$this->id;
2154 512
         }
2155
-        else
513
+        if ($this->element == 'contact')
2156 514
         {
2157
-            if (!$notrigger)
515
+            $contactid=$this->id;
516
+            $thirdpartyid=$object->fk_soc;
517
+        }
518
+        if ($this->element == 'user')
519
+        {
520
+            $contactid=$this->contact_id;
521
+            $thirdpartyid=$object->fk_soc;
522
+        }
523
+
524
+        $out='<!-- BEGIN part to show address block -->';
525
+
526
+        $outdone=0;
527
+        $coords = $this->getFullAddress(1,', ',$conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT);
528
+        if ($coords)
529
+        {
530
+            if (! empty($conf->use_javascript_ajax))
2158 531
             {
2159
-                // Call trigger
2160
-                $this->context=array('bankaccountupdate'=>1);
2161
-                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2162
-                if ($result < 0) $error++;
2163
-                // End call trigger
532
+                $namecoords = $this->getFullName($langs,1).'<br>'.$coords;
533
+                // hideonsmatphone because copyToClipboard call jquery dialog that does not work with jmobile
534
+                $out.='<a href="#" class="hideonsmartphone" onclick="return copyToClipboard(\''.dol_escape_js($namecoords).'\',\''.dol_escape_js($langs->trans("HelpCopyToClipboard")).'\');">';
535
+                $out.=img_picto($langs->trans("Address"), 'object_address.png');
536
+                $out.='</a> ';
2164 537
             }
538
+            $out.=dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', '); $outdone++;
539
+            $outdone++;
2165 540
         }
2166
-        if ($error)
541
+
542
+        if (! in_array($this->country_code,$countriesusingstate) && empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS)   // If MAIN_FORCE_STATE_INTO_ADDRESS is on, state is already returned previously with getFullAddress
543
+                && empty($conf->global->SOCIETE_DISABLE_STATE) && $this->state)
2167 544
         {
2168
-            $this->db->rollback();
2169
-            return -1;
545
+            if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 && $this->region) {
546
+                $out.=($outdone?' - ':'').$this->region.' - '.$this->state;
547
+            }
548
+            else {
549
+                $out.=($outdone?' - ':'').$this->state;
550
+            }
551
+            $outdone++;
2170 552
         }
2171
-        else
553
+
554
+        if (! empty($this->phone) || ! empty($this->phone_pro) || ! empty($this->phone_mobile) || ! empty($this->phone_perso) || ! empty($this->fax) || ! empty($this->office_phone) || ! empty($this->user_mobile) || ! empty($this->office_fax)) $out.=($outdone?'<br>':'');
555
+        if (! empty($this->phone) && empty($this->phone_pro)) {		// For objects that store pro phone into ->phone
556
+            $out.=dol_print_phone($this->phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
557
+        }
558
+        if (! empty($this->phone_pro)) {
559
+            $out.=dol_print_phone($this->phone_pro,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
560
+        }
561
+        if (! empty($this->phone_mobile)) {
562
+            $out.=dol_print_phone($this->phone_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
563
+        }
564
+        if (! empty($this->phone_perso)) {
565
+            $out.=dol_print_phone($this->phone_perso,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePerso")); $outdone++;
566
+        }
567
+        if (! empty($this->office_phone)) {
568
+            $out.=dol_print_phone($this->office_phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
569
+        }
570
+        if (! empty($this->user_mobile)) {
571
+            $out.=dol_print_phone($this->user_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
572
+        }
573
+        if (! empty($this->fax)) {
574
+            $out.=dol_print_phone($this->fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
575
+        }
576
+        if (! empty($this->office_fax)) {
577
+            $out.=dol_print_phone($this->office_fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
578
+        }
579
+
580
+        $out.='<div style="clear: both;"></div>';
581
+        $outdone=0;
582
+        if (! empty($this->email))
2172 583
         {
2173
-            $this->fk_account = ($fk_account=='NULL')?null:$fk_account;
2174
-            $this->db->commit();
2175
-            return 1;
584
+            $out.=dol_print_email($this->email,$this->id,$object->id,'AC_EMAIL',0,0,1);
585
+            $outdone++;
586
+        }
587
+        if (! empty($this->url))
588
+        {
589
+            $out.=dol_print_url($this->url,'_goout',0,1);
590
+            $outdone++;
591
+        }
592
+        $out.='<div style="clear: both;">';
593
+        if (! empty($conf->socialnetworks->enabled))
594
+        {
595
+            if ($this->skype) $out.=dol_print_socialnetworks($this->skype,$this->id,$object->id,'skype');
596
+            $outdone++;
597
+            if ($this->jabberid) $out.=dol_print_socialnetworks($this->jabberid,$this->id,$object->id,'jabber');
598
+            $outdone++;
599
+            if ($this->twitter) $out.=dol_print_socialnetworks($this->twitter,$this->id,$object->id,'twitter');
600
+            $outdone++;
601
+            if ($this->facebook) $out.=dol_print_socialnetworks($this->facebook,$this->id,$object->id,'facebook');
602
+            $outdone++;
2176 603
         }
604
+        $out.='</div>';
605
+
606
+        $out.='<!-- END Part to show address block -->';
607
+
608
+        return $out;
2177 609
     }
2178 610
 
611
+    /**
612
+     * Return the link of last main doc file for direct public download.
613
+     *
614
+     * @param	string	$modulepart			Module related to document
615
+     * @param	int		$initsharekey		Init the share key if it was not yet defined
616
+     * @param	int		$relativelink		0=Return full external link, 1=Return link relative to root of file
617
+     * @return	string						Link or empty string if there is no download link
618
+     */
619
+    function getLastMainDocLink($modulepart, $initsharekey=0, $relativelink=0)
620
+    {
621
+        global $user, $dolibarr_main_url_root;
2179 622
 
2180
-	// TODO: Move line related operations to CommonObjectLine?
623
+        if (empty($this->last_main_doc))
624
+        {
625
+            return '';		// No way to known which document name to use
626
+        }
2181 627
 
2182
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2183
-	/**
2184
-	 *  Save a new position (field rang) for details lines.
2185
-	 *  You can choose to set position for lines with already a position or lines without any position defined.
2186
-	 *
2187
-	 * 	@param		boolean		$renum			   True to renum all already ordered lines, false to renum only not already ordered lines.
2188
-	 * 	@param		string		$rowidorder		   ASC or DESC
2189
-	 * 	@param		boolean		$fk_parent_line    Table with fk_parent_line field or not
2190
-	 * 	@return		int                            <0 if KO, >0 if OK
2191
-	 */
2192
-	function line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
2193
-	{
2194
-        // phpcs:enable
2195
-		if (! $this->table_element_line)
2196
-		{
2197
-			dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined",LOG_ERR);
2198
-			return -1;
2199
-		}
2200
-		if (! $this->fk_element)
2201
-		{
2202
-			dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined",LOG_ERR);
2203
-			return -1;
2204
-		}
2205
-
2206
-		// Count number of lines to reorder (according to choice $renum)
2207
-		$nl=0;
2208
-		$sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2209
-		$sql.= ' WHERE '.$this->fk_element.'='.$this->id;
2210
-		if (! $renum) $sql.= ' AND rang = 0';
2211
-		if ($renum) $sql.= ' AND rang <> 0';
2212
-
2213
-		dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
2214
-		$resql = $this->db->query($sql);
2215
-		if ($resql)
2216
-		{
2217
-			$row = $this->db->fetch_row($resql);
2218
-			$nl = $row[0];
2219
-		}
2220
-		else dol_print_error($this->db);
2221
-		if ($nl > 0)
2222
-		{
2223
-			// The goal of this part is to reorder all lines, with all children lines sharing the same
2224
-			// counter that parents.
2225
-			$rows=array();
2226
-
2227
-			// We first search all lines that are parent lines (for multilevel details lines)
2228
-			$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2229
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2230
-			if ($fk_parent_line) $sql.= ' AND fk_parent_line IS NULL';
2231
-			$sql.= ' ORDER BY rang ASC, rowid '.$rowidorder;
2232
-
2233
-			dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
2234
-			$resql = $this->db->query($sql);
2235
-			if ($resql)
2236
-			{
2237
-				$i=0;
2238
-				$num = $this->db->num_rows($resql);
2239
-				while ($i < $num)
2240
-				{
2241
-					$row = $this->db->fetch_row($resql);
2242
-					$rows[] = $row[0];	// Add parent line into array rows
2243
-					$childrens = $this->getChildrenOfLine($row[0]);
2244
-					if (! empty($childrens))
2245
-					{
2246
-						foreach($childrens as $child)
2247
-						{
2248
-							array_push($rows, $child);
2249
-						}
2250
-					}
2251
-					$i++;
2252
-				}
628
+        include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
629
+        $ecmfile=new EcmFiles($this->db);
630
+        $result = $ecmfile->fetch(0, '', $this->last_main_doc);
631
+        if ($result < 0)
632
+        {
633
+            $this->error = $ecmfile->error;
634
+            $this->errors = $ecmfile->errors;
635
+            return -1;
636
+        }
2253 637
 
2254
-				// Now we set a new number for each lines (parent and children with children included into parent tree)
2255
-				if (! empty($rows))
638
+        if (empty($ecmfile->id))
639
+        {
640
+            // Add entry into index
641
+            if ($initsharekey)
642
+            {
643
+                require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
644
+                // TODO We can't, we dont' have full path of file, only last_main_doc adn ->element, so we must rebuild full path first
645
+                /*
646
+				$ecmfile->filepath = $rel_dir;
647
+				$ecmfile->filename = $filename;
648
+				$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
649
+				$ecmfile->fullpath_orig = '';
650
+				$ecmfile->gen_or_uploaded = 'generated';
651
+				$ecmfile->description = '';    // indexed content
652
+				$ecmfile->keyword = '';        // keyword content
653
+				$ecmfile->share = getRandomPassword(true);
654
+				$result = $ecmfile->create($user);
655
+				if ($result < 0)
2256 656
 				{
2257
-					foreach($rows as $key => $row)
2258
-					{
2259
-						$this->updateRangOfLine($row, ($key+1));
2260
-					}
657
+					$this->error = $ecmfile->error;
658
+					$this->errors = $ecmfile->errors;
2261 659
 				}
2262
-			}
2263
-			else
2264
-			{
2265
-				dol_print_error($this->db);
2266
-			}
2267
-		}
2268
-		return 1;
2269
-	}
2270
-
2271
-	/**
2272
-	 * 	Get children of line
2273
-	 *
2274
-	 * 	@param	int		$id		Id of parent line
2275
-	 * 	@return	array			Array with list of children lines id
2276
-	 */
2277
-	function getChildrenOfLine($id)
2278
-	{
2279
-		$rows=array();
2280
-
2281
-		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2282
-		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2283
-		$sql.= ' AND fk_parent_line = '.$id;
2284
-		$sql.= ' ORDER BY rang ASC';
2285
-
2286
-		dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id."", LOG_DEBUG);
2287
-		$resql = $this->db->query($sql);
2288
-		if ($resql)
2289
-		{
2290
-			$i=0;
2291
-			$num = $this->db->num_rows($resql);
2292
-			while ($i < $num)
2293
-			{
2294
-				$row = $this->db->fetch_row($resql);
2295
-				$rows[$i] = $row[0];
2296
-				$i++;
2297
-			}
2298
-		}
660
+				*/
661
+            }
662
+            else return '';
663
+        }
664
+        elseif (empty($ecmfile->share))
665
+        {
666
+            // Add entry into index
667
+            if ($initsharekey)
668
+            {
669
+                require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
670
+                $ecmfile->share = getRandomPassword(true);
671
+                $ecmfile->update($user);
672
+            }
673
+            else return '';
674
+        }
2299 675
 
2300
-		return $rows;
2301
-	}
676
+        // Define $urlwithroot
677
+        $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
678
+        $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain name found into config file
679
+        //$urlwithroot=DOL_MAIN_URL_ROOT;					// This is to use same domain name than current
2302 680
 
2303
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2304
-	/**
2305
-	 * 	Update a line to have a lower rank
2306
-	 *
2307
-	 * 	@param 	int			$rowid				Id of line
2308
-	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2309
-	 * 	@return	void
2310
-	 */
2311
-	function line_up($rowid, $fk_parent_line=true)
2312
-	{
2313
-        // phpcs:enable
2314
-		$this->line_order(false, 'ASC', $fk_parent_line);
681
+        $forcedownload=0;
2315 682
 
2316
-		// Get rang of line
2317
-		$rang = $this->getRangOfLine($rowid);
683
+        $paramlink='';
684
+        //if (! empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart;		// For sharing with hash (so public files), modulepart is not required.
685
+        //if (! empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; 					// For sharing with hash (so public files), entity is not required.
686
+        //$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath);								// No need of name of file for public link, we will use the hash
687
+        if (! empty($ecmfile->share)) $paramlink.=($paramlink?'&':'').'hashp='.$ecmfile->share;			// Hash for public share
688
+        if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1';
2318 689
 
2319
-		// Update position of line
2320
-		$this->updateLineUp($rowid, $rang);
2321
-	}
690
+        if ($relativelink)
691
+        {
692
+            $linktoreturn='document.php'.($paramlink?'?'.$paramlink:'');
693
+        }
694
+        else
695
+        {
696
+            $linktoreturn=$urlwithroot.'/document.php'.($paramlink?'?'.$paramlink:'');
697
+        }
2322 698
 
2323
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2324
-	/**
2325
-	 * 	Update a line to have a higher rank
2326
-	 *
2327
-	 * 	@param	int			$rowid				Id of line
2328
-	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2329
-	 * 	@return	void
2330
-	 */
2331
-	function line_down($rowid, $fk_parent_line=true)
2332
-	{
2333
-        // phpcs:enable
2334
-		$this->line_order(false, 'ASC', $fk_parent_line);
2335
-
2336
-		// Get rang of line
2337
-		$rang = $this->getRangOfLine($rowid);
2338
-
2339
-		// Get max value for rang
2340
-		$max = $this->line_max();
2341
-
2342
-		// Update position of line
2343
-		$this->updateLineDown($rowid, $rang, $max);
2344
-	}
2345
-
2346
-	/**
2347
-	 * 	Update position of line (rang)
2348
-	 *
2349
-	 * 	@param	int		$rowid		Id of line
2350
-	 * 	@param	int		$rang		Position
2351
-	 * 	@return	void
2352
-	 */
2353
-	function updateRangOfLine($rowid,$rang)
2354
-	{
2355
-		$fieldposition = 'rang';
2356
-		if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2357
-
2358
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2359
-		$sql.= ' WHERE rowid = '.$rowid;
2360
-
2361
-		dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
2362
-		if (! $this->db->query($sql))
2363
-		{
2364
-			dol_print_error($this->db);
2365
-		}
2366
-	}
699
+        // Here $ecmfile->share is defined
700
+        return $linktoreturn;
701
+    }
2367 702
 
2368
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2369
-	/**
2370
-	 * 	Update position of line with ajax (rang)
2371
-	 *
2372
-	 * 	@param	array	$rows	Array of rows
2373
-	 * 	@return	void
2374
-	 */
2375
-	function line_ajaxorder($rows)
2376
-	{
2377
-        // phpcs:enable
2378
-		$num = count($rows);
2379
-		for ($i = 0 ; $i < $num ; $i++)
2380
-		{
2381
-			$this->updateRangOfLine($rows[$i], ($i+1));
2382
-		}
2383
-	}
2384
-
2385
-	/**
2386
-	 * 	Update position of line up (rang)
2387
-	 *
2388
-	 * 	@param	int		$rowid		Id of line
2389
-	 * 	@param	int		$rang		Position
2390
-	 * 	@return	void
2391
-	 */
2392
-	function updateLineUp($rowid,$rang)
2393
-	{
2394
-		if ($rang > 1)
2395
-		{
2396
-			$fieldposition = 'rang';
2397
-			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2398
-
2399
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang ;
2400
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2401
-			$sql.= ' AND rang = '.($rang - 1);
2402
-			if ($this->db->query($sql) )
2403
-			{
2404
-				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang - 1);
2405
-				$sql.= ' WHERE rowid = '.$rowid;
2406
-				if (! $this->db->query($sql) )
2407
-				{
2408
-					dol_print_error($this->db);
2409
-				}
2410
-			}
2411
-			else
2412
-			{
2413
-				dol_print_error($this->db);
2414
-			}
2415
-		}
2416
-	}
2417
-
2418
-	/**
2419
-	 * 	Update position of line down (rang)
2420
-	 *
2421
-	 * 	@param	int		$rowid		Id of line
2422
-	 * 	@param	int		$rang		Position
2423
-	 * 	@param	int		$max		Max
2424
-	 * 	@return	void
2425
-	 */
2426
-	function updateLineDown($rowid,$rang,$max)
2427
-	{
2428
-		if ($rang < $max)
2429
-		{
2430
-			$fieldposition = 'rang';
2431
-			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2432
-
2433
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2434
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2435
-			$sql.= ' AND rang = '.($rang+1);
2436
-			if ($this->db->query($sql) )
2437
-			{
2438
-				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang+1);
2439
-				$sql.= ' WHERE rowid = '.$rowid;
2440
-				if (! $this->db->query($sql) )
2441
-				{
2442
-					dol_print_error($this->db);
2443
-				}
2444
-			}
2445
-			else
2446
-			{
2447
-				dol_print_error($this->db);
2448
-			}
2449
-		}
2450
-	}
2451
-
2452
-	/**
2453
-	 * 	Get position of line (rang)
2454
-	 *
2455
-	 * 	@param		int		$rowid		Id of line
2456
-	 *  @return		int     			Value of rang in table of lines
2457
-	 */
2458
-	function getRangOfLine($rowid)
2459
-	{
2460
-		$sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2461
-		$sql.= ' WHERE rowid ='.$rowid;
2462
-
2463
-		dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
2464
-		$resql = $this->db->query($sql);
2465
-		if ($resql)
2466
-		{
2467
-			$row = $this->db->fetch_row($resql);
2468
-			return $row[0];
2469
-		}
2470
-	}
2471
-
2472
-	/**
2473
-	 * 	Get rowid of the line relative to its position
2474
-	 *
2475
-	 * 	@param		int		$rang		Rang value
2476
-	 *  @return     int     			Rowid of the line
2477
-	 */
2478
-	function getIdOfLine($rang)
2479
-	{
2480
-		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2481
-		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2482
-		$sql.= ' AND rang = '.$rang;
2483
-		$resql = $this->db->query($sql);
2484
-		if ($resql)
2485
-		{
2486
-			$row = $this->db->fetch_row($resql);
2487
-			return $row[0];
2488
-		}
2489
-	}
2490 703
 
2491 704
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2492
-	/**
2493
-	 * 	Get max value used for position of line (rang)
2494
-	 *
2495
-	 * 	@param		int		$fk_parent_line		Parent line id
2496
-	 *  @return     int  			   			Max value of rang in table of lines
2497
-	 */
2498
-	function line_max($fk_parent_line=0)
2499
-	{
705
+    /**
706
+     *  Add a link between element $this->element and a contact
707
+     *
708
+     *  @param	int		$fk_socpeople       Id of thirdparty contact (if source = 'external') or id of user (if souce = 'internal') to link
709
+     *  @param 	int		$type_contact 		Type of contact (code or id). Must be id or code found into table llx_c_type_contact. For example: SALESREPFOLL
710
+     *  @param  string	$source             external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
711
+     *  @param  int		$notrigger			Disable all triggers
712
+     *  @return int                 		<0 if KO, >0 if OK
713
+     */
714
+    function add_contact($fk_socpeople, $type_contact, $source='external',$notrigger=0)
715
+    {
2500 716
         // phpcs:enable
2501
-		// Search the last rang with fk_parent_line
2502
-		if ($fk_parent_line)
2503
-		{
2504
-			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2505
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2506
-			$sql.= ' AND fk_parent_line = '.$fk_parent_line;
2507
-
2508
-			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2509
-			$resql = $this->db->query($sql);
2510
-			if ($resql)
2511
-			{
2512
-				$row = $this->db->fetch_row($resql);
2513
-				if (! empty($row[0]))
2514
-				{
2515
-					return $row[0];
2516
-				}
2517
-				else
2518
-				{
2519
-					return $this->getRangOfLine($fk_parent_line);
2520
-				}
2521
-			}
2522
-		}
2523
-		// If not, search the last rang of element
2524
-		else
2525
-		{
2526
-			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2527
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2528
-
2529
-			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2530
-			$resql = $this->db->query($sql);
2531
-			if ($resql)
2532
-			{
2533
-				$row = $this->db->fetch_row($resql);
2534
-				return $row[0];
2535
-			}
2536
-		}
2537
-	}
717
+        global $user,$langs;
2538 718
 
2539
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2540
-	/**
2541
-	 *  Update external ref of element
2542
-	 *
2543
-	 *  @param      string		$ref_ext	Update field ref_ext
2544
-	 *  @return     int      		   		<0 if KO, >0 if OK
2545
-	 */
2546
-	function update_ref_ext($ref_ext)
2547
-	{
2548
-        // phpcs:enable
2549
-		if (! $this->table_element)
2550
-		{
2551
-			dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
2552
-			return -1;
2553
-		}
2554
-
2555
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2556
-		$sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
2557
-		$sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id;
2558
-
2559
-		dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
2560
-		if ($this->db->query($sql))
2561
-		{
2562
-			$this->ref_ext = $ref_ext;
2563
-			return 1;
2564
-		}
2565
-		else
2566
-		{
2567
-			$this->error=$this->db->error();
2568
-			return -1;
2569
-		}
2570
-	}
2571 719
 
2572
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2573
-	/**
2574
-	 *  Update note of element
2575
-	 *
2576
-	 *  @param      string		$note		New value for note
2577
-	 *  @param		string		$suffix		'', '_public' or '_private'
2578
-	 *  @return     int      		   		<0 if KO, >0 if OK
2579
-	 */
2580
-	function update_note($note, $suffix='')
2581
-	{
2582
-        // phpcs:enable
2583
-		global $user;
2584
-
2585
-		if (! $this->table_element)
2586
-		{
2587
-			$this->error='update_note was called on objet with property table_element not defined';
2588
-			dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
2589
-			return -1;
2590
-		}
2591
-		if (! in_array($suffix,array('','_public','_private')))
2592
-		{
2593
-			$this->error='update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
2594
-			dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
2595
-			return -2;
2596
-		}
2597
-		// Special cas
2598
-		//var_dump($this->table_element);exit;
2599
-		if ($this->table_element == 'product') $suffix='';
2600
-
2601
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2602
-		$sql.= " SET note".$suffix." = ".(!empty($note)?("'".$this->db->escape($note)."'"):"NULL");
2603
-		$sql.= " ,".(in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))?"fk_user_mod":"fk_user_modif")." = ".$user->id;
2604
-		$sql.= " WHERE rowid =". $this->id;
2605
-
2606
-		dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
2607
-		if ($this->db->query($sql))
2608
-		{
2609
-			if ($suffix == '_public') $this->note_public = $note;
2610
-			else if ($suffix == '_private') $this->note_private = $note;
2611
-			else
2612
-			{
2613
-				$this->note = $note;      // deprecated
2614
-				$this->note_private = $note;
2615
-			}
2616
-			return 1;
2617
-		}
2618
-		else
2619
-		{
2620
-			$this->error=$this->db->lasterror();
2621
-			return -1;
2622
-		}
2623
-	}
720
+        dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger");
2624 721
 
2625
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2626
-	/**
2627
-	 * 	Update public note (kept for backward compatibility)
2628
-	 *
2629
-	 * @param      string		$note		New value for note
2630
-	 * @return     int      		   		<0 if KO, >0 if OK
2631
-	 * @deprecated
2632
-	 * @see update_note()
2633
-	 */
2634
-	function update_note_public($note)
2635
-	{
2636
-        // phpcs:enable
2637
-		return $this->update_note($note,'_public');
2638
-	}
722
+        // Check parameters
723
+        if ($fk_socpeople <= 0)
724
+        {
725
+            $langs->load("errors");
726
+            $this->error=$langs->trans("ErrorWrongValueForParameterX","1");
727
+            dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
728
+            return -1;
729
+        }
730
+        if (! $type_contact)
731
+        {
732
+            $langs->load("errors");
733
+            $this->error=$langs->trans("ErrorWrongValueForParameterX","2");
734
+            dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
735
+            return -2;
736
+        }
2639 737
 
2640
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2641
-	/**
2642
-	 *	Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
2643
-	 *  Must be called at end of methods addline or updateline.
2644
-	 *
2645
-	 *	@param	int		$exclspec          	>0 = Exclude special product (product_type=9)
2646
-	 *  @param  string	$roundingadjust    	'none'=Do nothing, 'auto'=Use default method (MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND if defined, or '0'), '0'=Force mode total of rounding, '1'=Force mode rounding of total
2647
-	 *  @param	int		$nodatabaseupdate	1=Do not update database. Update only properties of object.
2648
-	 *  @param	Societe	$seller				If roundingadjust is '0' or '1' or maybe 'auto', it means we recalculate total for lines before calculating total for object and for this, we need seller object.
2649
-	 *	@return	int    			           	<0 if KO, >0 if OK
2650
-	 */
2651
-	function update_price($exclspec=0,$roundingadjust='none',$nodatabaseupdate=0,$seller=null)
2652
-	{
2653
-        // phpcs:enable
2654
-		global $conf, $hookmanager, $action;
2655
-
2656
-		// Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
2657
-		$MODULE = "";
2658
-		if ($this->element == 'propal')
2659
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
2660
-		elseif ($this->element == 'order')
2661
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
2662
-		elseif ($this->element == 'facture')
2663
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
2664
-		elseif ($this->element == 'facture_fourn')
2665
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
2666
-		elseif ($this->element == 'order_supplier')
2667
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
2668
-		elseif ($this->element == 'supplier_proposal')
2669
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
2670
-
2671
-		if (! empty($MODULE)) {
2672
-			if (! empty($conf->global->$MODULE)) {
2673
-				$modsactivated = explode(',', $conf->global->$MODULE);
2674
-				foreach ($modsactivated as $mod) {
2675
-					if ($conf->$mod->enabled)
2676
-						return 1; // update was disabled by specific setup
2677
-				}
2678
-			}
2679
-		}
2680
-
2681
-		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2682
-
2683
-		if ($roundingadjust == '-1') $roundingadjust='auto';	// For backward compatibility
2684
-
2685
-		$forcedroundingmode=$roundingadjust;
2686
-		if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) $forcedroundingmode=$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND;
2687
-		elseif ($forcedroundingmode == 'auto') $forcedroundingmode='0';
2688
-
2689
-		$error=0;
2690
-
2691
-		$multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
2692
-
2693
-		// Define constants to find lines to sum
2694
-		$fieldtva='total_tva';
2695
-		$fieldlocaltax1='total_localtax1';
2696
-		$fieldlocaltax2='total_localtax2';
2697
-		$fieldup='subprice';
2698
-		if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
2699
-		{
2700
-			$fieldtva='tva';
2701
-			$fieldup='pu_ht';
2702
-		}
2703
-		if ($this->element == 'expensereport')
2704
-		{
2705
-			$fieldup='value_unit';
2706
-		}
2707
-
2708
-		$sql = 'SELECT rowid, qty, '.$fieldup.' as up, remise_percent, total_ht, '.$fieldtva.' as total_tva, total_ttc, '.$fieldlocaltax1.' as total_localtax1, '.$fieldlocaltax2.' as total_localtax2,';
2709
-		$sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
2710
-			if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent';
2711
-			$sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
2712
-		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2713
-		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2714
-		if ($exclspec)
2715
-		{
2716
-			$product_field='product_type';
2717
-			if ($this->table_element_line == 'contratdet') $product_field='';    // contratdet table has no product_type field
2718
-			if ($product_field) $sql.= ' AND '.$product_field.' <> 9';
2719
-		}
2720
-		$sql.= ' ORDER by rowid';	// We want to be sure to always use same order of line to not change lines differently when option MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND is used
2721
-
2722
-		dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2723
-		$resql = $this->db->query($sql);
2724
-		if ($resql)
2725
-		{
2726
-			$this->total_ht  = 0;
2727
-			$this->total_tva = 0;
2728
-			$this->total_localtax1 = 0;
2729
-			$this->total_localtax2 = 0;
2730
-			$this->total_ttc = 0;
2731
-			$total_ht_by_vats  = array();
2732
-			$total_tva_by_vats = array();
2733
-			$total_ttc_by_vats = array();
2734
-			$this->multicurrency_total_ht	= 0;
2735
-			$this->multicurrency_total_tva	= 0;
2736
-			$this->multicurrency_total_ttc	= 0;
2737
-
2738
-			$num = $this->db->num_rows($resql);
2739
-			$i = 0;
2740
-			while ($i < $num)
2741
-			{
2742
-				$obj = $this->db->fetch_object($resql);
738
+        $id_type_contact=0;
739
+        if (is_numeric($type_contact))
740
+        {
741
+            $id_type_contact=$type_contact;
742
+        }
743
+        else
744
+        {
745
+            // We look for id type_contact
746
+            $sql = "SELECT tc.rowid";
747
+            $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
748
+            $sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
749
+            $sql.= " AND tc.source='".$this->db->escape($source)."'";
750
+            $sql.= " AND tc.code='".$this->db->escape($type_contact)."' AND tc.active=1";
751
+            //print $sql;
752
+            $resql=$this->db->query($sql);
753
+            if ($resql)
754
+            {
755
+                $obj = $this->db->fetch_object($resql);
756
+                if ($obj) $id_type_contact=$obj->rowid;
757
+            }
758
+        }
2743 759
 
2744
-				// Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
2745
-				$parameters=array('fk_element' => $obj->rowid);
2746
-				$reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
760
+        if ($id_type_contact == 0)
761
+        {
762
+            $this->error='CODE_NOT_VALID_FOR_THIS_ELEMENT';
763
+            dol_syslog("CODE_NOT_VALID_FOR_THIS_ELEMENT: Code type of contact '".$type_contact."' does not exists or is not active for element ".$this->element.", we can ignore it");
764
+            return -3;
765
+        }
2747 766
 
2748
-				if (empty($reshook) && $forcedroundingmode == '0')	// Check if data on line are consistent. This may solve lines that were not consistent because set with $forcedroundingmode='auto'
2749
-				{
2750
-					$localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx);
2751
-					$tmpcal=calcul_price_total($obj->qty, $obj->up, $obj->remise_percent, $obj->vatrate, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $obj->info_bits, $obj->product_type, $seller, $localtax_array, (isset($obj->situation_percent) ? $obj->situation_percent : 100), $multicurrency_tx);
2752
-					$diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1);
2753
-					if ($diff)
2754
-					{
2755
-						$sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid;
2756
-						dol_syslog('We found unconsistent data into detailed line (difference of '.$diff.') for line rowid = '.$obj->rowid." (total vat of line calculated=".$tmpcal[1].", database=".$obj->total_tva."). We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix);
2757
-								$resqlfix=$this->db->query($sqlfix);
2758
-								if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2759
-								$obj->total_tva = $tmpcal[1];
2760
-								$obj->total_ttc = $tmpcal[2];
2761
-						//
2762
-					}
2763
-				}
767
+        $datecreate = dol_now();
768
+
769
+        // Socpeople must have already been added by some trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error
770
+        $TListeContacts=$this->liste_contact(-1, $source);
771
+        $already_added=false;
772
+        if(!empty($TListeContacts)) {
773
+            foreach($TListeContacts as $array_contact) {
774
+                if($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) {
775
+                    $already_added=true;
776
+                    break;
777
+                }
778
+            }
779
+        }
2764 780
 
2765
-				$this->total_ht        += $obj->total_ht;		// The field visible at end of line detail
2766
-				$this->total_tva       += $obj->total_tva;
2767
-				$this->total_localtax1 += $obj->total_localtax1;
2768
-				$this->total_localtax2 += $obj->total_localtax2;
2769
-				$this->total_ttc       += $obj->total_ttc;
2770
-				$this->multicurrency_total_ht        += $obj->multicurrency_total_ht;		// The field visible at end of line detail
2771
-				$this->multicurrency_total_tva       += $obj->multicurrency_total_tva;
2772
-				$this->multicurrency_total_ttc       += $obj->multicurrency_total_ttc;
2773
-
2774
-				if (! isset($total_ht_by_vats[$obj->vatrate]))  $total_ht_by_vats[$obj->vatrate]=0;
2775
-				if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0;
2776
-				if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0;
2777
-				$total_ht_by_vats[$obj->vatrate]  += $obj->total_ht;
2778
-				$total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
2779
-				$total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
2780
-
2781
-				if ($forcedroundingmode == '1')	// Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency
2782
-				{
2783
-					$tmpvat=price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
2784
-					$diff=price2num($total_tva_by_vats[$obj->vatrate]-$tmpvat, 'MT', 1);
2785
-					//print 'Line '.$i.' rowid='.$obj->rowid.' vat_rate='.$obj->vatrate.' total_ht='.$obj->total_ht.' total_tva='.$obj->total_tva.' total_ttc='.$obj->total_ttc.' total_ht_by_vats='.$total_ht_by_vats[$obj->vatrate].' total_tva_by_vats='.$total_tva_by_vats[$obj->vatrate].' (new calculation = '.$tmpvat.') total_ttc_by_vats='.$total_ttc_by_vats[$obj->vatrate].($diff?" => DIFF":"")."<br>\n";
2786
-					if ($diff)
2787
-					{
2788
-						if (abs($diff) > 0.1) { dol_syslog('A rounding difference was detected into TOTAL but is too high to be corrected', LOG_WARNING); exit; }
2789
-						$sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".($obj->total_tva - $diff).", total_ttc = ".($obj->total_ttc - $diff)." WHERE rowid = ".$obj->rowid;
2790
-						dol_syslog('We found a difference of '.$diff.' for line rowid = '.$obj->rowid.". We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix);
2791
-								$resqlfix=$this->db->query($sqlfix);
2792
-								if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2793
-								$this->total_tva -= $diff;
2794
-								$this->total_ttc -= $diff;
2795
-								$total_tva_by_vats[$obj->vatrate] -= $diff;
2796
-								$total_ttc_by_vats[$obj->vatrate] -= $diff;
2797
-					}
2798
-				}
781
+        if(!$already_added) {
2799 782
 
2800
-				$i++;
2801
-			}
783
+            $this->db->begin();
2802 784
 
2803
-			// Add revenue stamp to total
2804
-			$this->total_ttc       			+= isset($this->revenuestamp)?$this->revenuestamp:0;
2805
-			$this->multicurrency_total_ttc  += isset($this->revenuestamp)?($this->revenuestamp * $multicurrency_tx):0;
785
+            // Insert into database
786
+            $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_contact";
787
+            $sql.= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) ";
788
+            $sql.= " VALUES (".$this->id.", ".$fk_socpeople." , " ;
789
+            $sql.= "'".$this->db->idate($datecreate)."'";
790
+            $sql.= ", 4, ". $id_type_contact;
791
+            $sql.= ")";
2806 792
 
2807
-			// Situations totals
2808
-			if ($this->situation_cycle_ref && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE )
2809
-			{
2810
-				$prev_sits = $this->get_prev_sits();
2811
-
2812
-				foreach ($prev_sits as $sit) {				// $sit is an object Facture loaded with a fetch.
2813
-					$this->total_ht -= $sit->total_ht;
2814
-					$this->total_tva -= $sit->total_tva;
2815
-					$this->total_localtax1 -= $sit->total_localtax1;
2816
-					$this->total_localtax2 -= $sit->total_localtax2;
2817
-					$this->total_ttc -= $sit->total_ttc;
2818
-					$this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
2819
-					$this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
2820
-					$this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
2821
-				}
2822
-			}
2823
-
2824
-			$this->db->free($resql);
2825
-
2826
-			// Now update global field total_ht, total_ttc and tva
2827
-			$fieldht='total_ht';
2828
-			$fieldtva='tva';
2829
-			$fieldlocaltax1='localtax1';
2830
-			$fieldlocaltax2='localtax2';
2831
-			$fieldttc='total_ttc';
2832
-			// Specific code for backward compatibility with old field names
2833
-			if ($this->element == 'facture' || $this->element == 'facturerec')             $fieldht='total';
2834
-			if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva';
2835
-			if ($this->element == 'propal')                                                $fieldttc='total';
2836
-			if ($this->element == 'expensereport')                                         $fieldtva='total_tva';
2837
-			if ($this->element == 'supplier_proposal')                                     $fieldttc='total';
2838
-
2839
-			if (empty($nodatabaseupdate))
2840
-			{
2841
-				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
2842
-				$sql .= " ".$fieldht."='".price2num($this->total_ht)."',";
2843
-				$sql .= " ".$fieldtva."='".price2num($this->total_tva)."',";
2844
-				$sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',";
2845
-				$sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',";
2846
-				$sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'";
2847
-						$sql .= ", multicurrency_total_ht='".price2num($this->multicurrency_total_ht, 'MT', 1)."'";
2848
-						$sql .= ", multicurrency_total_tva='".price2num($this->multicurrency_total_tva, 'MT', 1)."'";
2849
-						$sql .= ", multicurrency_total_ttc='".price2num($this->multicurrency_total_ttc, 'MT', 1)."'";
2850
-				$sql .= ' WHERE rowid = '.$this->id;
2851
-
2852
-
2853
-				dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2854
-				$resql=$this->db->query($sql);
2855
-				if (! $resql)
2856
-				{
2857
-					$error++;
2858
-					$this->error=$this->db->lasterror();
2859
-					$this->errors[]=$this->db->lasterror();
2860
-				}
2861
-			}
793
+            $resql=$this->db->query($sql);
794
+            if ($resql)
795
+            {
796
+                if (! $notrigger)
797
+                {
798
+                    $result=$this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user);
799
+                    if ($result < 0)
800
+                    {
801
+                        $this->db->rollback();
802
+                        return -1;
803
+                    }
804
+                }
805
+
806
+                $this->db->commit();
807
+                return 1;
808
+            }
809
+            else
810
+            {
811
+                if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
812
+                {
813
+                    $this->error=$this->db->errno();
814
+                    $this->db->rollback();
815
+                    echo 'err rollback';
816
+                    return -2;
817
+                }
818
+                else
819
+                {
820
+                    $this->error=$this->db->error();
821
+                    $this->db->rollback();
822
+                    return -1;
823
+                }
824
+            }
825
+        } else return 0;
826
+    }
2862 827
 
2863
-			if (! $error)
2864
-			{
2865
-				return 1;
2866
-			}
2867
-			else
2868
-			{
2869
-				return -1;
2870
-			}
2871
-		}
2872
-		else
2873
-		{
2874
-			dol_print_error($this->db,'Bad request in update_price');
2875
-			return -1;
2876
-		}
2877
-	}
828
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
829
+    /**
830
+     *    Copy contact from one element to current
831
+     *
832
+     *    @param    CommonObject    $objFrom    Source element
833
+     *    @param    string          $source     Nature of contact ('internal' or 'external')
834
+     *    @return   int                         >0 if OK, <0 if KO
835
+     */
836
+    function copy_linked_contact($objFrom, $source='internal')
837
+    {
838
+        // phpcs:enable
839
+        $contacts = $objFrom->liste_contact(-1, $source);
840
+        foreach($contacts as $contact)
841
+        {
842
+            if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0)
843
+            {
844
+                $this->error=$this->db->lasterror();
845
+                return -1;
846
+            }
847
+        }
848
+        return 1;
849
+    }
2878 850
 
2879 851
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2880
-	/**
2881
-	 *	Add objects linked in llx_element_element.
2882
-	 *
2883
-	 *	@param		string	$origin		Linked element type
2884
-	 *	@param		int		$origin_id	Linked element id
2885
-	 *	@return		int					<=0 if KO, >0 if OK
2886
-	 *	@see		fetchObjectLinked, updateObjectLinked, deleteObjectLinked
2887
-	 */
2888
-	function add_object_linked($origin=null, $origin_id=null)
2889
-	{
852
+    /**
853
+     *      Update a link to contact line
854
+     *
855
+     *      @param	int		$rowid              Id of line contact-element
856
+     * 		@param	int		$statut	            New status of link
857
+     *      @param  int		$type_contact_id    Id of contact type (not modified if 0)
858
+     *      @param  int		$fk_socpeople	    Id of soc_people to update (not modified if 0)
859
+     *      @return int                 		<0 if KO, >= 0 if OK
860
+     */
861
+    function update_contact($rowid, $statut, $type_contact_id=0, $fk_socpeople=0)
862
+    {
2890 863
         // phpcs:enable
2891
-		$origin = (! empty($origin) ? $origin : $this->origin);
2892
-		$origin_id = (! empty($origin_id) ? $origin_id : $this->origin_id);
2893
-
2894
-		// Special case
2895
-		if ($origin == 'order') $origin='commande';
2896
-		if ($origin == 'invoice') $origin='facture';
2897
-		if ($origin == 'invoice_template') $origin='facturerec';
2898
-    	if ($origin == 'supplierorder') $origin='order_supplier';
2899
-		$this->db->begin();
2900
-
2901
-		$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
2902
-		$sql.= "fk_source";
2903
-		$sql.= ", sourcetype";
2904
-		$sql.= ", fk_target";
2905
-		$sql.= ", targettype";
2906
-		$sql.= ") VALUES (";
2907
-		$sql.= $origin_id;
2908
-		$sql.= ", '".$this->db->escape($origin)."'";
2909
-		$sql.= ", ".$this->id;
2910
-		$sql.= ", '".$this->db->escape($this->element)."'";
2911
-		$sql.= ")";
2912
-
2913
-		dol_syslog(get_class($this)."::add_object_linked", LOG_DEBUG);
2914
-		if ($this->db->query($sql))
2915
-	  	{
2916
-	  		$this->db->commit();
2917
-	  		return 1;
2918
-	  	}
2919
-	  	else
2920
-	  	{
2921
-	  		$this->error=$this->db->lasterror();
2922
-	  		$this->db->rollback();
2923
-	  		return 0;
2924
-	  	}
2925
-	}
2926
-
2927
-	/**
2928
-	 *	Fetch array of objects linked to current object (object of enabled modules only). Links are loaded into
2929
-	 *		this->linkedObjectsIds array and
2930
-	 *		this->linkedObjects array if $loadalsoobjects = 1
2931
-	 *  Possible usage for parameters:
2932
-	 *  - all parameters empty -> we look all link to current object (current object can be source or target)
2933
-	 *  - source id+type -> will get target list linked to source
2934
-	 *  - target id+type -> will get source list linked to target
2935
-	 *  - source id+type + target type -> will get target list of the type
2936
-	 *  - target id+type + target source -> will get source list of the type
2937
-	 *
2938
-	 *	@param	int		$sourceid			Object source id (if not defined, id of object)
2939
-	 *	@param  string	$sourcetype			Object source type (if not defined, element name of object)
2940
-	 *	@param  int		$targetid			Object target id (if not defined, id of object)
2941
-	 *	@param  string	$targettype			Object target type (if not defined, elemennt name of object)
2942
-	 *	@param  string	$clause				'OR' or 'AND' clause used when both source id and target id are provided
2943
-	 *  @param  int		$alsosametype		0=Return only links to object that differs from source type. 1=Include also link to objects of same type.
2944
-	 *  @param  string	$orderby			SQL 'ORDER BY' clause
2945
-	 *  @param	int		$loadalsoobjects	Load also array this->linkedObjects (Use 0 to increase performances)
2946
-	 *	@return int							<0 if KO, >0 if OK
2947
-	 *  @see	add_object_linked, updateObjectLinked, deleteObjectLinked
2948
-	 */
2949
-	function fetchObjectLinked($sourceid=null,$sourcetype='',$targetid=null,$targettype='',$clause='OR',$alsosametype=1,$orderby='sourcetype',$loadalsoobjects=1)
2950
-	{
2951
-		global $conf;
2952
-
2953
-		$this->linkedObjectsIds=array();
2954
-		$this->linkedObjects=array();
2955
-
2956
-		$justsource=false;
2957
-		$justtarget=false;
2958
-		$withtargettype=false;
2959
-		$withsourcetype=false;
2960
-
2961
-		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid))
2962
-		{
2963
-			$justsource=true;  // the source (id and type) is a search criteria
2964
-			if (! empty($targettype)) $withtargettype=true;
2965
-		}
2966
-		if (! empty($targetid) && ! empty($targettype) && empty($sourceid))
2967
-		{
2968
-			$justtarget=true;  // the target (id and type) is a search criteria
2969
-			if (! empty($sourcetype)) $withsourcetype=true;
2970
-		}
2971
-
2972
-		$sourceid = (! empty($sourceid) ? $sourceid : $this->id);
2973
-		$targetid = (! empty($targetid) ? $targetid : $this->id);
2974
-		$sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
2975
-		$targettype = (! empty($targettype) ? $targettype : $this->element);
2976
-
2977
-		/*if (empty($sourceid) && empty($targetid))
2978
-		 {
2979
-		 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
2980
-		 return -1;
2981
-		 }*/
864
+        // Insert into database
865
+        $sql = "UPDATE ".MAIN_DB_PREFIX."element_contact set";
866
+        $sql.= " statut = ".$statut;
867
+        if ($type_contact_id) $sql.= ", fk_c_type_contact = '".$type_contact_id ."'";
868
+        if ($fk_socpeople) $sql.= ", fk_socpeople = '".$fk_socpeople ."'";
869
+        $sql.= " where rowid = ".$rowid;
870
+        $resql=$this->db->query($sql);
871
+        if ($resql)
872
+        {
873
+            return 0;
874
+        }
875
+        else
876
+        {
877
+            $this->error=$this->db->lasterror();
878
+            return -1;
879
+        }
880
+    }
2982 881
 
2983
-		// Links between objects are stored in table element_element
2984
-		$sql = 'SELECT rowid, fk_source, sourcetype, fk_target, targettype';
2985
-		$sql.= ' FROM '.MAIN_DB_PREFIX.'element_element';
2986
-		$sql.= " WHERE ";
2987
-		if ($justsource || $justtarget)
2988
-		{
2989
-			if ($justsource)
2990
-			{
2991
-				$sql.= "fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."'";
2992
-				if ($withtargettype) $sql.= " AND targettype = '".$targettype."'";
2993
-			}
2994
-			else if ($justtarget)
2995
-			{
2996
-				$sql.= "fk_target = ".$targetid." AND targettype = '".$targettype."'";
2997
-				if ($withsourcetype) $sql.= " AND sourcetype = '".$sourcetype."'";
2998
-			}
2999
-		}
3000
-		else
3001
-		{
3002
-			$sql.= "(fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."')";
3003
-			$sql.= " ".$clause." (fk_target = ".$targetid." AND targettype = '".$targettype."')";
3004
-		}
3005
-		$sql .= ' ORDER BY '.$orderby;
3006
-
3007
-		dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG);
3008
-		$resql = $this->db->query($sql);
3009
-		if ($resql)
3010
-		{
3011
-			$num = $this->db->num_rows($resql);
3012
-			$i = 0;
3013
-			while ($i < $num)
3014
-			{
3015
-				$obj = $this->db->fetch_object($resql);
3016
-				if ($justsource || $justtarget)
3017
-				{
3018
-					if ($justsource)
3019
-					{
3020
-						$this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3021
-					}
3022
-					else if ($justtarget)
3023
-					{
3024
-						$this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3025
-					}
3026
-				}
3027
-				else
3028
-				{
3029
-					if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype)
3030
-					{
3031
-						$this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3032
-					}
3033
-					if ($obj->fk_target == $targetid && $obj->targettype == $targettype)
3034
-					{
3035
-						$this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3036
-					}
3037
-				}
3038
-				$i++;
3039
-			}
882
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
883
+    /**
884
+     *    Delete a link to contact line
885
+     *
886
+     *    @param	int		$rowid			Id of contact link line to delete
887
+     *    @param	int		$notrigger		Disable all triggers
888
+     *    @return   int						>0 if OK, <0 if KO
889
+     */
890
+    function delete_contact($rowid, $notrigger=0)
891
+    {
892
+        // phpcs:enable
893
+        global $user;
3040 894
 
3041
-			if (! empty($this->linkedObjectsIds))
3042
-			{
3043
-				$tmparray = $this->linkedObjectsIds;
3044
-				foreach($tmparray as $objecttype => $objectids)       // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
3045
-				{
3046
-					// Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
3047
-					$module = $element = $subelement = $objecttype;
3048
-					if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
3049
-						&& preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
3050
-					{
3051
-						$module = $element = $regs[1];
3052
-						$subelement = $regs[2];
3053
-					}
3054
-
3055
-					$classpath = $element.'/class';
3056
-					// To work with non standard classpath or module name
3057
-					if ($objecttype == 'facture')			{
3058
-						$classpath = 'compta/facture/class';
3059
-					}
3060
-					else if ($objecttype == 'facturerec')			{
3061
-						$classpath = 'compta/facture/class'; $module = 'facture';
3062
-					}
3063
-					else if ($objecttype == 'propal')			{
3064
-						$classpath = 'comm/propal/class';
3065
-					}
3066
-					else if ($objecttype == 'supplier_proposal')			{
3067
-						$classpath = 'supplier_proposal/class';
3068
-					}
3069
-					else if ($objecttype == 'shipping')			{
3070
-						$classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon';
3071
-					}
3072
-					else if ($objecttype == 'delivery')			{
3073
-						$classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon';
3074
-					}
3075
-					else if ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier')	{
3076
-						$classpath = 'fourn/class'; $module = 'fournisseur';
3077
-					}
3078
-					else if ($objecttype == 'fichinter')			{
3079
-						$classpath = 'fichinter/class'; $subelement = 'fichinter'; $module = 'ficheinter';
3080
-					}
3081
-					else if ($objecttype == 'subscription')			{
3082
-						$classpath = 'adherents/class'; $module = 'adherent';
3083
-					}
3084
-
3085
-					// Set classfile
3086
-					$classfile = strtolower($subelement); $classname = ucfirst($subelement);
3087
-
3088
-					if ($objecttype == 'order') {
3089
-						$classfile = 'commande'; $classname = 'Commande';
3090
-					}
3091
-					else if ($objecttype == 'invoice_supplier') {
3092
-						$classfile = 'fournisseur.facture'; $classname = 'FactureFournisseur';
3093
-					}
3094
-					else if ($objecttype == 'order_supplier')   {
3095
-						$classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur';
3096
-					}
3097
-					else if ($objecttype == 'supplier_proposal')   {
3098
-						$classfile = 'supplier_proposal'; $classname = 'SupplierProposal';
3099
-					}
3100
-					else if ($objecttype == 'facturerec')   {
3101
-						$classfile = 'facture-rec'; $classname = 'FactureRec';
3102
-					}
3103
-					else if ($objecttype == 'subscription')   {
3104
-						$classfile = 'subscription'; $classname = 'Subscription';
3105
-					}
3106
-
3107
-					// Here $module, $classfile and $classname are set
3108
-					if ($conf->$module->enabled && (($element != $this->element) || $alsosametype))
3109
-					{
3110
-						if ($loadalsoobjects)
3111
-						{
3112
-							dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
3113
-							//print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
3114
-							if (class_exists($classname))
3115
-							{
3116
-								foreach($objectids as $i => $objectid)	// $i is rowid into llx_element_element
3117
-								{
3118
-									$object = new $classname($this->db);
3119
-									$ret = $object->fetch($objectid);
3120
-									if ($ret >= 0)
3121
-									{
3122
-										$this->linkedObjects[$objecttype][$i] = $object;
3123
-									}
3124
-								}
3125
-							}
3126
-						}
3127
-					}
3128
-					else
3129
-					{
3130
-						unset($this->linkedObjectsIds[$objecttype]);
3131
-					}
3132
-				}
3133
-			}
3134
-			return 1;
3135
-		}
3136
-		else
3137
-		{
3138
-			dol_print_error($this->db);
3139
-			return -1;
3140
-		}
3141
-	}
3142
-
3143
-	/**
3144
-	 *	Update object linked of a current object
3145
-	 *
3146
-	 *	@param	int		$sourceid		Object source id
3147
-	 *	@param  string	$sourcetype		Object source type
3148
-	 *	@param  int		$targetid		Object target id
3149
-	 *	@param  string	$targettype		Object target type
3150
-	 *	@return							int	>0 if OK, <0 if KO
3151
-	 *	@see	add_object_linked, fetObjectLinked, deleteObjectLinked
3152
-	 */
3153
-	function updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='')
3154
-	{
3155
-		$updatesource=false;
3156
-		$updatetarget=false;
3157
-
3158
-		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $updatesource=true;
3159
-		else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $updatetarget=true;
3160
-
3161
-		$sql = "UPDATE ".MAIN_DB_PREFIX."element_element SET ";
3162
-		if ($updatesource)
3163
-		{
3164
-			$sql.= "fk_source = ".$sourceid;
3165
-			$sql.= ", sourcetype = '".$this->db->escape($sourcetype)."'";
3166
-			$sql.= " WHERE fk_target = ".$this->id;
3167
-			$sql.= " AND targettype = '".$this->db->escape($this->element)."'";
3168
-		}
3169
-		else if ($updatetarget)
3170
-		{
3171
-			$sql.= "fk_target = ".$targetid;
3172
-			$sql.= ", targettype = '".$this->db->escape($targettype)."'";
3173
-			$sql.= " WHERE fk_source = ".$this->id;
3174
-			$sql.= " AND sourcetype = '".$this->db->escape($this->element)."'";
3175
-		}
3176
-
3177
-		dol_syslog(get_class($this)."::updateObjectLinked", LOG_DEBUG);
3178
-		if ($this->db->query($sql))
3179
-		{
3180
-			return 1;
3181
-		}
3182
-		else
3183
-		{
3184
-			$this->error=$this->db->lasterror();
3185
-			return -1;
3186
-		}
3187
-	}
3188
-
3189
-	/**
3190
-	 *	Delete all links between an object $this
3191
-	 *
3192
-	 *	@param	int		$sourceid		Object source id
3193
-	 *	@param  string	$sourcetype		Object source type
3194
-	 *	@param  int		$targetid		Object target id
3195
-	 *	@param  string	$targettype		Object target type
3196
-	 *  @param	int		$rowid			Row id of line to delete. If defined, other parameters are not used.
3197
-	 *	@return     					int	>0 if OK, <0 if KO
3198
-	 *	@see	add_object_linked, updateObjectLinked, fetchObjectLinked
3199
-	 */
3200
-	function deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
3201
-	{
3202
-		$deletesource=false;
3203
-		$deletetarget=false;
3204
-
3205
-		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $deletesource=true;
3206
-		else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $deletetarget=true;
3207
-
3208
-		$sourceid = (! empty($sourceid) ? $sourceid : $this->id);
3209
-		$sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
3210
-		$targetid = (! empty($targetid) ? $targetid : $this->id);
3211
-		$targettype = (! empty($targettype) ? $targettype : $this->element);
3212
-
3213
-		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_element";
3214
-		$sql.= " WHERE";
3215
-		if ($rowid > 0)
3216
-		{
3217
-			$sql.=" rowid = ".$rowid;
3218
-		}
3219
-		else
3220
-		{
3221
-			if ($deletesource)
3222
-			{
3223
-				$sql.= " fk_source = ".$sourceid." AND sourcetype = '".$this->db->escape($sourcetype)."'";
3224
-				$sql.= " AND fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."'";
3225
-			}
3226
-			else if ($deletetarget)
3227
-			{
3228
-				$sql.= " fk_target = ".$targetid." AND targettype = '".$this->db->escape($targettype)."'";
3229
-				$sql.= " AND fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."'";
3230
-			}
3231
-			else
3232
-			{
3233
-				$sql.= " (fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."')";
3234
-				$sql.= " OR";
3235
-				$sql.= " (fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."')";
3236
-			}
3237
-		}
3238
-
3239
-		dol_syslog(get_class($this)."::deleteObjectLinked", LOG_DEBUG);
3240
-		if ($this->db->query($sql))
3241
-		{
3242
-			return 1;
3243
-		}
3244
-		else
3245
-		{
3246
-			$this->error=$this->db->lasterror();
3247
-			$this->errors[]=$this->error;
3248
-			return -1;
3249
-		}
3250
-	}
3251
-
3252
-	/**
3253
-	 *      Set status of an object
3254
-	 *
3255
-	 *      @param	int		$status			Status to set
3256
-	 *      @param	int		$elementId		Id of element to force (use this->id by default)
3257
-	 *      @param	string	$elementType	Type of element to force (use this->table_element by default)
3258
-	 *      @param	string	$trigkey		Trigger key to use for trigger
3259
-	 *      @return int						<0 if KO, >0 if OK
3260
-	 */
3261
-	function setStatut($status, $elementId=null, $elementType='', $trigkey='')
3262
-	{
3263
-		global $user,$langs,$conf;
3264
-
3265
-		$savElementId=$elementId;  // To be used later to know if we were using the method using the id of this or not.
3266
-
3267
-		$elementId = (!empty($elementId)?$elementId:$this->id);
3268
-		$elementTable = (!empty($elementType)?$elementType:$this->table_element);
3269
-
3270
-		$this->db->begin();
3271
-
3272
-		$fieldstatus="fk_statut";
3273
-		if ($elementTable == 'facture_rec') $fieldstatus="suspended";
3274
-		if ($elementTable == 'mailing') $fieldstatus="statut";
3275
-		if ($elementTable == 'cronjob') $fieldstatus="status";
3276
-		if ($elementTable == 'user') $fieldstatus="statut";
3277
-		if ($elementTable == 'expensereport') $fieldstatus="fk_statut";
3278
-		if ($elementTable == 'commande_fournisseur_dispatch') $fieldstatus="status";
3279
-
3280
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable;
3281
-		$sql.= " SET ".$fieldstatus." = ".$status;
3282
-		// If status = 1 = validated, update also fk_user_valid
3283
-		if ($status == 1 && $elementTable == 'expensereport') $sql.=", fk_user_valid = ".$user->id;
3284
-		$sql.= " WHERE rowid=".$elementId;
3285
-
3286
-		dol_syslog(get_class($this)."::setStatut", LOG_DEBUG);
3287
-		if ($this->db->query($sql))
3288
-		{
3289
-			$error = 0;
3290
-
3291
-			// Try autoset of trigkey
3292
-			if (empty($trigkey))
3293
-			{
3294
-				if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_SIGN';   // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
3295
-				if ($this->element == 'supplier_proposal' && $status == 3) $trigkey='SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
3296
-				if ($this->element == 'supplier_proposal' && $status == 4) $trigkey='SUPPLIER_PROPOSAL_CLOSE';  // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
3297
-				if ($this->element == 'fichinter' && $status == 3) $trigkey='FICHINTER_CLASSIFY_DONE';
3298
-				if ($this->element == 'fichinter' && $status == 2) $trigkey='FICHINTER_CLASSIFY_BILLED';
3299
-				if ($this->element == 'fichinter' && $status == 1) $trigkey='FICHINTER_CLASSIFY_UNBILLED';
3300
-			}
3301
-
3302
-			if ($trigkey)
3303
-			{
3304
-				// Appel des triggers
3305
-				include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
3306
-				$interface=new Interfaces($this->db);
3307
-				$result=$interface->run_triggers($trigkey,$this,$user,$langs,$conf);
3308
-				if ($result < 0) {
3309
-					$error++; $this->errors=$interface->errors;
3310
-				}
3311
-				// Fin appel triggers
3312
-			}
3313 895
 
3314
-			if (! $error)
3315
-			{
3316
-				$this->db->commit();
896
+        $this->db->begin();
3317 897
 
3318
-				if (empty($savElementId))    // If the element we update was $this (so $elementId is null)
3319
-				{
3320
-					$this->statut = $status;
3321
-					$this->status = $status;
3322
-				}
898
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
899
+        $sql.= " WHERE rowid =".$rowid;
3323 900
 
3324
-				return 1;
3325
-			}
3326
-			else
3327
-			{
3328
-				$this->db->rollback();
3329
-				dol_syslog(get_class($this)."::setStatus ".$this->error,LOG_ERR);
3330
-				return -1;
3331
-			}
3332
-		}
3333
-		else
3334
-		{
3335
-			$this->error=$this->db->lasterror();
3336
-			$this->db->rollback();
3337
-			return -1;
3338
-		}
3339
-	}
3340
-
3341
-
3342
-	/**
3343
-	 *  Load type of canvas of an object if it exists
3344
-	 *
3345
-	 *  @param      int		$id     Record id
3346
-	 *  @param      string	$ref    Record ref
3347
-	 *  @return		int				<0 if KO, 0 if nothing done, >0 if OK
3348
-	 */
3349
-	function getCanvas($id=0,$ref='')
3350
-	{
3351
-		global $conf;
3352
-
3353
-		if (empty($id) && empty($ref)) return 0;
3354
-		if (! empty($conf->global->MAIN_DISABLE_CANVAS)) return 0;    // To increase speed. Not enabled by default.
3355
-
3356
-		// Clean parameters
3357
-		$ref = trim($ref);
3358
-
3359
-		$sql = "SELECT rowid, canvas";
3360
-		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
3361
-		$sql.= " WHERE entity IN (".getEntity($this->element).")";
3362
-		if (! empty($id))  $sql.= " AND rowid = ".$id;
3363
-		if (! empty($ref)) $sql.= " AND ref = '".$this->db->escape($ref)."'";
3364
-
3365
-		$resql = $this->db->query($sql);
3366
-		if ($resql)
3367
-		{
3368
-			$obj = $this->db->fetch_object($resql);
3369
-			if ($obj)
3370
-			{
3371
-				$this->canvas   = $obj->canvas;
3372
-				return 1;
3373
-			}
3374
-			else return 0;
3375
-		}
3376
-		else
3377
-		{
3378
-			dol_print_error($this->db);
3379
-			return -1;
3380
-		}
3381
-	}
3382
-
3383
-
3384
-	/**
3385
-	 * 	Get special code of a line
3386
-	 *
3387
-	 * 	@param	int		$lineid		Id of line
3388
-	 * 	@return	int					Special code
3389
-	 */
3390
-	function getSpecialCode($lineid)
3391
-	{
3392
-		$sql = 'SELECT special_code FROM '.MAIN_DB_PREFIX.$this->table_element_line;
3393
-		$sql.= ' WHERE rowid = '.$lineid;
3394
-		$resql = $this->db->query($sql);
3395
-		if ($resql)
3396
-		{
3397
-			$row = $this->db->fetch_row($resql);
3398
-			return $row[0];
3399
-		}
3400
-	}
3401
-
3402
-	/**
3403
-	 *  Function to check if an object is used by others.
3404
-	 *  Check is done into this->childtables. There is no check into llx_element_element.
3405
-	 *
3406
-	 *  @param	int		$id			Force id of object
3407
-	 *  @return	int					<0 if KO, 0 if not used, >0 if already used
3408
-	 */
3409
-	function isObjectUsed($id=0)
3410
-	{
3411
-		global $langs;
3412
-
3413
-		if (empty($id)) $id=$this->id;
3414
-
3415
-		// Check parameters
3416
-		if (! isset($this->childtables) || ! is_array($this->childtables) || count($this->childtables) == 0)
3417
-		{
3418
-			dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
3419
-			return -1;
3420
-		}
3421
-
3422
-		$arraytoscan = $this->childtables;
3423
-		// For backward compatibility, we check if array is old format array('table1', 'table2', ...)
3424
-		$tmparray=array_keys($this->childtables);
3425
-		if (is_numeric($tmparray[0]))
3426
-		{
3427
-			$arraytoscan = array_flip($this->childtables);
3428
-		}
3429
-
3430
-		// Test if child exists
3431
-		$haschild=0;
3432
-		foreach($arraytoscan as $table => $elementname)
3433
-		{
3434
-			//print $id.'-'.$table.'-'.$elementname.'<br>';
3435
-			// Check if third party can be deleted
3436
-			$sql = "SELECT COUNT(*) as nb from ".MAIN_DB_PREFIX.$table;
3437
-			$sql.= " WHERE ".$this->fk_element." = ".$id;
3438
-			$resql=$this->db->query($sql);
3439
-			if ($resql)
3440
-			{
3441
-				$obj=$this->db->fetch_object($resql);
3442
-				if ($obj->nb > 0)
3443
-				{
3444
-					$langs->load("errors");
3445
-					//print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
3446
-					$haschild += $obj->nb;
3447
-					if (is_numeric($elementname))	// old usage
3448
-					{
3449
-						$this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $table);
3450
-					}
3451
-					else	// new usage: $elementname=Translation key
3452
-					{
3453
-						$this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $langs->transnoentitiesnoconv($elementname));
3454
-					}
3455
-					break;    // We found at least one, we stop here
3456
-				}
3457
-			}
3458
-			else
3459
-			{
3460
-				$this->errors[]=$this->db->lasterror();
3461
-				return -1;
3462
-			}
3463
-		}
3464
-		if ($haschild > 0)
3465
-		{
3466
-			$this->errors[]="ErrorRecordHasChildren";
3467
-			return $haschild;
3468
-		}
3469
-		else return 0;
3470
-	}
3471
-
3472
-	/**
3473
-	 *  Function to say how many lines object contains
3474
-	 *
3475
-	 *	@param	int		$predefined		-1=All, 0=Count free product/service only, 1=Count predefined product/service only, 2=Count predefined product, 3=Count predefined service
3476
-	 *  @return	int						<0 if KO, 0 if no predefined products, nb of lines with predefined products if found
3477
-	 */
3478
-	function hasProductsOrServices($predefined=-1)
3479
-	{
3480
-		$nb=0;
3481
-
3482
-		foreach($this->lines as $key => $val)
3483
-		{
3484
-			$qualified=0;
3485
-			if ($predefined == -1) $qualified=1;
3486
-			if ($predefined == 1 && $val->fk_product > 0) $qualified=1;
3487
-			if ($predefined == 0 && $val->fk_product <= 0) $qualified=1;
3488
-			if ($predefined == 2 && $val->fk_product > 0 && $val->product_type==0) $qualified=1;
3489
-			if ($predefined == 3 && $val->fk_product > 0 && $val->product_type==1) $qualified=1;
3490
-			if ($qualified) $nb++;
3491
-		}
3492
-		dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
3493
-		return $nb;
3494
-	}
3495
-
3496
-	/**
3497
-	 * Function that returns the total amount HT of discounts applied for all lines.
3498
-	 *
3499
-	 * @return 	float
3500
-	 */
3501
-	function getTotalDiscount()
3502
-	{
3503
-		$total_discount=0.00;
3504
-
3505
-		$sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
3506
-		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."det";
3507
-		$sql.= " WHERE ".$this->fk_element." = ".$this->id;
3508
-
3509
-		dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
3510
-		$resql = $this->db->query($sql);
3511
-		if ($resql)
3512
-		{
3513
-			$num=$this->db->num_rows($resql);
3514
-			$i=0;
3515
-			while ($i < $num)
3516
-			{
3517
-				$obj = $this->db->fetch_object($resql);
3518
-
3519
-				$pu_ht = $obj->pu_ht;
3520
-				$qty= $obj->qty;
3521
-				$total_ht = $obj->total_ht;
3522
-
3523
-				$total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
3524
-				$total_discount += $total_discount_line;
3525
-
3526
-				$i++;
3527
-			}
3528
-		}
3529
-
3530
-		//print $total_discount; exit;
3531
-		return price2num($total_discount);
3532
-	}
3533
-
3534
-
3535
-	/**
3536
-	 * Return into unit=0, the calculated total of weight and volume of all lines * qty
3537
-	 * Calculate by adding weight and volume of each product line, so properties ->volume/volume_units/weight/weight_units must be loaded on line.
3538
-	 *
3539
-	 * @return  array                           array('weight'=>...,'volume'=>...)
3540
-	 */
3541
-	function getTotalWeightVolume()
3542
-	{
3543
-		$totalWeight = 0;
3544
-		$totalVolume = 0;
3545
-		// defined for shipment only
3546
-		$totalOrdered = '';
3547
-		// defined for shipment only
3548
-		$totalToShip = '';
3549
-
3550
-		foreach ($this->lines as $line)
3551
-		{
3552
-			if (isset($line->qty_asked))
3553
-			{
3554
-				if (empty($totalOrdered)) $totalOrdered=0;  // Avoid warning because $totalOrdered is ''
3555
-				$totalOrdered+=$line->qty_asked;    // defined for shipment only
3556
-			}
3557
-			if (isset($line->qty_shipped))
3558
-			{
3559
-				if (empty($totalToShip)) $totalToShip=0;    // Avoid warning because $totalToShip is ''
3560
-				$totalToShip+=$line->qty_shipped;   // defined for shipment only
3561
-            }else if ($line->element == 'commandefournisseurdispatch' && isset($line->qty))
901
+        dol_syslog(get_class($this)."::delete_contact", LOG_DEBUG);
902
+        if ($this->db->query($sql))
903
+        {
904
+            if (! $notrigger)
3562 905
             {
3563
-                if (empty($totalToShip)) $totalToShip=0;
3564
-                $totalToShip+=$line->qty;   // defined for reception only
3565
-			}
3566
-
3567
-			// Define qty, weight, volume, weight_units, volume_units
3568
-			if ($this->element == 'shipping') {
3569
-				// for shipments
3570
-				$qty = $line->qty_shipped ? $line->qty_shipped : 0;
3571
-			}
3572
-			else {
3573
-				$qty = $line->qty ? $line->qty : 0;
3574
-			}
3575
-
3576
-			$weight = $line->weight ? $line->weight : 0;
3577
-            ($weight==0 && !empty($line->product->weight))? $weight=$line->product->weight: 0;
3578
-			$volume = $line->volume ? $line->volume : 0;
3579
-			($volume==0 && !empty($line->product->volume))? $volume=$line->product->volume: 0;
906
+                $result=$this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user);
907
+                if ($result < 0) { $this->db->rollback(); return -1; }
908
+            }
3580 909
 
3581
-			$weight_units=$line->weight_units;
3582
-			($weight_units==0 && !empty($line->product->weight_units))? $weight_units=$line->product->weight_units: 0;
3583
-			$volume_units=$line->volume_units;
3584
-			($volume_units==0 && !empty($line->product->volume_units))? $volume_units=$line->product->volume_units: 0;
910
+            $this->db->commit();
911
+            return 1;
912
+        }
913
+        else
914
+        {
915
+            $this->error=$this->db->lasterror();
916
+            $this->db->rollback();
917
+            return -1;
918
+        }
919
+    }
3585 920
 
3586
-			$weightUnit=0;
3587
-			$volumeUnit=0;
3588
-			if (! empty($weight_units)) $weightUnit = $weight_units;
3589
-			if (! empty($volume_units)) $volumeUnit = $volume_units;
921
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
922
+    /**
923
+     *    Delete all links between an object $this and all its contacts
924
+     *
925
+     *	  @param	string	$source		'' or 'internal' or 'external'
926
+     *	  @param	string	$code		Type of contact (code or id)
927
+     *    @return   int					>0 if OK, <0 if KO
928
+     */
929
+    function delete_linked_contact($source='',$code='')
930
+    {
931
+        // phpcs:enable
932
+        $temp = array();
933
+        $typeContact = $this->liste_type_contact($source,'',0,0,$code);
3590 934
 
3591
-			if (empty($totalWeight)) $totalWeight=0;  // Avoid warning because $totalWeight is ''
3592
-			if (empty($totalVolume)) $totalVolume=0;  // Avoid warning because $totalVolume is ''
935
+        foreach($typeContact as $key => $value)
936
+        {
937
+            array_push($temp,$key);
938
+        }
939
+        $listId = implode(",", $temp);
3593 940
 
3594
-			//var_dump($line->volume_units);
3595
-			if ($weight_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3596
-			{
3597
-				$trueWeightUnit=pow(10, $weightUnit);
3598
-				$totalWeight += $weight * $qty * $trueWeightUnit;
3599
-			}
3600
-			else {
3601
-		if ($weight_units == 99) {
3602
-			// conversion 1 Pound = 0.45359237 KG
3603
-			$trueWeightUnit = 0.45359237;
3604
-			$totalWeight += $weight * $qty * $trueWeightUnit;
3605
-		} elseif ($weight_units == 98) {
3606
-			// conversion 1 Ounce = 0.0283495 KG
3607
-			$trueWeightUnit = 0.0283495;
3608
-			$totalWeight += $weight * $qty * $trueWeightUnit;
3609
-		}
3610
-		else
3611
-					$totalWeight += $weight * $qty;   // This may be wrong if we mix different units
3612
-			}
3613
-			if ($volume_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3614
-			{
3615
-				//print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
3616
-				$trueVolumeUnit=pow(10, $volumeUnit);
3617
-				//print $line->volume;
3618
-				$totalVolume += $volume * $qty * $trueVolumeUnit;
3619
-			}
3620
-			else
3621
-			{
3622
-				$totalVolume += $volume * $qty;   // This may be wrong if we mix different units
3623
-			}
3624
-		}
3625
-
3626
-		return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
3627
-	}
3628
-
3629
-
3630
-	/**
3631
-	 *	Set extra parameters
3632
-	 *
3633
-	 *	@return	int      <0 if KO, >0 if OK
3634
-	 */
3635
-	function setExtraParameters()
3636
-	{
3637
-		$this->db->begin();
3638
-
3639
-		$extraparams = (! empty($this->extraparams) ? json_encode($this->extraparams) : null);
3640
-
3641
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3642
-		$sql.= " SET extraparams = ".(! empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
3643
-		$sql.= " WHERE rowid = ".$this->id;
3644
-
3645
-		dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG);
3646
-		$resql = $this->db->query($sql);
3647
-		if (! $resql)
3648
-		{
3649
-			$this->error=$this->db->lasterror();
3650
-			$this->db->rollback();
3651
-			return -1;
3652
-		}
3653
-		else
3654
-		{
3655
-			$this->db->commit();
3656
-			return 1;
3657
-		}
3658
-	}
941
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
942
+        $sql.= " WHERE element_id = ".$this->id;
943
+        if ($listId)
944
+            $sql.= " AND fk_c_type_contact IN (".$listId.")";
3659 945
 
946
+        dol_syslog(get_class($this)."::delete_linked_contact", LOG_DEBUG);
947
+        if ($this->db->query($sql))
948
+        {
949
+            return 1;
950
+        }
951
+        else
952
+        {
953
+            $this->error=$this->db->lasterror();
954
+            return -1;
955
+        }
956
+    }
3660 957
 
3661 958
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3662
-	/**
3663
-	 *    Return incoterms informations
3664
-	 *    TODO Use a cache for label get
3665
-	 *
3666
-	 *    @return	string	incoterms info
3667
-	 */
3668
-	function display_incoterms()
3669
-	{
959
+    /**
960
+     *    Get array of all contacts for an object
961
+     *
962
+     *    @param	int			$statut		Status of links to get (-1=all)
963
+     *    @param	string		$source		Source of contact: external or thirdparty (llx_socpeople) or internal (llx_user)
964
+     *    @param	int         $list       0:Return array contains all properties, 1:Return array contains just id
965
+     *    @param    string      $code       Filter on this code of contact type ('SHIPPING', 'BILLING', ...)
966
+     *    @return	array|int		        Array of contacts, -1 if error
967
+     */
968
+    function liste_contact($statut=-1,$source='external',$list=0,$code='')
969
+    {
3670 970
         // phpcs:enable
3671
-		$out = '';
3672
-		$this->libelle_incoterms = '';
3673
-		if (!empty($this->fk_incoterms))
3674
-		{
3675
-			$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3676
-			$result = $this->db->query($sql);
3677
-			if ($result)
3678
-			{
3679
-				$res = $this->db->fetch_object($result);
3680
-				$out .= $res->code;
3681
-			}
3682
-		}
3683
-
3684
-		$out .= (($res->code && $this->location_incoterms)?' - ':'').$this->location_incoterms;
3685
-
3686
-		return $out;
3687
-	}
3688
-
3689
-	/**
3690
-	 *    Return incoterms informations for pdf display
3691
-	 *
3692
-	 *    @return	string		incoterms info
3693
-	 */
3694
-	function getIncotermsForPDF()
3695
-	{
3696
-		$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3697
-		$resql = $this->db->query($sql);
3698
-		if ($resql)
3699
-		{
3700
-			$num = $this->db->num_rows($resql);
3701
-			if ($num > 0)
3702
-			{
3703
-				$res = $this->db->fetch_object($resql);
3704
-				return 'Incoterm : '.$res->code.' - '.$this->location_incoterms;
3705
-			}
3706
-			else
3707
-			{
3708
-				return '';
3709
-			}
3710
-		}
3711
-		else
3712
-		{
3713
-			$this->errors[] = $this->db->lasterror();
3714
-			return false;
3715
-		}
3716
-	}
3717
-
3718
-	/**
3719
-	 *    Define incoterms values of current object
3720
-	 *
3721
-	 *    @param	int		$id_incoterm     Id of incoterm to set or '' to remove
3722
-	 * 	  @param 	string  $location		 location of incoterm
3723
-	 *    @return	int     		<0 if KO, >0 if OK
3724
-	 */
3725
-	function setIncoterms($id_incoterm, $location)
3726
-	{
3727
-		if ($this->id && $this->table_element)
3728
-		{
3729
-			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3730
-			$sql.= " SET fk_incoterms = ".($id_incoterm > 0 ? $id_incoterm : "null");
3731
-			$sql.= ", location_incoterms = ".($id_incoterm > 0 ? "'".$this->db->escape($location)."'" : "null");
3732
-			$sql.= " WHERE rowid = " . $this->id;
3733
-			dol_syslog(get_class($this).'::setIncoterms', LOG_DEBUG);
3734
-			$resql=$this->db->query($sql);
3735
-			if ($resql)
3736
-			{
3737
-				$this->fk_incoterms = $id_incoterm;
3738
-				$this->location_incoterms = $location;
3739
-
3740
-				$sql = 'SELECT libelle FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3741
-				$res = $this->db->query($sql);
3742
-				if ($res)
3743
-				{
3744
-					$obj = $this->db->fetch_object($res);
3745
-					$this->libelle_incoterms = $obj->libelle;
3746
-				}
3747
-				return 1;
3748
-			}
3749
-			else
3750
-			{
3751
-				$this->errors[] = $this->db->lasterror();
3752
-				return -1;
3753
-			}
3754
-		}
3755
-		else return -1;
3756
-	}
3757
-
3758
-
3759
-	// --------------------
3760
-	// TODO: All functions here must be redesigned and moved as they are not business functions but output functions
3761
-	// --------------------
3762
-
3763
-	/* This is to show add lines */
3764
-
3765
-	/**
3766
-	 *	Show add free and predefined products/services form
3767
-	 *
3768
-	 *  @param	int		        $dateSelector       1=Show also date range input fields
3769
-	 *  @param	Societe			$seller				Object thirdparty who sell
3770
-	 *  @param	Societe			$buyer				Object thirdparty who buy
3771
-	 *	@return	void
3772
-	 */
3773
-	function formAddObjectLine($dateSelector, $seller, $buyer)
3774
-	{
3775
-		global $conf,$user,$langs,$object,$hookmanager;
3776
-		global $form,$bcnd,$var;
3777
-
3778
-		// Line extrafield
3779
-		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3780
-		$extrafieldsline = new ExtraFields($this->db);
3781
-		$extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3782
-
3783
-		// Output template part (modules that overwrite templates must declare this into descriptor)
3784
-		// Use global variables + $dateSelector + $seller and $buyer
3785
-		$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
3786
-		foreach($dirtpls as $reldir)
3787
-		{
3788
-			$tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
3789
-			if (empty($conf->file->strict_mode)) {
3790
-				$res=@include $tpl;
3791
-			} else {
3792
-				$res=include $tpl; // for debug
3793
-			}
3794
-			if ($res) break;
3795
-		}
3796
-	}
3797
-
3798
-
3799
-
3800
-	/* This is to show array of line of details */
3801
-
3802
-
3803
-	/**
3804
-	 *	Return HTML table for object lines
3805
-	 *	TODO Move this into an output class file (htmlline.class.php)
3806
-	 *	If lines are into a template, title must also be into a template
3807
-	 *	But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
3808
-	 *
3809
-	 *	@param	string		$action				Action code
3810
-	 *	@param  string		$seller            	Object of seller third party
3811
-	 *	@param  string  	$buyer             	Object of buyer third party
3812
-	 *	@param	int			$selected		   	Object line selected
3813
-	 *	@param  int	    	$dateSelector      	1=Show also date range input fields
3814
-	 *	@return	void
3815
-	 */
3816
-	function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0)
3817
-	{
3818
-		global $conf, $hookmanager, $langs, $user;
3819
-		// TODO We should not use global var for this !
3820
-		global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
3821
-
3822
-		// Define usemargins
3823
-		$usemargins=0;
3824
-		if (! empty($conf->margin->enabled) && ! empty($this->element) && in_array($this->element,array('facture','propal','commande'))) $usemargins=1;
3825
-
3826
-		$num = count($this->lines);
3827
-
3828
-		// Line extrafield
3829
-		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3830
-		$extrafieldsline = new ExtraFields($this->db);
3831
-		$extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3832
-
3833
-		$parameters = array('num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3834
-		$reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3835
-		if (empty($reshook))
3836
-		{
3837
-			// Title line
3838
-		    print "<thead>\n";
3839
-
3840
-			print '<tr class="liste_titre nodrag nodrop">';
3841
-
3842
-			// Adds a line numbering column
3843
-			if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) print '<td class="linecolnum" align="center" width="5">&nbsp;</td>';
3844
-
3845
-			// Description
3846
-			print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
3847
-
3848
-			if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier')
3849
-			{
3850
-				print '<td class="linerefsupplier"><span id="title_fourn_ref">'.$langs->trans("SupplierRef").'</span></td>';
3851
-			}
3852
-
3853
-			// VAT
3854
-			print '<td class="linecolvat" align="right" width="80">'.$langs->trans('VAT').'</td>';
971
+        global $langs;
972
+
973
+        $tab=array();
974
+
975
+        $sql = "SELECT ec.rowid, ec.statut as statuslink, ec.fk_socpeople as id, ec.fk_c_type_contact";    // This field contains id of llx_socpeople or id of llx_user
976
+        if ($source == 'internal') $sql.=", '-1' as socid, t.statut as statuscontact, t.login, t.photo";
977
+        if ($source == 'external' || $source == 'thirdparty') $sql.=", t.fk_soc as socid, t.statut as statuscontact";
978
+        $sql.= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email";
979
+        $sql.= ", tc.source, tc.element, tc.code, tc.libelle";
980
+        $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
981
+        $sql.= ", ".MAIN_DB_PREFIX."element_contact ec";
982
+        if ($source == 'internal') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
983
+        if ($source == 'external'|| $source == 'thirdparty') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
984
+        $sql.= " WHERE ec.element_id =".$this->id;
985
+        $sql.= " AND ec.fk_c_type_contact=tc.rowid";
986
+        $sql.= " AND tc.element='".$this->db->escape($this->element)."'";
987
+        if ($code) $sql.= " AND tc.code = '".$this->db->escape($code)."'";
988
+        if ($source == 'internal') $sql.= " AND tc.source = 'internal'";
989
+        if ($source == 'external' || $source == 'thirdparty') $sql.= " AND tc.source = 'external'";
990
+        $sql.= " AND tc.active=1";
991
+        if ($statut >= 0) $sql.= " AND ec.statut = '".$statut."'";
992
+        $sql.=" ORDER BY t.lastname ASC";
993
+
994
+        dol_syslog(get_class($this)."::liste_contact", LOG_DEBUG);
995
+        $resql=$this->db->query($sql);
996
+        if ($resql)
997
+        {
998
+            $num=$this->db->num_rows($resql);
999
+            $i=0;
1000
+            while ($i < $num)
1001
+            {
1002
+                $obj = $this->db->fetch_object($resql);
1003
+
1004
+                if (! $list)
1005
+                {
1006
+                    $transkey="TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
1007
+                    $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1008
+                    $tab[$i]=array('source'=>$obj->source,'socid'=>$obj->socid,'id'=>$obj->id,
1009
+                                    'nom'=>$obj->lastname,      // For backward compatibility
1010
+                                    'civility'=>$obj->civility, 'lastname'=>$obj->lastname, 'firstname'=>$obj->firstname, 'email'=>$obj->email, 'login'=>$obj->login, 'photo'=>$obj->photo, 'statuscontact'=>$obj->statuscontact,
1011
+                                    'rowid'=>$obj->rowid, 'code'=>$obj->code, 'libelle'=>$libelle_type, 'status'=>$obj->statuslink, 'fk_c_type_contact'=>$obj->fk_c_type_contact);
1012
+                }
1013
+                else
1014
+                {
1015
+                    $tab[$i]=$obj->id;
1016
+                }
1017
+
1018
+                $i++;
1019
+            }
3855 1020
 
3856
-			// Price HT
3857
-			print '<td class="linecoluht" align="right" width="80">'.$langs->trans('PriceUHT').'</td>';
1021
+            return $tab;
1022
+        }
1023
+        else
1024
+        {
1025
+            $this->error=$this->db->lasterror();
1026
+            dol_print_error($this->db);
1027
+            return -1;
1028
+        }
1029
+    }
3858 1030
 
3859
-			// Multicurrency
3860
-			if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoluht_currency" align="right" width="80">'.$langs->trans('PriceUHTCurrency', $this->multicurrency_code).'</td>';
3861 1031
 
3862
-			if ($inputalsopricewithtax) print '<td align="right" width="80">'.$langs->trans('PriceUTTC').'</td>';
1032
+    /**
1033
+     * 		Update status of a contact linked to object
1034
+     *
1035
+     * 		@param	int		$rowid		Id of link between object and contact
1036
+     * 		@return	int					<0 if KO, >=0 if OK
1037
+     */
1038
+    function swapContactStatus($rowid)
1039
+    {
1040
+        $sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,";
1041
+        $sql.= " tc.code, tc.libelle";
1042
+        //$sql.= ", s.fk_soc";
1043
+        $sql.= " FROM (".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as tc)";
1044
+        //$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as s ON ec.fk_socpeople=s.rowid";	// Si contact de type external, alors il est lie a une societe
1045
+        $sql.= " WHERE ec.rowid =".$rowid;
1046
+        $sql.= " AND ec.fk_c_type_contact=tc.rowid";
1047
+        $sql.= " AND tc.element = '".$this->db->escape($this->element)."'";
1048
+
1049
+        dol_syslog(get_class($this)."::swapContactStatus", LOG_DEBUG);
1050
+        $resql=$this->db->query($sql);
1051
+        if ($resql)
1052
+        {
1053
+            $obj = $this->db->fetch_object($resql);
1054
+            $newstatut = ($obj->statut == 4) ? 5 : 4;
1055
+            $result = $this->update_contact($rowid, $newstatut);
1056
+            $this->db->free($resql);
1057
+            return $result;
1058
+        }
1059
+        else
1060
+        {
1061
+            $this->error=$this->db->error();
1062
+            dol_print_error($this->db);
1063
+            return -1;
1064
+        }
1065
+    }
3863 1066
 
3864
-			// Qty
3865
-			print '<td class="linecolqty" align="right">'.$langs->trans('Qty').'</td>';
1067
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1068
+    /**
1069
+     *      Return array with list of possible values for type of contacts
1070
+     *
1071
+     *      @param	string	$source     'internal', 'external' or 'all'
1072
+     *      @param	string	$order		Sort order by : 'position', 'code', 'rowid'...
1073
+     *      @param  int		$option     0=Return array id->label, 1=Return array code->label
1074
+     *      @param  int		$activeonly 0=all status of contact, 1=only the active
1075
+     *		@param	string	$code		Type of contact (Example: 'CUSTOMER', 'SERVICE')
1076
+     *      @return array       		Array list of type of contacts (id->label if option=0, code->label if option=1)
1077
+     */
1078
+    function liste_type_contact($source='internal', $order='position', $option=0, $activeonly=0, $code='')
1079
+    {
1080
+        // phpcs:enable
1081
+        global $langs;
1082
+
1083
+        if (empty($order)) $order='position';
1084
+        if ($order == 'position') $order.=',code';
1085
+
1086
+        $tab = array();
1087
+        $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position";
1088
+        $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
1089
+        $sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
1090
+        if ($activeonly == 1) $sql.= " AND tc.active=1"; // only the active types
1091
+        if (! empty($source) && $source != 'all') $sql.= " AND tc.source='".$this->db->escape($source)."'";
1092
+        if (! empty($code)) $sql.= " AND tc.code='".$this->db->escape($code)."'";
1093
+        $sql.= $this->db->order($order,'ASC');
1094
+
1095
+        //print "sql=".$sql;
1096
+        $resql=$this->db->query($sql);
1097
+        if ($resql)
1098
+        {
1099
+            $num=$this->db->num_rows($resql);
1100
+            $i=0;
1101
+            while ($i < $num)
1102
+            {
1103
+                $obj = $this->db->fetch_object($resql);
3866 1104
 
3867
-			if($conf->global->PRODUCT_USE_UNITS)
3868
-			{
3869
-				print '<td class="linecoluseunit" align="left">'.$langs->trans('Unit').'</td>';
3870
-			}
1105
+                $transkey="TypeContact_".$this->element."_".$source."_".$obj->code;
1106
+                $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1107
+                if (empty($option)) $tab[$obj->rowid]=$libelle_type;
1108
+                else $tab[$obj->code]=$libelle_type;
1109
+                $i++;
1110
+            }
1111
+            return $tab;
1112
+        }
1113
+        else
1114
+        {
1115
+            $this->error=$this->db->lasterror();
1116
+            //dol_print_error($this->db);
1117
+            return null;
1118
+        }
1119
+    }
3871 1120
 
3872
-			// Reduction short
3873
-			print '<td class="linecoldiscount" align="right">'.$langs->trans('ReductionShort').'</td>';
1121
+    /**
1122
+     *      Return id of contacts for a source and a contact code.
1123
+     *      Example: contact client de facturation ('external', 'BILLING')
1124
+     *      Example: contact client de livraison ('external', 'SHIPPING')
1125
+     *      Example: contact interne suivi paiement ('internal', 'SALESREPFOLL')
1126
+     *
1127
+     *		@param	string	$source		'external' or 'internal'
1128
+     *		@param	string	$code		'BILLING', 'SHIPPING', 'SALESREPFOLL', ...
1129
+     *		@param	int		$status		limited to a certain status
1130
+     *      @return array       		List of id for such contacts
1131
+     */
1132
+    function getIdContact($source,$code,$status=0)
1133
+    {
1134
+        global $conf;
3874 1135
 
3875
-			if ($this->situation_cycle_ref) {
3876
-				print '<td class="linecolcycleref" align="right">' . $langs->trans('Progress') . '</td>';
3877
-			}
1136
+        $result=array();
1137
+        $i=0;
1138
+        //cas particulier pour les expeditions
1139
+        if($this->element=='shipping' && $this->origin_id != 0) {
1140
+            $id=$this->origin_id;
1141
+            $element='commande';
1142
+        } else if($this->element=='reception' && $this->origin_id != 0) {
1143
+            $id=$this->origin_id;
1144
+            $element='order_supplier';
1145
+        } else {
1146
+            $id=$this->id;
1147
+            $element=$this->element;
1148
+        }
3878 1149
 
3879
-			if ($usemargins && ! empty($conf->margin->enabled) && empty($user->societe_id))
3880
-			{
3881
-				if (!empty($user->rights->margins->creer))
3882
-				{
3883
-					if ($conf->global->MARGIN_TYPE == "1")
3884
-						print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('BuyingPrice').'</td>';
3885
-					else
3886
-						print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('CostPrice').'</td>';
3887
-				}
1150
+        $sql = "SELECT ec.fk_socpeople";
1151
+        $sql.= " FROM ".MAIN_DB_PREFIX."element_contact as ec,";
1152
+        if ($source == 'internal') $sql.= " ".MAIN_DB_PREFIX."user as c,";
1153
+        if ($source == 'external') $sql.= " ".MAIN_DB_PREFIX."socpeople as c,";
1154
+        $sql.= " ".MAIN_DB_PREFIX."c_type_contact as tc";
1155
+        $sql.= " WHERE ec.element_id = ".$id;
1156
+        $sql.= " AND ec.fk_socpeople = c.rowid";
1157
+        if ($source == 'internal') $sql.= " AND c.entity IN (".getEntity('user').")";
1158
+        if ($source == 'external') $sql.= " AND c.entity IN (".getEntity('societe').")";
1159
+        $sql.= " AND ec.fk_c_type_contact = tc.rowid";
1160
+        $sql.= " AND tc.element = '".$element."'";
1161
+        $sql.= " AND tc.source = '".$source."'";
1162
+        $sql.= " AND tc.code = '".$code."'";
1163
+        $sql.= " AND tc.active = 1";
1164
+        if ($status) $sql.= " AND ec.statut = ".$status;
1165
+
1166
+        dol_syslog(get_class($this)."::getIdContact", LOG_DEBUG);
1167
+        $resql=$this->db->query($sql);
1168
+        if ($resql)
1169
+        {
1170
+            while ($obj = $this->db->fetch_object($resql))
1171
+            {
1172
+                $result[$i]=$obj->fk_socpeople;
1173
+                $i++;
1174
+            }
1175
+        }
1176
+        else
1177
+        {
1178
+            $this->error=$this->db->error();
1179
+            return null;
1180
+        }
3888 1181
 
3889
-				if (! empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous)
3890
-					print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarginRate').'</td>';
3891
-				if (! empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous)
3892
-					print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarkRate').'</td>';
3893
-			}
1182
+        return $result;
1183
+    }
3894 1184
 
3895
-			// Total HT
3896
-			print '<td class="linecolht" align="right">'.$langs->trans('TotalHTShort').'</td>';
1185
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1186
+    /**
1187
+     *		Load object contact with id=$this->contactid into $this->contact
1188
+     *
1189
+     *		@param	int		$contactid      Id du contact. Use this->contactid if empty.
1190
+     *		@return	int						<0 if KO, >0 if OK
1191
+     */
1192
+    function fetch_contact($contactid=null)
1193
+    {
1194
+        // phpcs:enable
1195
+        if (empty($contactid)) $contactid=$this->contactid;
3897 1196
 
3898
-			// Multicurrency
3899
-			if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoltotalht_currency" align="right">'.$langs->trans('TotalHTShortCurrency', $this->multicurrency_code).'</td>';
1197
+        if (empty($contactid)) return 0;
3900 1198
 
3901
-			if ($outputalsopricetotalwithtax) print '<td align="right" width="80">'.$langs->trans('TotalTTCShort').'</td>';
1199
+        require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1200
+        $contact = new Contact($this->db);
1201
+        $result=$contact->fetch($contactid);
1202
+        $this->contact = $contact;
1203
+        return $result;
1204
+    }
3902 1205
 
3903
-			print '<td class="linecoledit"></td>';  // No width to allow autodim
1206
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1207
+    /**
1208
+     *    	Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty
1209
+     *
1210
+     *		@param		int		$force_thirdparty_id	Force thirdparty id
1211
+     *		@return		int								<0 if KO, >0 if OK
1212
+     */
1213
+    function fetch_thirdparty($force_thirdparty_id=0)
1214
+    {
1215
+        // phpcs:enable
1216
+        global $conf;
3904 1217
 
3905
-			print '<td class="linecoldelete" width="10"></td>';
1218
+        if (empty($this->socid) && empty($this->fk_soc) && empty($this->fk_thirdparty) && empty($force_thirdparty_id))
1219
+            return 0;
3906 1220
 
3907
-			print '<td class="linecolmove" width="10"></td>';
1221
+        require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3908 1222
 
3909
-			if($action == 'selectlines')
3910
-			{
3911
-			    print '<td class="linecolcheckall" align="center">';
3912
-			    print '<input type="checkbox" class="linecheckboxtoggle" />';
3913
-			    print '<script type="text/javascript">$(document).ready(function() {$(".linecheckboxtoggle").click(function() {var checkBoxes = $(".linecheckbox");checkBoxes.prop("checked", this.checked);})});</script>';
3914
-			    print '</td>';
3915
-			}
3916
-
3917
-			print "</tr>\n";
3918
-			print "</thead>\n";
3919
-		}
3920
-
3921
-		$var = true;
3922
-		$i	 = 0;
3923
-
3924
-		print "<tbody>\n";
3925
-		foreach ($this->lines as $line)
3926
-		{
3927
-			//Line extrafield
3928
-			$line->fetch_optionals();
3929
-
3930
-			//if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
3931
-			if (is_object($hookmanager))   // Old code is commented on preceding line.
3932
-			{
3933
-				if (empty($line->fk_parent_line))
3934
-				{
3935
-					$parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3936
-					$reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3937
-				}
3938
-				else
3939
-				{
3940
-					$parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline, 'fk_parent_line'=>$line->fk_parent_line);
3941
-					$reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3942
-				}
3943
-			}
3944
-			if (empty($reshook))
3945
-			{
3946
-				$this->printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected,$extrafieldsline);
3947
-			}
3948
-
3949
-			$i++;
3950
-		}
3951
-		print "</tbody>\n";
3952
-	}
3953
-
3954
-	/**
3955
-	 *	Return HTML content of a detail line
3956
-	 *	TODO Move this into an output class file (htmlline.class.php)
3957
-	 *
3958
-	 *	@param	string		$action				GET/POST action
3959
-	 *	@param CommonObjectLine $line		       	Selected object line to output
3960
-	 *	@param  string	    $var               	Is it a an odd line (true)
3961
-	 *	@param  int		    $num               	Number of line (0)
3962
-	 *	@param  int		    $i					I
3963
-	 *	@param  int		    $dateSelector      	1=Show also date range input fields
3964
-	 *	@param  string	    $seller            	Object of seller third party
3965
-	 *	@param  string	    $buyer             	Object of buyer third party
3966
-	 *	@param	int			$selected		   	Object line selected
3967
-	 *  @param  int			$extrafieldsline	Object of extrafield line attribute
3968
-	 *	@return	void
3969
-	 */
3970
-	function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0)
3971
-	{
3972
-		global $conf,$langs,$user,$object,$hookmanager;
3973
-		global $form,$bc,$bcdd;
3974
-		global $object_rights, $disableedit, $disablemove, $disableremove;   // TODO We should not use global var for this !
3975
-
3976
-		$object_rights = $this->getRights();
3977
-
3978
-		$element=$this->element;
3979
-
3980
-		$text=''; $description=''; $type=0;
3981
-
3982
-		// Show product and description
3983
-		$type=(! empty($line->product_type)?$line->product_type:$line->fk_product_type);
3984
-		// Try to enhance type detection using date_start and date_end for free lines where type was not saved.
3985
-		if (! empty($line->date_start)) $type=1; // deprecated
3986
-		if (! empty($line->date_end)) $type=1; // deprecated
3987
-
3988
-		// Ligne en mode visu
3989
-		if ($action != 'editline' || $selected != $line->id)
3990
-		{
3991
-			// Product
3992
-			if ($line->fk_product > 0)
3993
-			{
3994
-				$product_static = new Product($this->db);
3995
-				$product_static->fetch($line->fk_product);
1223
+        $idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : $this->fk_thirdparty);
1224
+        if ($force_thirdparty_id)
1225
+            $idtofetch = $force_thirdparty_id;
3996 1226
 
3997
-				$product_static->ref = $line->ref; //can change ref in hook
3998
-				$product_static->label = $line->label; //can change label in hook
3999
-				$text=$product_static->getNomUrl(1);
1227
+        if ($idtofetch) {
1228
+            $thirdparty = new Societe($this->db);
1229
+            $result = $thirdparty->fetch($idtofetch);
1230
+            $this->thirdparty = $thirdparty;
4000 1231
 
4001
-				// Define output language and label
4002
-				if (! empty($conf->global->MAIN_MULTILANGS))
4003
-				{
4004
-					if (! is_object($this->thirdparty))
4005
-					{
4006
-						dol_print_error('','Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
4007
-						return;
4008
-					}
4009
-
4010
-					$prod = new Product($this->db);
4011
-					$prod->fetch($line->fk_product);
4012
-
4013
-					$outputlangs = $langs;
4014
-					$newlang='';
4015
-					if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09');
4016
-					if (! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang)) $newlang=$this->thirdparty->default_lang;		// For language to language of customer
4017
-					if (! empty($newlang))
4018
-					{
4019
-						$outputlangs = new Translate("",$conf);
4020
-						$outputlangs->setDefaultLang($newlang);
4021
-					}
4022
-
4023
-					$label = (! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
4024
-				}
4025
-				else
4026
-				{
4027
-					$label = $line->product_label;
4028
-				}
1232
+            // Use first price level if level not defined for third party
1233
+            if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) {
1234
+                $this->thirdparty->price_level = 1;
1235
+            }
4029 1236
 
4030
-				$text.= ' - '.(! empty($line->label)?$line->label:$label);
4031
-				$description.=(! empty($conf->global->PRODUIT_DESC_IN_FORM)?'':dol_htmlentitiesbr($line->description));	// Description is what to show on popup. We shown nothing if already into desc.
4032
-			}
1237
+            return $result;
1238
+        } else
1239
+            return -1;
1240
+    }
4033 1241
 
4034
-			$line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4035 1242
 
4036
-			// Output template part (modules that overwrite templates must declare this into descriptor)
4037
-			// Use global variables + $dateSelector + $seller and $buyer
4038
-			$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4039
-			foreach($dirtpls as $reldir)
4040
-			{
4041
-				$tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
4042
-				if (empty($conf->file->strict_mode)) {
4043
-					$res=@include $tpl;
4044
-				} else {
4045
-					$res=include $tpl; // for debug
4046
-				}
4047
-				if ($res) break;
4048
-			}
4049
-		}
4050
-
4051
-		// Ligne en mode update
4052
-		if ($this->statut == 0 && $action == 'editline' && $selected == $line->id)
4053
-		{
4054
-			$label = (! empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
4055
-			$placeholder=' placeholder="'.$langs->trans("Label").'"';
4056
-
4057
-			$line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4058
-
4059
-			// Output template part (modules that overwrite templates must declare this into descriptor)
4060
-			// Use global variables + $dateSelector + $seller and $buyer
4061
-			$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4062
-			foreach($dirtpls as $reldir)
4063
-			{
4064
-				$tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
4065
-				if (empty($conf->file->strict_mode)) {
4066
-					$res=@include $tpl;
4067
-				} else {
4068
-					$res=include $tpl; // for debug
4069
-				}
4070
-				if ($res) break;
4071
-			}
4072
-		}
4073
-	}
4074
-
4075
-
4076
-	/* This is to show array of line of details of source object */
4077
-
4078
-
4079
-	/**
4080
-	 * 	Return HTML table table of source object lines
4081
-	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
4082
-	 *  If lines are into a template, title must also be into a template
4083
-	 *  But for the moment we don't know if it's possible, so we keep the method available on overloaded objects.
4084
-	 *
4085
-	 *	@param	string		$restrictlist		''=All lines, 'services'=Restrict to services only
4086
-	 *  @return	void
4087
-	 */
4088
-	function printOriginLinesList($restrictlist='')
4089
-	{
4090
-		global $langs, $hookmanager, $conf;
4091
-
4092
-		print '<tr class="liste_titre">';
4093
-		print '<td>'.$langs->trans('Ref').'</td>';
4094
-		print '<td>'.$langs->trans('Description').'</td>';
4095
-		print '<td align="right">'.$langs->trans('VATRate').'</td>';
4096
-		print '<td align="right">'.$langs->trans('PriceUHT').'</td>';
4097
-		if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('PriceUHTCurrency').'</td>';
4098
-		print '<td align="right">'.$langs->trans('Qty').'</td>';
4099
-		if($conf->global->PRODUCT_USE_UNITS)
4100
-		{
4101
-			print '<td align="left">'.$langs->trans('Unit').'</td>';
4102
-		}
4103
-		print '<td align="right">'.$langs->trans('ReductionShort').'</td></tr>';
4104
-
4105
-		$var = true;
4106
-		$i	 = 0;
4107
-
4108
-		if (! empty($this->lines))
4109
-		{
4110
-			foreach ($this->lines as $line)
4111
-			{
4112
-				if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
4113
-				{
4114
-					if (empty($line->fk_parent_line))
4115
-					{
4116
-						$parameters=array('line'=>$line,'var'=>$var,'i'=>$i);
4117
-						$action='';
4118
-						$hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
4119
-					}
4120
-				}
4121
-				else
4122
-				{
4123
-					$this->printOriginLine($line, $var, $restrictlist);
4124
-				}
1243
+    /**
1244
+     * Looks for an object with ref matching the wildcard provided
1245
+     * It does only work when $this->table_ref_field is set
1246
+     *
1247
+     * @param string $ref Wildcard
1248
+     * @return int >1 = OK, 0 = Not found or table_ref_field not defined, <0 = KO
1249
+     */
1250
+    public function fetchOneLike($ref)
1251
+    {
1252
+        if (!$this->table_ref_field) {
1253
+            return 0;
1254
+        }
4125 1255
 
4126
-				$i++;
4127
-			}
4128
-		}
4129
-	}
4130
-
4131
-	/**
4132
-	 * 	Return HTML with a line of table array of source object lines
4133
-	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
4134
-	 *  If lines are into a template, title must also be into a template
4135
-	 *  But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
4136
-	 *
4137
-	 * 	@param	CommonObjectLine	$line				Line
4138
-	 * 	@param	string				$var				Var
4139
-	 *	@param	string				$restrictlist		''=All lines, 'services'=Restrict to services only (strike line if not)
4140
-	 * 	@return	void
4141
-	 */
4142
-	function printOriginLine($line, $var, $restrictlist='')
4143
-	{
4144
-		global $langs, $conf;
4145
-
4146
-		//var_dump($line);
4147
-		if (!empty($line->date_start))
4148
-		{
4149
-			$date_start=$line->date_start;
4150
-		}
4151
-		else
4152
-		{
4153
-			$date_start=$line->date_debut_prevue;
4154
-			if ($line->date_debut_reel) $date_start=$line->date_debut_reel;
4155
-		}
4156
-		if (!empty($line->date_end))
4157
-		{
4158
-			$date_end=$line->date_end;
4159
-		}
4160
-		else
4161
-		{
4162
-			$date_end=$line->date_fin_prevue;
4163
-			if ($line->date_fin_reel) $date_end=$line->date_fin_reel;
4164
-		}
4165
-
4166
-		$this->tpl['label'] = '';
4167
-		if (! empty($line->fk_parent_line)) $this->tpl['label'].= img_picto('', 'rightarrow');
4168
-
4169
-		if (($line->info_bits & 2) == 2)  // TODO Not sure this is used for source object
4170
-		{
4171
-			$discount=new DiscountAbsolute($this->db);
4172
-			$discount->fk_soc = $this->socid;
4173
-			$this->tpl['label'].= $discount->getNomUrl(0,'discount');
4174
-		}
4175
-		else if (! empty($line->fk_product))
4176
-		{
4177
-			$productstatic = new Product($this->db);
4178
-			$productstatic->id = $line->fk_product;
4179
-			$productstatic->ref = $line->ref;
4180
-			$productstatic->type = $line->fk_product_type;
4181
-            if(empty($productstatic->ref)){
4182
-				$line->fetch_product();
4183
-				$productstatic = $line->product;
4184
-			}
4185
-			
4186
-			$this->tpl['label'].= $productstatic->getNomUrl(1);
4187
-			$this->tpl['label'].= ' - '.(! empty($line->label)?$line->label:$line->product_label);
4188
-			// Dates
4189
-			if ($line->product_type == 1 && ($date_start || $date_end))
4190
-			{
4191
-				$this->tpl['label'].= get_date_range($date_start,$date_end);
4192
-			}
4193
-		}
4194
-		else
4195
-		{
4196
-			$this->tpl['label'].= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''),'service') : img_object($langs->trans(''),'product')));
4197
-			if (!empty($line->desc)) {
4198
-				$this->tpl['label'].=$line->desc;
4199
-			}else {
4200
-				$this->tpl['label'].= ($line->label ? '&nbsp;'.$line->label : '');
4201
-			}
4202
-			
4203
-			// Dates
4204
-			if ($line->product_type == 1 && ($date_start || $date_end))
4205
-			{
4206
-				$this->tpl['label'].= get_date_range($date_start,$date_end);
4207
-			}
4208
-		}
1256
+        $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE '.$this->table_ref_field.' LIKE "'.$this->db->escape($ref).'" LIMIT 1';
4209 1257
 
4210
-		if (! empty($line->desc))
4211
-		{
4212
-			if ($line->desc == '(CREDIT_NOTE)')  // TODO Not sure this is used for source object
4213
-			{
4214
-				$discount=new DiscountAbsolute($this->db);
4215
-				$discount->fetch($line->fk_remise_except);
4216
-				$this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote",$discount->getNomUrl(0));
4217
-			}
4218
-			elseif ($line->desc == '(DEPOSIT)')  // TODO Not sure this is used for source object
4219
-			{
4220
-				$discount=new DiscountAbsolute($this->db);
4221
-				$discount->fetch($line->fk_remise_except);
4222
-				$this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit",$discount->getNomUrl(0));
4223
-			}
4224
-			elseif ($line->desc == '(EXCESS RECEIVED)')
4225
-			{
4226
-				$discount=new DiscountAbsolute($this->db);
4227
-				$discount->fetch($line->fk_remise_except);
4228
-				$this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived",$discount->getNomUrl(0));
4229
-			}
4230
-			elseif ($line->desc == '(EXCESS PAID)')
4231
-			{
4232
-				$discount=new DiscountAbsolute($this->db);
4233
-				$discount->fetch($line->fk_remise_except);
4234
-				$this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid",$discount->getNomUrl(0));
4235
-			}
4236
-			else
4237
-			{
4238
-				$this->tpl['description'] = dol_trunc($line->desc,60);
4239
-			}
4240
-		}
4241
-		else
4242
-		{
4243
-			$this->tpl['description'] = '&nbsp;';
4244
-		}
1258
+        $query = $this->db->query($sql);
4245 1259
 
4246
-        // VAT Rate
4247
-        $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
4248
-        $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
4249
-        if (! empty($line->vat_src_code) && ! preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'].=' ('.$line->vat_src_code.')';
1260
+        if (!$this->db->num_rows($query)) {
1261
+            return 0;
1262
+        }
4250 1263
 
4251
-		$this->tpl['price'] = price($line->subprice);
4252
-		$this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
4253
-		$this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
4254
-		if ($conf->global->PRODUCT_USE_UNITS) $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
4255
-		$this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
4256
-
4257
-		// Is the line strike or not
4258
-		$this->tpl['strike']=0;
4259
-		if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) $this->tpl['strike']=1;
4260
-
4261
-		// Output template part (modules that overwrite templates must declare this into descriptor)
4262
-		// Use global variables + $dateSelector + $seller and $buyer
4263
-		$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4264
-		foreach($dirtpls as $reldir)
4265
-		{
4266
-			$tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
4267
-			if (empty($conf->file->strict_mode)) {
4268
-				$res=@include $tpl;
4269
-			} else {
4270
-				$res=include $tpl; // for debug
4271
-			}
4272
-			if ($res) break;
4273
-		}
4274
-	}
1264
+        $result = $this->db->fetch_object($query);
4275 1265
 
1266
+        return $this->fetch($result->rowid);
1267
+    }
4276 1268
 
4277 1269
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4278
-	/**
4279
-	 *	Add resources to the current object : add entry into llx_element_resources
4280
-	 *	Need $this->element & $this->id
4281
-	 *
4282
-	 *	@param		int		$resource_id		Resource id
4283
-	 *	@param		string	$resource_type		'resource'
4284
-	 *	@param		int		$busy				Busy or not
4285
-	 *	@param		int		$mandatory			Mandatory or not
4286
-	 *	@return		int							<=0 if KO, >0 if OK
4287
-	 */
4288
-	function add_element_resource($resource_id, $resource_type, $busy=0, $mandatory=0)
4289
-	{
1270
+    /**
1271
+     *	Load data for barcode into properties ->barcode_type*
1272
+     *	Properties ->barcode_type that is id of barcode. Type is used to find other properties, but
1273
+     *  if it is not defined, ->element must be defined to know default barcode type.
1274
+     *
1275
+     *	@return		int			<0 if KO, 0 if can't guess type of barcode (ISBN, EAN13...), >0 if OK (all barcode properties loaded)
1276
+     */
1277
+    function fetch_barcode()
1278
+    {
4290 1279
         // phpcs:enable
4291
-		$this->db->begin();
4292
-
4293
-		$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_resources (";
4294
-		$sql.= "resource_id";
4295
-		$sql.= ", resource_type";
4296
-		$sql.= ", element_id";
4297
-		$sql.= ", element_type";
4298
-		$sql.= ", busy";
4299
-		$sql.= ", mandatory";
4300
-		$sql.= ") VALUES (";
4301
-		$sql.= $resource_id;
4302
-		$sql.= ", '".$this->db->escape($resource_type)."'";
4303
-		$sql.= ", '".$this->db->escape($this->id)."'";
4304
-		$sql.= ", '".$this->db->escape($this->element)."'";
4305
-		$sql.= ", '".$this->db->escape($busy)."'";
4306
-		$sql.= ", '".$this->db->escape($mandatory)."'";
4307
-		$sql.= ")";
4308
-
4309
-		dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG);
4310
-		if ($this->db->query($sql))
4311
-		{
4312
-			$this->db->commit();
4313
-			return 1;
4314
-		}
4315
-		else
4316
-		{
4317
-			$this->error=$this->db->lasterror();
4318
-			$this->db->rollback();
4319
-			return  0;
4320
-		}
4321
-	}
1280
+        global $conf;
1281
+
1282
+        dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
1283
+
1284
+        $idtype=$this->barcode_type;
1285
+        if (empty($idtype) && $idtype != '0')	// If type of barcode no set, we try to guess. If set to '0' it means we forced to have type remain not defined
1286
+        {
1287
+            if ($this->element == 'product')      $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1288
+            else if ($this->element == 'societe') $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1289
+            else dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1290
+        }
1291
+
1292
+        if ($idtype > 0)
1293
+        {
1294
+            if (empty($this->barcode_type) || empty($this->barcode_type_code) || empty($this->barcode_type_label) || empty($this->barcode_type_coder))    // If data not already loaded
1295
+            {
1296
+                $sql = "SELECT rowid, code, libelle as label, coder";
1297
+                $sql.= " FROM ".MAIN_DB_PREFIX."c_barcode_type";
1298
+                $sql.= " WHERE rowid = ".$idtype;
1299
+                dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1300
+                $resql = $this->db->query($sql);
1301
+                if ($resql)
1302
+                {
1303
+                    $obj = $this->db->fetch_object($resql);
1304
+                    $this->barcode_type       = $obj->rowid;
1305
+                    $this->barcode_type_code  = $obj->code;
1306
+                    $this->barcode_type_label = $obj->label;
1307
+                    $this->barcode_type_coder = $obj->coder;
1308
+                    return 1;
1309
+                }
1310
+                else
1311
+                {
1312
+                    dol_print_error($this->db);
1313
+                    return -1;
1314
+                }
1315
+            }
1316
+        }
1317
+        return 0;
1318
+    }
4322 1319
 
4323 1320
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4324
-	/**
4325
-	 *    Delete a link to resource line
4326
-	 *
4327
-	 *    @param	int		$rowid			Id of resource line to delete
4328
-	 *    @param	int		$element		element name (for trigger) TODO: use $this->element into commonobject class
4329
-	 *    @param	int		$notrigger		Disable all triggers
4330
-	 *    @return   int						>0 if OK, <0 if KO
4331
-	 */
4332
-	function delete_resource($rowid, $element, $notrigger=0)
4333
-	{
1321
+    /**
1322
+     *		Load the project with id $this->fk_project into this->project
1323
+     *
1324
+     *		@return		int			<0 if KO, >=0 if OK
1325
+     */
1326
+    function fetch_projet()
1327
+    {
4334 1328
         // phpcs:enable
4335
-		global $user;
4336
-
4337
-		$this->db->begin();
1329
+        include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
4338 1330
 
4339
-		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_resources";
4340
-		$sql.= " WHERE rowid=".$rowid;
1331
+        if (empty($this->fk_project) && ! empty($this->fk_projet)) $this->fk_project = $this->fk_projet;	// For backward compatibility
1332
+        if (empty($this->fk_project)) return 0;
4341 1333
 
4342
-		dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG);
1334
+        $project = new Project($this->db);
1335
+        $result = $project->fetch($this->fk_project);
4343 1336
 
4344
-		$resql=$this->db->query($sql);
4345
-		if (! $resql)
4346
-		{
4347
-			$this->error=$this->db->lasterror();
4348
-			$this->db->rollback();
4349
-			return -1;
4350
-		}
4351
-		else
4352
-		{
4353
-			if (! $notrigger)
4354
-			{
4355
-				$result=$this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
4356
-				if ($result < 0) { $this->db->rollback(); return -1; }
4357
-			}
4358
-			$this->db->commit();
4359
-			return 1;
4360
-		}
4361
-	}
4362
-
4363
-
4364
-	/**
4365
-	 * Overwrite magic function to solve problem of cloning object that are kept as references
4366
-	 *
4367
-	 * @return void
4368
-	 */
4369
-	function __clone()
4370
-	{
4371
-		// Force a copy of this->lines, otherwise it will point to same object.
4372
-		if (isset($this->lines) && is_array($this->lines))
4373
-		{
4374
-			$nboflines=count($this->lines);
4375
-			for($i=0; $i < $nboflines; $i++)
4376
-			{
4377
-				$this->lines[$i] = clone $this->lines[$i];
4378
-			}
4379
-		}
4380
-	}
4381
-
4382
-	/**
4383
-	 * Common function for all objects extending CommonObject for generating documents
4384
-	 *
4385
-	 * @param 	string 		$modelspath 	Relative folder where generators are placed
4386
-	 * @param 	string 		$modele 		Generator to use. Caller must set it to obj->modelpdf or GETPOST('modelpdf') for example.
4387
-	 * @param 	Translate 	$outputlangs 	Output language to use
4388
-	 * @param 	int 		$hidedetails 	1 to hide details. 0 by default
4389
-	 * @param 	int 		$hidedesc 		1 to hide product description. 0 by default
4390
-	 * @param 	int 		$hideref 		1 to hide product reference. 0 by default
4391
-	 * @param   null|array  $moreparams     Array to provide more information
4392
-	 * @return 	int 						>0 if OK, <0 if KO
4393
-	 * @see	addFileIntoDatabaseIndex
4394
-	 */
4395
-	protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
4396
-	{
4397
-		global $conf, $langs, $user;
4398
-
4399
-		$srctemplatepath='';
4400
-
4401
-		// Increase limit for PDF build
4402
-		$err=error_reporting();
4403
-		error_reporting(0);
4404
-		@set_time_limit(120);
4405
-		error_reporting($err);
4406
-
4407
-		// If selected model is a filename template (then $modele="modelname" or "modelname:filename")
4408
-		$tmp=explode(':',$modele,2);
4409
-		if (! empty($tmp[1]))
4410
-		{
4411
-			$modele=$tmp[0];
4412
-			$srctemplatepath=$tmp[1];
4413
-		}
4414
-
4415
-		// Search template files
4416
-		$file=''; $classname=''; $filefound=0;
4417
-		$dirmodels=array('/');
4418
-		if (is_array($conf->modules_parts['models'])) $dirmodels=array_merge($dirmodels,$conf->modules_parts['models']);
4419
-		foreach($dirmodels as $reldir)
4420
-		{
4421
-			foreach(array('doc','pdf') as $prefix)
4422
-			{
4423
-				if (in_array(get_class($this), array('Adherent'))) $file = $prefix."_".$modele.".class.php";     // Member module use prefix_module.class.php
4424
-				else $file = $prefix."_".$modele.".modules.php";
1337
+        $this->projet = $project;	// deprecated
1338
+        $this->project = $project;
1339
+        return $result;
1340
+    }
4425 1341
 
4426
-				// On verifie l'emplacement du modele
4427
-				$file=dol_buildpath($reldir.$modelspath.$file,0);
4428
-				if (file_exists($file))
4429
-				{
4430
-					$filefound=1;
4431
-					$classname=$prefix.'_'.$modele;
4432
-					break;
4433
-				}
4434
-			}
4435
-			if ($filefound) break;
4436
-		}
1342
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1343
+    /**
1344
+     *		Load the product with id $this->fk_product into this->product
1345
+     *
1346
+     *		@return		int			<0 if KO, >=0 if OK
1347
+     */
1348
+    function fetch_product()
1349
+    {
1350
+        // phpcs:enable
1351
+        include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
4437 1352
 
4438
-		// If generator was found
4439
-		if ($filefound)
4440
-		{
4441
-			global $db;  // Required to solve a conception default in commonstickergenerator.class.php making an include of code using $db
1353
+        if (empty($this->fk_product)) return 0;
4442 1354
 
4443
-			require_once $file;
1355
+        $product = new Product($this->db);
1356
+        $result = $product->fetch($this->fk_product);
4444 1357
 
4445
-			$obj = new $classname($this->db);
1358
+        $this->product = $product;
1359
+        return $result;
1360
+    }
4446 1361
 
4447
-			// If generator is ODT, we must have srctemplatepath defined, if not we set it.
4448
-			if ($obj->type == 'odt' && empty($srctemplatepath))
4449
-			{
4450
-				$varfortemplatedir=$obj->scandir;
4451
-				if ($varfortemplatedir && ! empty($conf->global->$varfortemplatedir))
4452
-				{
4453
-					$dirtoscan=$conf->global->$varfortemplatedir;
4454
-
4455
-					$listoffiles=array();
4456
-
4457
-					// Now we add first model found in directories scanned
4458
-					$listofdir=explode(',',$dirtoscan);
4459
-					foreach($listofdir as $key => $tmpdir)
4460
-					{
4461
-						$tmpdir=trim($tmpdir);
4462
-						$tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
4463
-						if (! $tmpdir) { unset($listofdir[$key]); continue; }
4464
-						if (is_dir($tmpdir))
4465
-						{
4466
-							$tmpfiles=dol_dir_list($tmpdir,'files',0,'\.od(s|t)$','','name',SORT_ASC,0);
4467
-							if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles);
4468
-						}
4469
-					}
4470
-
4471
-					if (count($listoffiles))
4472
-					{
4473
-						foreach($listoffiles as $record)
4474
-						{
4475
-							$srctemplatepath=$record['fullname'];
4476
-							break;
4477
-						}
4478
-					}
4479
-				}
1362
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1363
+    /**
1364
+     *		Load the user with id $userid into this->user
1365
+     *
1366
+     *		@param	int		$userid 		Id du contact
1367
+     *		@return	int						<0 if KO, >0 if OK
1368
+     */
1369
+    function fetch_user($userid)
1370
+    {
1371
+        // phpcs:enable
1372
+        $user = new User($this->db);
1373
+        $result=$user->fetch($userid);
1374
+        $this->user = $user;
1375
+        return $result;
1376
+    }
4480 1377
 
4481
-				if (empty($srctemplatepath))
4482
-				{
4483
-					$this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
4484
-					return -1;
4485
-				}
4486
-			}
1378
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1379
+    /**
1380
+     *	Read linked origin object
1381
+     *
1382
+     *	@return		void
1383
+     */
1384
+    function fetch_origin()
1385
+    {
1386
+        // phpcs:enable
1387
+        if ($this->origin == 'shipping') $this->origin = 'expedition';
1388
+        if ($this->origin == 'delivery') $this->origin = 'livraison';
1389
+        if ($this->origin == 'order_supplier') $this->origin = 'commandeFournisseur';
4487 1390
 
4488
-			if ($obj->type == 'odt' && ! empty($srctemplatepath))
4489
-			{
4490
-				if (! dol_is_file($srctemplatepath))
4491
-				{
4492
-					$this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
4493
-					return -1;
4494
-				}
4495
-			}
1391
+        $origin = $this->origin;
4496 1392
 
4497
-			// We save charset_output to restore it because write_file can change it if needed for
4498
-			// output format that does not support UTF8.
4499
-			$sav_charset_output=$outputlangs->charset_output;
1393
+        $classname = ucfirst($origin);
1394
+        $this->$origin = new $classname($this->db);
1395
+        $this->$origin->fetch($this->origin_id);
1396
+    }
4500 1397
 
4501
-			if (in_array(get_class($this), array('Adherent')))
4502
-			{
4503
-				$arrayofrecords = array();   // The write_file of templates of adherent class need this var
4504
-				$resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams);
4505
-			}
4506
-			else
4507
-			{
4508
-				$resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
4509
-			}
4510
-			// After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
1398
+    /**
1399
+     *  Load object from specific field
1400
+     *
1401
+     *  @param	string	$table		Table element or element line
1402
+     *  @param	string	$field		Field selected
1403
+     *  @param	string	$key		Import key
1404
+     *  @param	string	$element	Element name
1405
+     *	@return	int					<0 if KO, >0 if OK
1406
+     */
1407
+    function fetchObjectFrom($table, $field, $key, $element = null)
1408
+    {
1409
+        global $conf;
4511 1410
 
4512
-			if ($resultwritefile > 0)
4513
-			{
4514
-				$outputlangs->charset_output=$sav_charset_output;
1411
+        $result=false;
4515 1412
 
4516
-				// We delete old preview
4517
-				require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
4518
-				dol_delete_preview($this);
1413
+        $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table;
1414
+        $sql.= " WHERE ".$field." = '".$key."'";
1415
+        if (! empty($element)) {
1416
+            $sql.= " AND entity IN (".getEntity($element).")";
1417
+        } else {
1418
+            $sql.= " AND entity = ".$conf->entity;
1419
+        }
4519 1420
 
4520
-				// Index file in database
4521
-				if (! empty($obj->result['fullpath']))
4522
-				{
4523
-					$destfull = $obj->result['fullpath'];
4524
-					$upload_dir = dirname($destfull);
4525
-					$destfile = basename($destfull);
4526
-					$rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir);
4527
-
4528
-					if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir))     // If not a tmp dir
4529
-					{
4530
-						$filename = basename($destfile);
4531
-						$rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
4532
-						$rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
4533
-
4534
-						include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
4535
-						$ecmfile=new EcmFiles($this->db);
4536
-						$result = $ecmfile->fetch(0, '', ($rel_dir?$rel_dir.'/':'').$filename);
4537
-
4538
-						// Set the public "share" key
4539
-						$setsharekey = false;
4540
-						if ($this->element == 'propal')
4541
-						{
4542
-							$useonlinesignature = $conf->global->MAIN_FEATURES_LEVEL;	// Replace this with 1 when feature to make online signature is ok
4543
-							if ($useonlinesignature) $setsharekey=true;
4544
-							if (! empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4545
-						}
4546
-						if ($this->element == 'commande'     && ! empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD))        $setsharekey=true;
4547
-						if ($this->element == 'facture'      && ! empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD))      $setsharekey=true;
4548
-						if ($this->element == 'bank_account' && ! empty($conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4549
-
4550
-						if ($setsharekey)
4551
-						{
4552
-							if (empty($ecmfile->share))	// Because object not found or share not set yet
4553
-							{
4554
-								require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
4555
-								$ecmfile->share = getRandomPassword(true);
4556
-							}
4557
-						}
1421
+        dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
1422
+        $resql = $this->db->query($sql);
1423
+        if ($resql)
1424
+        {
1425
+            $row = $this->db->fetch_row($resql);
1426
+            // Test for avoid error -1
1427
+            if ($row[0] > 0) {
1428
+                $result = $this->fetch($row[0]);
1429
+            }
1430
+        }
4558 1431
 
4559
-						if ($result > 0)
4560
-						{
4561
-							$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4562
-							$ecmfile->fullpath_orig = '';
4563
-							$ecmfile->gen_or_uploaded = 'generated';
4564
-							$ecmfile->description = '';    // indexed content
4565
-							$ecmfile->keyword = '';        // keyword content
4566
-							$result = $ecmfile->update($user);
4567
-							if ($result < 0)
4568
-							{
4569
-								setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4570
-							}
4571
-						}
4572
-						else
4573
-						{
4574
-							$ecmfile->entity = $conf->entity;
4575
-							$ecmfile->filepath = $rel_dir;
4576
-							$ecmfile->filename = $filename;
4577
-							$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4578
-							$ecmfile->fullpath_orig = '';
4579
-							$ecmfile->gen_or_uploaded = 'generated';
4580
-							$ecmfile->description = '';    // indexed content
4581
-							$ecmfile->keyword = '';        // keyword content
4582
-							$ecmfile->src_object_type = $this->table_element;
4583
-							$ecmfile->src_object_id   = $this->id;
4584
-
4585
-							$result = $ecmfile->create($user);
4586
-							if ($result < 0)
4587
-							{
4588
-								setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4589
-							}
4590
-						}
1432
+        return $result;
1433
+    }
4591 1434
 
4592
-						/*$this->result['fullname']=$destfull;
4593
-						$this->result['filepath']=$ecmfile->filepath;
4594
-						$this->result['filename']=$ecmfile->filename;*/
4595
-						//var_dump($obj->update_main_doc_field);exit;
4596
-
4597
-						// Update the last_main_doc field into main object (if documenent generator has property ->update_main_doc_field set)
4598
-						$update_main_doc_field=0;
4599
-						if (! empty($obj->update_main_doc_field)) $update_main_doc_field=1;
4600
-						if ($update_main_doc_field && ! empty($this->table_element))
4601
-						{
4602
-							$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET last_main_doc = '".($ecmfile->filepath.'/'.$ecmfile->filename)."'";
4603
-							$sql.= ' WHERE rowid = '.$this->id;
4604
-							$resql = $this->db->query($sql);
4605
-							if (! $resql) dol_print_error($this->db);
4606
-						}
4607
-					}
4608
-				}
4609
-				else
4610
-				{
4611
-					dol_syslog('Method ->write_file was called on object '.get_class($obj).' and return a success but the return array ->result["fullpath"] was not set.', LOG_WARNING);
4612
-				}
1435
+    /**
1436
+     *	Getter generic. Load value from a specific field
1437
+     *
1438
+     *	@param	string	$table		Table of element or element line
1439
+     *	@param	int		$id			Element id
1440
+     *	@param	string	$field		Field selected
1441
+     *	@return	int					<0 if KO, >0 if OK
1442
+     */
1443
+    function getValueFrom($table, $id, $field)
1444
+    {
1445
+        $result=false;
1446
+        if (!empty($id) && !empty($field) && !empty($table)) {
1447
+            $sql = "SELECT ".$field." FROM ".MAIN_DB_PREFIX.$table;
1448
+            $sql.= " WHERE rowid = ".$id;
1449
+
1450
+            dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
1451
+            $resql = $this->db->query($sql);
1452
+            if ($resql)
1453
+            {
1454
+                $row = $this->db->fetch_row($resql);
1455
+                $result = $row[0];
1456
+            }
1457
+        }
1458
+        return $result;
1459
+    }
4613 1460
 
4614
-				// Success in building document. We build meta file.
4615
-				dol_meta_create($this);
1461
+    /**
1462
+     *	Setter generic. Update a specific field into database.
1463
+     *  Warning: Trigger is run only if param trigkey is provided.
1464
+     *
1465
+     *	@param	string		$field			Field to update
1466
+     *	@param	mixed		$value			New value
1467
+     *	@param	string		$table			To force other table element or element line (should not be used)
1468
+     *	@param	int			$id				To force other object id (should not be used)
1469
+     *	@param	string		$format			Data format ('text', 'date'). 'text' is used if not defined
1470
+     *	@param	string		$id_field		To force rowid field name. 'rowid' is used if not defined
1471
+     *	@param	User|string	$fuser			Update the user of last update field with this user. If not provided, current user is used except if value is 'none'
1472
+     *  @param  string      $trigkey    	Trigger key to run (in most cases something like 'XXX_MODIFY')
1473
+     *  @param	string		$fk_user_field	Name of field to save user id making change
1474
+     *	@return	int							<0 if KO, >0 if OK
1475
+     *  @see updateExtraField
1476
+     */
1477
+    function setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='', $fk_user_field='fk_user_modif')
1478
+    {
1479
+        global $user,$langs,$conf;
4616 1480
 
4617
-				return 1;
4618
-			}
4619
-			else
4620
-			{
4621
-				$outputlangs->charset_output=$sav_charset_output;
4622
-				dol_print_error($this->db, "Error generating document for ".__CLASS__.". Error: ".$obj->error, $obj->errors);
4623
-				return -1;
4624
-			}
4625
-		}
4626
-		else
4627
-		{
4628
-			$this->error=$langs->trans("Error")." ".$langs->trans("ErrorFileDoesNotExists",$file);
4629
-			dol_print_error('',$this->error);
4630
-			return -1;
4631
-		}
4632
-	}
4633
-
4634
-	/**
4635
-	 *  Build thumb
4636
-	 *  @TODO Move this into files.lib.php
4637
-	 *
4638
-	 *  @param      string	$file           Path file in UTF8 to original file to create thumbs from.
4639
-	 *	@return		void
4640
-	 */
4641
-	function addThumbs($file)
4642
-	{
4643
-		global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini, $quality;
4644
-
4645
-		require_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';		// This define also $maxwidthsmall, $quality, ...
4646
-
4647
-		$file_osencoded=dol_osencode($file);
4648
-		if (file_exists($file_osencoded))
4649
-		{
4650
-			// Create small thumbs for company (Ratio is near 16/9)
4651
-			// Used on logon for example
4652
-			vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
4653
-
4654
-			// Create mini thumbs for company (Ratio is near 16/9)
4655
-			// Used on menu or for setup page for example
4656
-			vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
4657
-		}
4658
-	}
4659
-
4660
-
4661
-	/* Functions common to commonobject and commonobjectline */
4662
-
4663
-	/* For default values */
4664
-
4665
-	/**
4666
-	 * Return the default value to use for a field when showing the create form of object.
4667
-	 * Return values in this order:
4668
-	 * 1) If parameter is available into POST, we return it first.
4669
-	 * 2) If not but an alternate value was provided as parameter of function, we return it.
4670
-	 * 3) If not but a constant $conf->global->OBJECTELEMENT_FIELDNAME is set, we return it (It is better to use the dedicated table).
4671
-	 * 4) Return value found into database (TODO No yet implemented)
4672
-	 *
4673
-	 * @param   string              $fieldname          Name of field
4674
-	 * @param   string              $alternatevalue     Alternate value to use
4675
-	 * @return  string|string[]                         Default value (can be an array if the GETPOST return an array)
4676
-	 **/
4677
-	function getDefaultCreateValueFor($fieldname, $alternatevalue=null)
4678
-	{
4679
-		global $conf, $_POST;
4680
-
4681
-		// If param here has been posted, we use this value first.
4682
-		if (isset($_POST[$fieldname])) return GETPOST($fieldname, 2);
4683
-
4684
-		if (isset($alternatevalue)) return $alternatevalue;
4685
-
4686
-		$newelement=$this->element;
4687
-		if ($newelement == 'facture') $newelement='invoice';
4688
-		if ($newelement == 'commande') $newelement='order';
4689
-		if (empty($newelement))
4690
-		{
4691
-			dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
4692
-			return '';
4693
-		}
4694
-
4695
-		$keyforfieldname=strtoupper($newelement.'_DEFAULT_'.$fieldname);
4696
-		//var_dump($keyforfieldname);
4697
-		if (isset($conf->global->$keyforfieldname)) return $conf->global->$keyforfieldname;
4698
-
4699
-		// TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
4700
-	}
4701
-
4702
-
4703
-	/* For triggers */
1481
+        if (empty($table)) 	  $table=$this->table_element;
1482
+        if (empty($id))    	  $id=$this->id;
1483
+        if (empty($format))   $format='text';
1484
+        if (empty($id_field)) $id_field='rowid';
4704 1485
 
1486
+        $error=0;
4705 1487
 
4706
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4707
-	/**
4708
-	 * Call trigger based on this instance.
4709
-	 * Some context information may also be provided into array property this->context.
4710
-	 * NB:  Error from trigger are stacked in interface->errors
4711
-	 * NB2: If return code of triggers are < 0, action calling trigger should cancel all transaction.
4712
-	 *
4713
-	 * @param   string    $trigger_name   trigger's name to execute
4714
-	 * @param   User      $user           Object user
4715
-	 * @return  int                       Result of run_triggers
4716
-	 */
4717
-	function call_trigger($trigger_name, $user)
4718
-	{
4719
-        // phpcs:enable
4720
-		global $langs,$conf;
1488
+        $this->db->begin();
4721 1489
 
4722
-		include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
4723
-		$interface=new Interfaces($this->db);
4724
-		$result=$interface->run_triggers($trigger_name,$this,$user,$langs,$conf);
1490
+        // Special case
1491
+        if ($table == 'product' && $field == 'note_private') $field='note';
1492
+        if (in_array($table, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) $fk_user_field = 'fk_user_mod';
4725 1493
 
4726
-		if ($result < 0)
4727
-		{
4728
-			if (!empty($this->errors))
4729
-			{
4730
-				$this->errors=array_unique(array_merge($this->errors,$interface->errors));   // We use array_unique because when a trigger call another trigger on same object, this->errors is added twice.
4731
-			}
4732
-			else
4733
-			{
4734
-				$this->errors=$interface->errors;
4735
-			}
4736
-		}
4737
-		return $result;
4738
-	}
1494
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET ";
4739 1495
 
1496
+        if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'";
1497
+        else if ($format == 'int') $sql.= $field." = ".$this->db->escape($value);
1498
+        else if ($format == 'date') $sql.= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
4740 1499
 
4741
-	/* Functions for extrafields */
1500
+        if ($fk_user_field)
1501
+        {
1502
+            if (! empty($fuser) && is_object($fuser)) $sql.=", ".$fk_user_field." = ".$fuser->id;
1503
+            elseif (empty($fuser) || $fuser != 'none') $sql.=", ".$fk_user_field." = ".$user->id;
1504
+        }
4742 1505
 
1506
+        $sql.= " WHERE ".$id_field." = ".$id;
4743 1507
 
4744
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4745
-	/**
4746
-	 *  Function to get extra fields of an object into $this->array_options
4747
-	 *  This method is in most cases called by method fetch of objects but you can call it separately.
4748
-	 *
4749
-	 *  @param	int		$rowid			Id of line. Use the id of object if not defined. Deprecated. Function must be called without parameters.
4750
-	 *  @param  array	$optionsArray   Array resulting of call of extrafields->fetch_name_optionals_label(). Deprecated. Function must be called without parameters.
4751
-	 *  @return	int						<0 if error, 0 if no values of extrafield to find nor found, 1 if an attribute is found and value loaded
4752
-	 */
4753
-	function fetch_optionals($rowid=null, $optionsArray=null)
4754
-	{
4755
-        // phpcs:enable
4756
-		if (empty($rowid)) $rowid=$this->id;
4757
-
4758
-		// To avoid SQL errors. Probably not the better solution though
4759
-		if (!$this->table_element) {
4760
-			return 0;
4761
-		}
4762
-
4763
-		$this->array_options=array();
4764
-
4765
-		if (! is_array($optionsArray))
4766
-		{
4767
-			// If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
4768
-			// TODO Use of existing $extrafield is not yet ready (must mutualize code that use extrafields in form first)
4769
-			// global $extrafields;
4770
-			//if (! is_object($extrafields))
4771
-			//{
4772
-				// require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4773
-            $extrafields = new ExtraFields();
4774
-            //}
1508
+        dol_syslog(get_class($this)."::".__FUNCTION__."", LOG_DEBUG);
1509
+        $resql = $this->db->query($sql);
1510
+        if ($resql)
1511
+        {
1512
+            if ($trigkey)
1513
+            {
1514
+                // call trigger with updated object values
1515
+                if (empty($this->fields) && method_exists($this, 'fetch'))
1516
+                {
1517
+                    $result = $this->fetch($id);
1518
+                }
1519
+                else
1520
+                {
1521
+                    $result = $this->fetchCommon($id);
1522
+                }
1523
+                if ($result >= 0) $result=$this->call_trigger($trigkey, (! empty($fuser) && is_object($fuser)) ? $fuser : $user);   // This may set this->errors
1524
+                if ($result < 0) $error++;
1525
+            }
4775 1526
 
4776
-			// Load array of extrafields for elementype = $this->table_element
4777
-			if (empty($extrafields->attributes[$this->table_element]['loaded']))
4778
-			{
4779
-				$extrafields->fetch_name_optionals_label($this->table_element);
4780
-			}
4781
-			$optionsArray = (! empty($extrafields->attributes[$this->table_element]['label'])?$extrafields->attributes[$this->table_element]['label']:null);
4782
-		}
4783
-		else
4784
-		{
4785
-			global $extrafields;
4786
-			dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
4787
-		}
4788
-
4789
-		$table_element = $this->table_element;
4790
-		if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4791
-
4792
-		// Request to get complementary values
4793
-		if (is_array($optionsArray) && count($optionsArray) > 0)
4794
-		{
4795
-			$sql = "SELECT rowid";
4796
-			foreach ($optionsArray as $name => $label)
4797
-			{
4798
-				if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate')
4799
-				{
4800
-					$sql.= ", ".$name;
4801
-				}
4802
-			}
4803
-			$sql.= " FROM ".MAIN_DB_PREFIX.$table_element."_extrafields";
4804
-			$sql.= " WHERE fk_object = ".$rowid;
1527
+            if (! $error)
1528
+            {
1529
+                if (property_exists($this, $field)) $this->$field = $value;
1530
+                $this->db->commit();
1531
+                return 1;
1532
+            }
1533
+            else
1534
+            {
1535
+                $this->db->rollback();
1536
+                return -2;
1537
+            }
1538
+        }
1539
+        else
1540
+        {
1541
+            $this->error=$this->db->lasterror();
1542
+            $this->db->rollback();
1543
+            return -1;
1544
+        }
1545
+    }
4805 1546
 
4806
-			//dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG);		// Too verbose
4807
-			$resql=$this->db->query($sql);
4808
-			if ($resql)
4809
-			{
4810
-				$this->array_options = array();
4811
-				$numrows=$this->db->num_rows($resql);
4812
-				if ($numrows)
4813
-				{
4814
-					$tab = $this->db->fetch_array($resql);
4815
-
4816
-					foreach ($tab as $key => $value)
4817
-					{
4818
-						// Test fetch_array ! is_int($key) because fetch_array result is a mix table with Key as alpha and Key as int (depend db engine)
4819
-						if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && ! is_int($key))
4820
-						{
4821
-							// we can add this attribute to object
4822
-							if (! empty($extrafields) && in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date','datetime')))
4823
-							{
4824
-								//var_dump($extrafields->attributes[$this->table_element]['type'][$key]);
4825
-								$this->array_options["options_".$key]=$this->db->jdate($value);
4826
-							}
4827
-							else
4828
-							{
4829
-								$this->array_options["options_".$key]=$value;
4830
-							}
1547
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1548
+    /**
1549
+     *      Load properties id_previous and id_next by comparing $fieldid with $this->ref
1550
+     *
1551
+     *      @param	string	$filter		Optional filter. Example: " AND (t.field1 = 'aa' OR t.field2 = 'bb')"
1552
+     *	 	@param  string	$fieldid   	Name of field to use for the select MAX and MIN
1553
+     *		@param	int		$nodbprefix	Do not include DB prefix to forge table name
1554
+     *      @return int         		<0 if KO, >0 if OK
1555
+     */
1556
+    function load_previous_next_ref($filter, $fieldid, $nodbprefix=0)
1557
+    {
1558
+        // phpcs:enable
1559
+        global $conf, $user;
4831 1560
 
4832
-							//var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_".$key]);
4833
-						}
4834
-					}
4835
-				}
1561
+        if (! $this->table_element)
1562
+        {
1563
+            dol_print_error('',get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
1564
+            return -1;
1565
+        }
1566
+        if ($fieldid == 'none') return 1;
4836 1567
 
4837
-				$this->db->free($resql);
1568
+        // Security on socid
1569
+        $socid = 0;
1570
+        if ($user->societe_id > 0) $socid = $user->societe_id;
4838 1571
 
4839
-				if ($numrows) return $numrows;
4840
-				else return 0;
4841
-			}
4842
-			else
4843
-			{
4844
-				dol_print_error($this->db);
4845
-				return -1;
4846
-			}
4847
-		}
4848
-		return 0;
4849
-	}
4850
-
4851
-	/**
4852
-	 *	Delete all extra fields values for the current object.
4853
-	 *
4854
-	 *  @return	int		<0 if KO, >0 if OK
4855
-	 */
4856
-	function deleteExtraFields()
4857
-	{
4858
-		$this->db->begin();
4859
-
4860
-		$table_element = $this->table_element;
4861
-		if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4862
-
4863
-		$sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
4864
-		dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG);
4865
-		$resql=$this->db->query($sql_del);
4866
-		if (! $resql)
4867
-		{
4868
-			$this->error=$this->db->lasterror();
4869
-			$this->db->rollback();
4870
-			return -1;
4871
-		}
4872
-		else
4873
-		{
4874
-			$this->db->commit();
4875
-			return 1;
4876
-		}
4877
-	}
4878
-
4879
-	/**
4880
-	 *	Add/Update all extra fields values for the current object.
4881
-	 *  Data to describe values to insert/update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
4882
-	 *  This function delete record with all extrafields and insert them again from the array $this->array_options.
4883
-	 *
4884
-	 *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
4885
-	 *  @param	User		$userused		Object user
4886
-	 *  @return int 						-1=error, O=did nothing, 1=OK
4887
-	 *  @see updateExtraField, setValueFrom
4888
-	 */
4889
-	function insertExtraFields($trigger='', $userused=null)
4890
-	{
4891
-		global $conf,$langs,$user;
4892
-
4893
-		if (empty($userused)) $userused=$user;
4894
-
4895
-		$error=0;
4896
-
4897
-		if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
4898
-
4899
-		if (! empty($this->array_options))
4900
-		{
4901
-			// Check parameters
4902
-			$langs->load('admin');
4903
-			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4904
-			$extrafields = new ExtraFields($this->db);
4905
-			$target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
4906
-
4907
-			//Eliminate copied source object extra_fields that do not exist in target object
4908
-			$new_array_options=array();
4909
-			foreach ($this->array_options as $key => $value) {
4910
-				if (in_array(substr($key,8), array_keys($target_extrafields)))	// We remove the 'options_' from $key for test
4911
-					$new_array_options[$key] = $value;
4912
-				elseif (in_array($key, array_keys($target_extrafields)))		// We test on $key that does not contains the 'options_' prefix
4913
-					$new_array_options['options_'.$key] = $value;
4914
-			}
4915
-
4916
-			foreach($new_array_options as $key => $value)
4917
-			{
4918
-			   	$attributeKey      = substr($key,8);   // Remove 'options_' prefix
4919
-			   	$attributeType     = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
4920
-			   	$attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$attributeKey];
4921
-			   	$attributeParam    = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
4922
-			   	$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
4923
-
4924
-			   	if ($attributeRequired)
4925
-			   	{
4926
-			   		$mandatorypb=false;
4927
-			   		if ($attributeType == 'link' && $this->array_options[$key] == '-1') $mandatorypb=true;
4928
-			   		if ($this->array_options[$key] === '') $mandatorypb=true;
4929
-			   		if ($mandatorypb)
4930
-			   		{
4931
-			   			dol_syslog($this->error);
4932
-			   			$this->errors[]=$langs->trans('ErrorFieldRequired', $attributeLabel);
4933
-			   			return -1;
4934
-			   		}
4935
-			   	}
4936
-
4937
-				//dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
4938
-				//dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
4939
-
4940
-			   	switch ($attributeType)
4941
-			   	{
4942
-			   		case 'int':
4943
-			  			if (!is_numeric($value) && $value!='')
4944
-			   			{
4945
-			   				$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4946
-			   				return -1;
4947
-			  			}
4948
-			   			elseif ($value=='')
4949
-			   			{
4950
-			   				$new_array_options[$key] = null;
4951
-			   			}
4952
-			 			break;
4953
-					case 'double':
4954
-						$value = price2num($value);
4955
-						if (!is_numeric($value) && $value!='')
4956
-						{
4957
-							dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
4958
-							$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4959
-							return -1;
4960
-						}
4961
-						elseif ($value=='')
4962
-						{
4963
-							$new_array_options[$key] = null;
4964
-						}
4965
-						//dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
4966
-						$new_array_options[$key] = $value;
4967
-						break;
4968
-			 		/*case 'select':	// Not required, we chosed value='0' for undefined values
4969
-             			if ($value=='-1')
4970
-             			{
4971
-             				$this->array_options[$key] = null;
4972
-             			}
4973
-             			break;*/
4974
-			   		case 'password':
4975
-			   			$algo='';
4976
-			   			if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']))
4977
-			   			{
4978
-			   				// If there is an encryption choice, we use it to crypt data before insert
4979
-			   				$tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
4980
-			   				$algo=reset($tmparrays);
4981
-			   				if ($algo != '')
4982
-			   				{
4983
-			   					//global $action;		// $action may be 'create', 'update', 'update_extras'...
4984
-			   					//var_dump($action);
4985
-			   					//var_dump($this->oldcopy);exit;
4986
-			   					if (is_object($this->oldcopy))		// If this->oldcopy is not defined, we can't know if we change attribute or not, so we must keep value
4987
-			   					{
4988
-			   						//var_dump($this->oldcopy->array_options[$key]); var_dump($this->array_options[$key]);
4989
-				   					if ($this->array_options[$key] == $this->oldcopy->array_options[$key])	// If old value crypted in database is same than submited new value, it means we don't change it, so we don't update.
4990
-				   					{
4991
-				   						$new_array_options[$key] = $this->array_options[$key];	// Value is kept
4992
-				   					}
4993
-									else
4994
-									{
4995
-										// var_dump($algo);
4996
-										$newvalue = dol_hash($this->array_options[$key], $algo);
4997
-										$new_array_options[$key] = $newvalue;
4998
-									}
4999
-			   					}
5000
-			   					else
5001
-			   					{
5002
-			   						$new_array_options[$key] = $this->array_options[$key];	// Value is kept
5003
-			   					}
5004
-			   				}
5005
-			   			}
5006
-			   			else	// Common usage
5007
-			   			{
5008
-			   				$new_array_options[$key] = $this->array_options[$key];
5009
-			   			}
5010
-			   			break;
5011
-			   		case 'price':
5012
-						$new_array_options[$key] = price2num($this->array_options[$key]);
5013
-						break;
5014
-					case 'date':
5015
-						$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5016
-						break;
5017
-					case 'datetime':
5018
-						// If data is a string instead of a timestamp, we convert it
5019
-						if (! is_int($this->array_options[$key])) {
5020
-							$this->array_options[$key] = strtotime($this->array_options[$key]);
5021
-						}
5022
-						$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5023
-						break;
5024
-		   			case 'link':
5025
-						$param_list=array_keys($attributeParam['options']);
5026
-						// 0 : ObjectName
5027
-						// 1 : classPath
5028
-						$InfoFieldList = explode(":", $param_list[0]);
5029
-						dol_include_once($InfoFieldList[1]);
5030
-						if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
5031
-						{
5032
-							if ($value == '-1')	// -1 is key for no defined in combo list of objects
5033
-							{
5034
-								$new_array_options[$key]='';
5035
-							}
5036
-							elseif ($value)
5037
-							{
5038
-								$object = new $InfoFieldList[0]($this->db);
5039
-								if (is_numeric($value)) $res=$object->fetch($value);
5040
-								else $res=$object->fetch('',$value);
5041
-
5042
-								if ($res > 0) $new_array_options[$key]=$object->id;
5043
-								else
5044
-								{
5045
-									$this->error="Id/Ref '".$value."' for object '".$object->element."' not found";
5046
-									$this->db->rollback();
5047
-									return -1;
5048
-								}
5049
-							}
5050
-						}
5051
-						else
5052
-						{
5053
-							dol_syslog('Error bad setup of extrafield', LOG_WARNING);
5054
-						}
5055
-						break;
5056
-			   	}
5057
-			}
1572
+        // this->ismultientitymanaged contains
1573
+        // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
1574
+        $alias = 's';
1575
+        if ($this->element == 'societe') $alias = 'te';
5058 1576
 
5059
-			$this->db->begin();
1577
+        $sql = "SELECT MAX(te.".$fieldid.")";
1578
+        $sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1579
+        if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1580
+            $sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1581
+        }
1582
+        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to entity
1583
+        else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to socid
1584
+        else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid";	// If we need to link to societe to limit select to socid
1585
+        if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid)  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
1586
+        $sql.= " WHERE te.".$fieldid." < '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1587
+        if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1588
+        if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1589
+        if (! empty($filter))
1590
+        {
1591
+            if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1592
+            $sql.=$filter;
1593
+        }
1594
+        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to entity
1595
+        else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to socid
1596
+        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1597
+            if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1598
+                if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1599
+                    $sql.= " AND te.entity IS NOT NULL"; // Show all users
1600
+                } else {
1601
+                    $sql.= " AND ug.fk_user = te.rowid";
1602
+                    $sql.= " AND ug.entity IN (".getEntity($this->element).")";
1603
+                }
1604
+            } else {
1605
+                $sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1606
+            }
1607
+        }
1608
+        if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1609
+        if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1610
+        if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1611
+        //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
5060 1612
 
5061
-			$table_element = $this->table_element;
5062
-			if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
1613
+        $result = $this->db->query($sql);
1614
+        if (! $result)
1615
+        {
1616
+            $this->error=$this->db->lasterror();
1617
+            return -1;
1618
+        }
1619
+        $row = $this->db->fetch_row($result);
1620
+        $this->ref_previous = $row[0];
5063 1621
 
5064
-			$sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
5065
-			dol_syslog(get_class($this)."::insertExtraFields delete", LOG_DEBUG);
5066
-			$this->db->query($sql_del);
5067 1622
 
5068
-			$sql = "INSERT INTO ".MAIN_DB_PREFIX.$table_element."_extrafields (fk_object";
5069
-			foreach($new_array_options as $key => $value)
5070
-			{
5071
-				$attributeKey = substr($key,8);   // Remove 'options_' prefix
5072
-				// Add field of attribut
5073
-				if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator
5074
-					$sql.=",".$attributeKey;
5075
-			}
5076
-			$sql .= ") VALUES (".$this->id;
5077
-
5078
-			foreach($new_array_options as $key => $value)
5079
-			{
5080
-				$attributeKey = substr($key,8);   // Remove 'options_' prefix
5081
-				// Add field of attribute
5082
-				if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator)
5083
-				{
5084
-					if ($new_array_options[$key] != '')
5085
-					{
5086
-						$sql.=",'".$this->db->escape($new_array_options[$key])."'";
5087
-					}
5088
-					else
5089
-					{
5090
-						$sql.=",null";
5091
-					}
5092
-				}
5093
-			}
5094
-			$sql.=")";
1623
+        $sql = "SELECT MIN(te.".$fieldid.")";
1624
+        $sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1625
+        if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1626
+            $sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1627
+        }
1628
+        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to entity
1629
+        else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to socid
1630
+        else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid";	// If we need to link to societe to limit select to socid
1631
+        if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
1632
+        $sql.= " WHERE te.".$fieldid." > '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1633
+        if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1634
+        if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1635
+        if (! empty($filter))
1636
+        {
1637
+            if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1638
+            $sql.=$filter;
1639
+        }
1640
+        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to entity
1641
+        else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to socid
1642
+        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1643
+            if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1644
+                if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1645
+                    $sql.= " AND te.entity IS NOT NULL"; // Show all users
1646
+                } else {
1647
+                    $sql.= " AND ug.fk_user = te.rowid";
1648
+                    $sql.= " AND ug.entity IN (".getEntity($this->element).")";
1649
+                }
1650
+            } else {
1651
+                $sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1652
+            }
1653
+        }
1654
+        if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1655
+        if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1656
+        if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1657
+        //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1658
+        // Rem: Bug in some mysql version: SELECT MIN(rowid) FROM llx_socpeople WHERE rowid > 1 when one row in database with rowid=1, returns 1 instead of null
1659
+
1660
+        $result = $this->db->query($sql);
1661
+        if (! $result)
1662
+        {
1663
+            $this->error=$this->db->lasterror();
1664
+            return -2;
1665
+        }
1666
+        $row = $this->db->fetch_row($result);
1667
+        $this->ref_next = $row[0];
5095 1668
 
5096
-			dol_syslog(get_class($this)."::insertExtraFields insert", LOG_DEBUG);
5097
-			$resql = $this->db->query($sql);
5098
-			if (! $resql)
5099
-			{
5100
-				$this->error=$this->db->lasterror();
5101
-				$error++;
5102
-			}
1669
+        return 1;
1670
+    }
5103 1671
 
5104
-			if (! $error && $trigger)
5105
-			{
5106
-				// Call trigger
5107
-				$this->context=array('extrafieldaddupdate'=>1);
5108
-				$result=$this->call_trigger($trigger, $userused);
5109
-				if ($result < 0) $error++;
5110
-				// End call trigger
5111
-			}
5112
-
5113
-			if ($error)
5114
-			{
5115
-				$this->db->rollback();
5116
-				return -1;
5117
-			}
5118
-			else
5119
-			{
5120
-				$this->db->commit();
5121
-				return 1;
5122
-			}
5123
-		}
5124
-		else return 0;
5125
-	}
5126
-
5127
-	/**
5128
-	 *	Update an extra field value for the current object.
5129
-	 *  Data to describe values to update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
5130
-	 *
5131
-	 *  @param  string      $key    		Key of the extrafield (without starting 'options_')
5132
-	 *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
5133
-	 *  @param	User		$userused		Object user
5134
-	 *  @return int                 		-1=error, O=did nothing, 1=OK
5135
-	 *  @see setValueFrom, insertExtraFields
5136
-	 */
5137
-	function updateExtraField($key, $trigger=null, $userused=null)
5138
-	{
5139
-		global $conf,$langs,$user;
5140
-
5141
-		if (empty($userused)) $userused=$user;
5142
-
5143
-		$error=0;
5144
-
5145
-		if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
5146
-
5147
-		if (! empty($this->array_options) && isset($this->array_options["options_".$key]))
5148
-		{
5149
-			// Check parameters
5150
-			$langs->load('admin');
5151
-			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
5152
-			$extrafields = new ExtraFields($this->db);
5153
-			$target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
5154
-
5155
-			$value=$this->array_options["options_".$key];
5156
-
5157
-			$attributeType     = $extrafields->attributes[$this->table_element]['type'][$key];
5158
-			$attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$key];
5159
-			$attributeParam    = $extrafields->attributes[$this->table_element]['param'][$key];
5160
-			$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
5161
-
5162
-			//dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
5163
-			//dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
5164
-
5165
-			switch ($attributeType)
5166
-			{
5167
-				case 'int':
5168
-					if (!is_numeric($value) && $value!='')
5169
-					{
5170
-						$this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel);
5171
-						return -1;
5172
-					}
5173
-					elseif ($value=='')
5174
-					{
5175
-						$this->array_options["options_".$key] = null;
5176
-					}
5177
-					break;
5178
-				case 'double':
5179
-					$value = price2num($value);
5180
-					if (!is_numeric($value) && $value!='')
5181
-					{
5182
-						dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
5183
-						$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
5184
-						return -1;
5185
-					}
5186
-					elseif ($value=='')
5187
-					{
5188
-						$this->array_options["options_".$key] = null;
5189
-					}
5190
-					//dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
5191
-					$this->array_options["options_".$key] = $value;
5192
-					break;
5193
-			 	/*case 'select':	// Not required, we chosed value='0' for undefined values
5194
-             		if ($value=='-1')
5195
-             		{
5196
-             			$this->array_options[$key] = null;
5197
-             		}
5198
-             		break;*/
5199
-				case 'price':
5200
-					$this->array_options["options_".$key] = price2num($this->array_options["options_".$key]);
5201
-					break;
5202
-				case 'date':
5203
-					$this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5204
-					break;
5205
-				case 'datetime':
5206
-					$this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5207
-					break;
5208
-				case 'link':
5209
-					$param_list=array_keys($attributeParam['options']);
5210
-					// 0 : ObjectName
5211
-					// 1 : classPath
5212
-					$InfoFieldList = explode(":", $param_list[0]);
5213
-					dol_include_once($InfoFieldList[1]);
5214
-					if ($value)
5215
-					{
5216
-						$object = new $InfoFieldList[0]($this->db);
5217
-						$object->fetch(0,$value);
5218
-						$this->array_options["options_".$key]=$object->id;
5219
-					}
5220
-					break;
5221
-			}
5222
-
5223
-			$this->db->begin();
5224
-			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element."_extrafields SET ".$key."='".$this->db->escape($this->array_options["options_".$key])."'";
5225
-			$sql .= " WHERE fk_object = ".$this->id;
5226
-			$resql = $this->db->query($sql);
5227
-			if (! $resql)
5228
-			{
5229
-				$error++;
5230
-				$this->error=$this->db->lasterror();
5231
-			}
5232 1672
 
5233
-			if (! $error && $trigger)
5234
-			{
5235
-				// Call trigger
5236
-				$this->context=array('extrafieldupdate'=>1);
5237
-				$result=$this->call_trigger($trigger, $userused);
5238
-				if ($result < 0) $error++;
5239
-				// End call trigger
5240
-			}
5241
-
5242
-			if ($error)
5243
-			{
5244
-				dol_syslog(get_class($this) . "::".__METHOD__ . $this->error, LOG_ERR);
5245
-				$this->db->rollback();
5246
-				return -1;
5247
-			}
5248
-			else
5249
-			{
5250
-				$this->db->commit();
5251
-				return 1;
5252
-			}
5253
-		}
5254
-		else return 0;
5255
-	}
5256
-
5257
-
5258
-	/**
5259
-	 * Return HTML string to put an input field into a page
5260
-	 * Code very similar with showInputField of extra fields
5261
-	 *
5262
-	 * @param  array   		$val	       Array of properties for field to show
5263
-	 * @param  string  		$key           Key of attribute
5264
-	 * @param  string  		$value         Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value)
5265
-	 * @param  string  		$moreparam     To add more parameters on html input tag
5266
-	 * @param  string  		$keysuffix     Prefix string to add into name and id of field (can be used to avoid duplicate names)
5267
-	 * @param  string  		$keyprefix     Suffix string to add into name and id of field (can be used to avoid duplicate names)
5268
-	 * @param  string|int		$morecss       Value for css to define style/length of field. May also be a numeric.
5269
-	 * @return string
5270
-	 */
5271
-	function showInputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss=0)
5272
-	{
5273
-		global $conf,$langs,$form;
5274
-
5275
-		if (! is_object($form))
5276
-		{
5277
-			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5278
-			$form=new Form($this->db);
5279
-		}
5280
-
5281
-		$val=$this->fields[$key];
5282
-
5283
-		$out='';
5284
-        $type='';
5285
-        $param = array();
5286
-        $param['options']=array();
5287
-        $size =$this->fields[$key]['size'];
5288
-        // Because we work on extrafields
5289
-        if(preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)){
5290
-            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5291
-            $type ='link';
5292
-        } elseif(preg_match('/^link:(.*):(.*)/i', $val['type'], $reg)) {
5293
-            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5294
-            $type ='link';
5295
-        } elseif(preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
5296
-            $param['options']=array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4]=>'N');
5297
-            $type ='sellist';
5298
-        } elseif(preg_match('/varchar\((\d+)\)/', $val['type'],$reg)) {
5299
-            $param['options']=array();
5300
-            $type ='varchar';
5301
-            $size=$reg[1];
5302
-        } elseif(preg_match('/varchar/', $val['type'])) {
5303
-            $param['options']=array();
5304
-            $type ='varchar';
5305
-        } elseif(is_array($this->fields[$key]['arrayofkeyval'])) {
5306
-            $param['options']=$this->fields[$key]['arrayofkeyval'];
5307
-            $type ='select';
5308
-        } else {
5309
-            $param['options']=array();
5310
-            $type =$this->fields[$key]['type'];
1673
+    /**
1674
+     *      Return list of id of contacts of object
1675
+     *
1676
+     *      @param	string	$source     Source of contact: external (llx_socpeople) or internal (llx_user) or thirdparty (llx_societe)
1677
+     *      @return array				Array of id of contacts (if source=external or internal)
1678
+     * 									Array of id of third parties with at least one contact on object (if source=thirdparty)
1679
+     */
1680
+    function getListContactId($source='external')
1681
+    {
1682
+        $contactAlreadySelected = array();
1683
+        $tab = $this->liste_contact(-1,$source);
1684
+        $num=count($tab);
1685
+        $i = 0;
1686
+        while ($i < $num)
1687
+        {
1688
+            if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
1689
+            else  $contactAlreadySelected[$i] = $tab[$i]['id'];
1690
+            $i++;
5311 1691
         }
1692
+        return $contactAlreadySelected;
1693
+    }
5312 1694
 
5313
-		$label=$this->fields[$key]['label'];
5314
-		//$elementtype=$this->fields[$key]['elementtype'];	// Seems not used
5315
-		$default=$this->fields[$key]['default'];
5316
-		$computed=$this->fields[$key]['computed'];
5317
-		$unique=$this->fields[$key]['unique'];
5318
-		$required=$this->fields[$key]['required'];
5319 1695
 
5320
-		$langfile=$this->fields[$key]['langfile'];
5321
-		$list=$this->fields[$key]['list'];
5322
-		$hidden=abs($this->fields[$key]['visible'])!=1?1:0;
1696
+    /**
1697
+     *	Link element with a project
1698
+     *
1699
+     *	@param     	int		$projectid		Project id to link element to
1700
+     *	@return		int						<0 if KO, >0 if OK
1701
+     */
1702
+    function setProject($projectid)
1703
+    {
1704
+        if (! $this->table_element)
1705
+        {
1706
+            dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined",LOG_ERR);
1707
+            return -1;
1708
+        }
5323 1709
 
5324
-		$objectid = $this->id;
1710
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1711
+        if ($this->table_element == 'actioncomm')
1712
+        {
1713
+            if ($projectid) $sql.= ' SET fk_project = '.$projectid;
1714
+            else $sql.= ' SET fk_project = NULL';
1715
+            $sql.= ' WHERE id = '.$this->id;
1716
+        }
1717
+        else
1718
+        {
1719
+            if ($projectid) $sql.= ' SET fk_projet = '.$projectid;
1720
+            else $sql.= ' SET fk_projet = NULL';
1721
+            $sql.= ' WHERE rowid = '.$this->id;
1722
+        }
5325 1723
 
1724
+        dol_syslog(get_class($this)."::setProject", LOG_DEBUG);
1725
+        if ($this->db->query($sql))
1726
+        {
1727
+            $this->fk_project = $projectid;
1728
+            return 1;
1729
+        }
1730
+        else
1731
+        {
1732
+            dol_print_error($this->db);
1733
+            return -1;
1734
+        }
1735
+    }
5326 1736
 
5327
-		if ($computed)
5328
-		{
5329
-			if (! preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
5330
-			else return '';
5331
-		}
1737
+    /**
1738
+     *  Change the payments methods
1739
+     *
1740
+     *  @param		int		$id		Id of new payment method
1741
+     *  @return		int				>0 if OK, <0 if KO
1742
+     */
1743
+    function setPaymentMethods($id)
1744
+    {
1745
+        dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
1746
+        if ($this->statut >= 0 || $this->element == 'societe')
1747
+        {
1748
+            // TODO uniformize field name
1749
+            $fieldname = 'fk_mode_reglement';
1750
+            if ($this->element == 'societe') $fieldname = 'mode_reglement';
1751
+            if (get_class($this) == 'Fournisseur') $fieldname = 'mode_reglement_supplier';
5332 1752
 
1753
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1754
+            $sql .= ' SET '.$fieldname.' = '.$id;
1755
+            $sql .= ' WHERE rowid='.$this->id;
5333 1756
 
5334
-		// Use in priority showsize from parameters, then $val['css'] then autodefine
5335
-		if (empty($morecss) && ! empty($val['css']))
5336
-		{
5337
-			$showsize = $val['css'];
5338
-		}
5339
-		if (empty($morecss))
5340
-		{
5341
-			if ($type == 'date')
5342
-			{
5343
-				$morecss = 'minwidth100imp';
5344
-			}
5345
-			elseif ($type == 'datetime')
5346
-			{
5347
-				$morecss = 'minwidth200imp';
5348
-			}
5349
-			elseif (in_array($type,array('int','integer','price')) || preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5350
-			{
5351
-				$morecss = 'maxwidth75';
5352
-                        }elseif ($type == 'url')
5353
-			{
5354
-				$morecss='minwidth400';
5355
-			}
5356
-			elseif ($type == 'boolean')
5357
-			{
5358
-				$morecss='';
5359
-			}
5360
-			else
5361
-			{
5362
-				if (round($size) < 12)
5363
-				{
5364
-					$morecss = 'minwidth100';
5365
-				}
5366
-				else if (round($size) <= 48)
5367
-				{
5368
-					$morecss = 'minwidth200';
5369
-				}
5370
-				else
5371
-				{
5372
-					$morecss = 'minwidth400';
5373
-				}
5374
-			}
5375
-		}
5376
-
5377
-		if (in_array($type,array('date','datetime')))
5378
-		{
5379
-			$tmp=explode(',',$size);
5380
-			$newsize=$tmp[0];
5381
-
5382
-			$showtime = in_array($type,array('datetime')) ? 1 : 0;
5383
-
5384
-			// Do not show current date when field not required (see selectDate() method)
5385
-			if (!$required && $value == '') $value = '-1';
5386
-
5387
-			// TODO Must also support $moreparam
5388
-			$out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
5389
-		}
5390
-		elseif (in_array($type,array('int','integer')))
5391
-		{
5392
-			$tmp=explode(',',$size);
5393
-			$newsize=$tmp[0];
5394
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$newsize.'" value="'.dol_escape_htmltag($value).'"'.($moreparam?$moreparam:'').'>';
5395
-		}
5396
-		elseif (preg_match('/varchar/', $type))
5397
-		{
5398
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$size.'" value="'.dol_escape_htmltag($value).'"'.($moreparam?$moreparam:'').'>';
5399
-		}
5400
-		elseif (in_array($type, array('mail', 'phone', 'url')))
5401
-		{
5402
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5403
-		}
5404
-		elseif ($type == 'text')
5405
-		{
5406
-			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5407
-			{
5408
-				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5409
-				$doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,false,ROWS_5,'90%');
5410
-				$out=$doleditor->Create(1);
5411
-			}
5412
-			else
5413
-			{
5414
-				$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5415
-			}
5416
-		}
5417
-		elseif ($type == 'html')
5418
-		{
5419
-			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5420
-			{
5421
-				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5422
-				$doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,! empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE,ROWS_5,'90%');
5423
-				$out=$doleditor->Create(1);
5424
-			}
5425
-			else
5426
-			{
5427
-				$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5428
-			}
5429
-		}
5430
-		elseif ($type == 'boolean')
5431
-		{
5432
-			$checked='';
5433
-			if (!empty($value)) {
5434
-				$checked=' checked value="1" ';
5435
-			} else {
5436
-				$checked=' value="1" ';
5437
-			}
5438
-			$out='<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
5439
-		}
5440
-		elseif ($type == 'price')
5441
-		{
5442
-			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5443
-				$value=price($value);
5444
-			}
5445
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> '.$langs->getCurrencySymbol($conf->currency);
5446
-		}
5447
-		elseif (preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5448
-		{
5449
-			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5450
-				$value=price($value);
5451
-			}
5452
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
5453
-		}
5454
-		elseif ($type == 'select')
5455
-		{
5456
-			$out = '';
5457
-			if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5458
-			{
5459
-				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5460
-				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5461
-			}
1757
+            if ($this->db->query($sql))
1758
+            {
1759
+                $this->mode_reglement_id = $id;
1760
+                // for supplier
1761
+                if (get_class($this) == 'Fournisseur') $this->mode_reglement_supplier_id = $id;
1762
+                return 1;
1763
+            }
1764
+            else
1765
+            {
1766
+                dol_syslog(get_class($this).'::setPaymentMethods Erreur '.$sql.' - '.$this->db->error());
1767
+                $this->error=$this->db->error();
1768
+                return -1;
1769
+            }
1770
+        }
1771
+        else
1772
+        {
1773
+            dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
1774
+            $this->error='Status of the object is incompatible '.$this->statut;
1775
+            return -2;
1776
+        }
1777
+    }
5462 1778
 
5463
-			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5464
-                if((! isset($this->fields[$key]['default'])) ||($this->fields[$key]['notnull']!=1))$out.='<option value="0">&nbsp;</option>';
5465
-			foreach ($param['options'] as $key => $val)
5466
-			{
5467
-				if ((string) $key == '') continue;
5468
-				list($val, $parent) = explode('|', $val);
5469
-				$out.='<option value="'.$key.'"';
5470
-				$out.= (((string) $value == (string) $key)?' selected':'');
5471
-				$out.= (!empty($parent)?' parent="'.$parent.'"':'');
5472
-				$out.='>'.$val.'</option>';
5473
-			}
5474
-			$out.='</select>';
5475
-		}
5476
-		elseif ($type == 'sellist')
5477
-		{
5478
-			$out = '';
5479
-			if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5480
-			{
5481
-				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5482
-				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5483
-			}
1779
+    /**
1780
+     *  Change the multicurrency code
1781
+     *
1782
+     *  @param		string	$code	multicurrency code
1783
+     *  @return		int				>0 if OK, <0 if KO
1784
+     */
1785
+    function setMulticurrencyCode($code)
1786
+    {
1787
+        dol_syslog(get_class($this).'::setMulticurrencyCode('.$id.')');
1788
+        if ($this->statut >= 0 || $this->element == 'societe')
1789
+        {
1790
+            $fieldname = 'multicurrency_code';
5484 1791
 
5485
-			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5486
-			if (is_array($param['options']))
5487
-			{
5488
-				$param_list=array_keys($param['options']);
5489
-				$InfoFieldList = explode(":", $param_list[0]);
5490
-				$parentName='';
5491
-				$parentField='';
5492
-				// 0 : tableName
5493
-				// 1 : label field name
5494
-				// 2 : key fields name (if differ of rowid)
5495
-				// 3 : key field parent (for dependent lists)
5496
-				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5497
-				$keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
5498
-
5499
-
5500
-				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
5501
-				{
5502
-					if (strpos($InfoFieldList[4], 'extra.') !== false)
5503
-					{
5504
-						$keyList='main.'.$InfoFieldList[2].' as rowid';
5505
-					} else {
5506
-						$keyList=$InfoFieldList[2].' as rowid';
5507
-					}
5508
-				}
5509
-				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
5510
-				{
5511
-					list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
5512
-					$keyList.= ', '.$parentField;
5513
-				}
1792
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1793
+            $sql .= ' SET '.$fieldname." = '".$this->db->escape($code)."'";
1794
+            $sql .= ' WHERE rowid='.$this->id;
5514 1795
 
5515
-				$fields_label = explode('|',$InfoFieldList[1]);
5516
-				if (is_array($fields_label))
5517
-				{
5518
-					$keyList .=', ';
5519
-					$keyList .= implode(', ', $fields_label);
5520
-				}
1796
+            if ($this->db->query($sql))
1797
+            {
1798
+                $this->multicurrency_code = $code;
5521 1799
 
5522
-				$sqlwhere='';
5523
-				$sql = 'SELECT '.$keyList;
5524
-				$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
5525
-				if (!empty($InfoFieldList[4]))
5526
-				{
5527
-					// can use SELECT request
5528
-					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5529
-						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5530
-					}
5531
-
5532
-					// current object id can be use into filter
5533
-					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5534
-						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5535
-					} else {
5536
-						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5537
-					}
5538
-					//We have to join on extrafield table
5539
-					if (strpos($InfoFieldList[4], 'extra')!==false)
5540
-					{
5541
-						$sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
5542
-						$sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
5543
-					}
5544
-					else
5545
-					{
5546
-						$sqlwhere.= ' WHERE '.$InfoFieldList[4];
5547
-					}
5548
-				}
5549
-				else
5550
-				{
5551
-					$sqlwhere.= ' WHERE 1=1';
5552
-				}
5553
-				// Some tables may have field, some other not. For the moment we disable it.
5554
-				if (in_array($InfoFieldList[0],array('tablewithentity')))
5555
-				{
5556
-					$sqlwhere.= ' AND entity = '.$conf->entity;
5557
-				}
5558
-				$sql.=$sqlwhere;
5559
-				//print $sql;
1800
+                list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
1801
+                if ($rate) $this->setMulticurrencyRate($rate,2);
5560 1802
 
5561
-				$sql .= ' ORDER BY ' . implode(', ', $fields_label);
1803
+                return 1;
1804
+            }
1805
+            else
1806
+            {
1807
+                dol_syslog(get_class($this).'::setMulticurrencyCode Erreur '.$sql.' - '.$this->db->error());
1808
+                $this->error=$this->db->error();
1809
+                return -1;
1810
+            }
1811
+        }
1812
+        else
1813
+        {
1814
+            dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
1815
+            $this->error='Status of the object is incompatible '.$this->statut;
1816
+            return -2;
1817
+        }
1818
+    }
5562 1819
 
5563
-				dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
5564
-				$resql = $this->db->query($sql);
5565
-				if ($resql)
5566
-				{
5567
-					$out.='<option value="0">&nbsp;</option>';
5568
-					$num = $this->db->num_rows($resql);
5569
-					$i = 0;
5570
-					while ($i < $num)
5571
-					{
5572
-						$labeltoshow='';
5573
-						$obj = $this->db->fetch_object($resql);
5574
-
5575
-						// Several field into label (eq table:code|libelle:rowid)
5576
-						$notrans = false;
5577
-						$fields_label = explode('|',$InfoFieldList[1]);
5578
-						if (is_array($fields_label))
5579
-						{
5580
-							$notrans = true;
5581
-							foreach ($fields_label as $field_toshow)
5582
-							{
5583
-								$labeltoshow.= $obj->$field_toshow.' ';
5584
-							}
5585
-						}
5586
-						else
5587
-						{
5588
-							$labeltoshow=$obj->{$InfoFieldList[1]};
5589
-						}
5590
-						$labeltoshow=dol_trunc($labeltoshow,45);
5591
-
5592
-						if ($value == $obj->rowid)
5593
-						{
5594
-							foreach ($fields_label as $field_toshow)
5595
-							{
5596
-								$translabel=$langs->trans($obj->$field_toshow);
5597
-								if ($translabel!=$obj->$field_toshow) {
5598
-									$labeltoshow=dol_trunc($translabel,18).' ';
5599
-								}else {
5600
-									$labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
5601
-								}
5602
-							}
5603
-							$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5604
-						}
5605
-						else
5606
-						{
5607
-							if (! $notrans)
5608
-							{
5609
-								$translabel=$langs->trans($obj->{$InfoFieldList[1]});
5610
-								if ($translabel!=$obj->{$InfoFieldList[1]}) {
5611
-									$labeltoshow=dol_trunc($translabel,18);
5612
-								}
5613
-								else {
5614
-									$labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
5615
-								}
5616
-							}
5617
-							if (empty($labeltoshow)) $labeltoshow='(not defined)';
5618
-							if ($value==$obj->rowid)
5619
-							{
5620
-								$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5621
-							}
1820
+    /**
1821
+     *  Change the multicurrency rate
1822
+     *
1823
+     *  @param		double	$rate	multicurrency rate
1824
+     *  @param		int		$mode	mode 1 : amounts in company currency will be recalculated, mode 2 : amounts in foreign currency
1825
+     *  @return		int				>0 if OK, <0 if KO
1826
+     */
1827
+    function setMulticurrencyRate($rate, $mode=1)
1828
+    {
1829
+        dol_syslog(get_class($this).'::setMulticurrencyRate('.$id.')');
1830
+        if ($this->statut >= 0 || $this->element == 'societe')
1831
+        {
1832
+            $fieldname = 'multicurrency_tx';
5622 1833
 
5623
-							if (!empty($InfoFieldList[3]) && $parentField)
5624
-							{
5625
-								$parent = $parentName.':'.$obj->{$parentField};
5626
-							}
1834
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1835
+            $sql .= ' SET '.$fieldname.' = '.$rate;
1836
+            $sql .= ' WHERE rowid='.$this->id;
5627 1837
 
5628
-							$out.='<option value="'.$obj->rowid.'"';
5629
-							$out.= ($value==$obj->rowid?' selected':'');
5630
-							$out.= (!empty($parent)?' parent="'.$parent.'"':'');
5631
-							$out.='>'.$labeltoshow.'</option>';
5632
-						}
1838
+            if ($this->db->query($sql))
1839
+            {
1840
+                $this->multicurrency_tx = $rate;
1841
+
1842
+                // Update line price
1843
+                if (!empty($this->lines))
1844
+                {
1845
+                    foreach ($this->lines as &$line)
1846
+                    {
1847
+                        if($mode == 1) {
1848
+                            $line->subprice = 0;
1849
+                        }
1850
+
1851
+                        switch ($this->element) {
1852
+                            case 'propal':
1853
+                                $this->updateline(
1854
+                                    $line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1855
+                                    ($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1856
+                                    $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start,
1857
+                                    $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1858
+                                );
1859
+                                break;
1860
+                            case 'commande':
1861
+                                $this->updateline(
1862
+                                    $line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1863
+                                    $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end,
1864
+                                    $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1865
+                                    $line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1866
+                                );
1867
+                                break;
1868
+                            case 'facture':
1869
+                                $this->updateline(
1870
+                                    $line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1871
+                                    $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits,
1872
+                                    $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1873
+                                    $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice
1874
+                                );
1875
+                                break;
1876
+                            case 'supplier_proposal':
1877
+                                $this->updateline(
1878
+                                    $line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1879
+                                    ($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1880
+                                    $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->array_options,
1881
+                                    $line->ref_fourn, $line->multicurrency_subprice
1882
+                                );
1883
+                                break;
1884
+                            case 'order_supplier':
1885
+                                $this->updateline(
1886
+                                    $line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1887
+                                    $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, false,
1888
+                                    $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1889
+                                );
1890
+                                break;
1891
+                            case 'invoice_supplier':
1892
+                                $this->updateline(
1893
+                                    $line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->tva_tx, $line->localtax1_tx,
1894
+                                    $line->localtax2_tx, $line->qty, 0, 'HT', $line->info_bits, $line->product_type, $line->remise_percent, false,
1895
+                                    $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1896
+                                );
1897
+                                break;
1898
+                            default:
1899
+                                dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
1900
+                                break;
1901
+                        }
1902
+                    }
1903
+                }
1904
+
1905
+                return 1;
1906
+            }
1907
+            else
1908
+            {
1909
+                dol_syslog(get_class($this).'::setMulticurrencyRate Erreur '.$sql.' - '.$this->db->error());
1910
+                $this->error=$this->db->error();
1911
+                return -1;
1912
+            }
1913
+        }
1914
+        else
1915
+        {
1916
+            dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
1917
+            $this->error='Status of the object is incompatible '.$this->statut;
1918
+            return -2;
1919
+        }
1920
+    }
5633 1921
 
5634
-						$i++;
5635
-					}
5636
-					$this->db->free($resql);
5637
-				}
5638
-				else {
5639
-					print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
5640
-				}
5641
-			}
5642
-			$out.='</select>';
5643
-		}
5644
-		elseif ($type == 'checkbox')
5645
-		{
5646
-			$value_arr=explode(',',$value);
5647
-			$out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
5648
-		}
5649
-		elseif ($type == 'radio')
5650
-		{
5651
-			$out='';
5652
-			foreach ($param['options'] as $keyopt => $val)
5653
-			{
5654
-				$out.='<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'');
5655
-				$out.=' value="'.$keyopt.'"';
5656
-				$out.=' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
5657
-				$out.= ($value==$keyopt?'checked':'');
5658
-				$out.='/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
5659
-			}
5660
-		}
5661
-		elseif ($type == 'chkbxlst')
5662
-		{
5663
-			if (is_array($value)) {
5664
-				$value_arr = $value;
5665
-			}
5666
-			else {
5667
-				$value_arr = explode(',', $value);
5668
-			}
5669
-
5670
-			if (is_array($param['options'])) {
5671
-				$param_list = array_keys($param['options']);
5672
-				$InfoFieldList = explode(":", $param_list[0]);
5673
-				$parentName='';
5674
-				$parentField='';
5675
-				// 0 : tableName
5676
-				// 1 : label field name
5677
-				// 2 : key fields name (if differ of rowid)
5678
-				// 3 : key field parent (for dependent lists)
5679
-				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5680
-				$keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
5681
-
5682
-				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
5683
-					list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
5684
-					$keyList .= ', ' . $parentField;
5685
-				}
5686
-				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
5687
-					if (strpos($InfoFieldList[4], 'extra.') !== false) {
5688
-						$keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
5689
-					} else {
5690
-						$keyList = $InfoFieldList[2] . ' as rowid';
5691
-					}
5692
-				}
1922
+    /**
1923
+     *  Change the payments terms
1924
+     *
1925
+     *  @param		int		$id		Id of new payment terms
1926
+     *  @return		int				>0 if OK, <0 if KO
1927
+     */
1928
+    function setPaymentTerms($id)
1929
+    {
1930
+        dol_syslog(get_class($this).'::setPaymentTerms('.$id.')');
1931
+        if ($this->statut >= 0 || $this->element == 'societe')
1932
+        {
1933
+            // TODO uniformize field name
1934
+            $fieldname = 'fk_cond_reglement';
1935
+            if ($this->element == 'societe') $fieldname = 'cond_reglement';
1936
+            if (get_class($this) == 'Fournisseur') $fieldname = 'cond_reglement_supplier';
1937
+
1938
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1939
+            $sql .= ' SET '.$fieldname.' = '.$id;
1940
+            $sql .= ' WHERE rowid='.$this->id;
1941
+
1942
+            if ($this->db->query($sql))
1943
+            {
1944
+                $this->cond_reglement_id = $id;
1945
+                // for supplier
1946
+                if (get_class($this) == 'Fournisseur') $this->cond_reglement_supplier_id = $id;
1947
+                $this->cond_reglement = $id;	// for compatibility
1948
+                return 1;
1949
+            }
1950
+            else
1951
+            {
1952
+                dol_syslog(get_class($this).'::setPaymentTerms Erreur '.$sql.' - '.$this->db->error());
1953
+                $this->error=$this->db->error();
1954
+                return -1;
1955
+            }
1956
+        }
1957
+        else
1958
+        {
1959
+            dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
1960
+            $this->error='Status of the object is incompatible '.$this->statut;
1961
+            return -2;
1962
+        }
1963
+    }
1964
+
1965
+    /**
1966
+     *	Define delivery address
1967
+     *  @deprecated
1968
+     *
1969
+     *	@param      int		$id		Address id
1970
+     *	@return     int				<0 si ko, >0 si ok
1971
+     */
1972
+    function setDeliveryAddress($id)
1973
+    {
1974
+        $fieldname = 'fk_delivery_address';
1975
+        if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address';
1976
+
1977
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ".$fieldname." = ".$id;
1978
+        $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1979
+
1980
+        if ($this->db->query($sql))
1981
+        {
1982
+            $this->fk_delivery_address = $id;
1983
+            return 1;
1984
+        }
1985
+        else
1986
+        {
1987
+            $this->error=$this->db->error();
1988
+            dol_syslog(get_class($this).'::setDeliveryAddress Erreur '.$sql.' - '.$this->error);
1989
+            return -1;
1990
+        }
1991
+    }
1992
+
1993
+
1994
+    /**
1995
+     *  Change the shipping method
1996
+     *
1997
+     *  @param      int     $shipping_method_id     Id of shipping method
1998
+     *  @param      bool    $notrigger              false=launch triggers after, true=disable triggers
1999
+     *  @param      User	$userused               Object user
2000
+     *
2001
+     *  @return     int              1 if OK, 0 if KO
2002
+     */
2003
+    function setShippingMethod($shipping_method_id, $notrigger=false, $userused=null)
2004
+    {
2005
+        global $user;
2006
+
2007
+        if (empty($userused)) $userused=$user;
2008
+
2009
+        $error = 0;
2010
+
2011
+        if (! $this->table_element) {
2012
+            dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined",LOG_ERR);
2013
+            return -1;
2014
+        }
2015
+
2016
+        $this->db->begin();
2017
+
2018
+        if ($shipping_method_id<0) $shipping_method_id='NULL';
2019
+        dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
2020
+
2021
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2022
+        $sql.= " SET fk_shipping_method = ".$shipping_method_id;
2023
+        $sql.= " WHERE rowid=".$this->id;
2024
+        $resql = $this->db->query($sql);
2025
+        if (! $resql) {
2026
+            dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2027
+            $this->error = $this->db->lasterror();
2028
+            $error++;
2029
+        } else {
2030
+            if (!$notrigger)
2031
+            {
2032
+                // Call trigger
2033
+                $this->context=array('shippingmethodupdate'=>1);
2034
+                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2035
+                if ($result < 0) $error++;
2036
+                // End call trigger
2037
+            }
2038
+        }
2039
+        if ($error)
2040
+        {
2041
+            $this->db->rollback();
2042
+            return -1;
2043
+        } else {
2044
+            $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id;
2045
+            $this->db->commit();
2046
+            return 1;
2047
+        }
2048
+    }
2049
+
2050
+
2051
+    /**
2052
+     *  Change the warehouse
2053
+     *
2054
+     *  @param      int     $warehouse_id     Id of warehouse
2055
+     *  @return     int              1 if OK, 0 if KO
2056
+     */
2057
+    function setWarehouse($warehouse_id)
2058
+    {
2059
+        if (! $this->table_element) {
2060
+            dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined",LOG_ERR);
2061
+            return -1;
2062
+        }
2063
+        if ($warehouse_id<0) $warehouse_id='NULL';
2064
+        dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2065
+
2066
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2067
+        $sql.= " SET fk_warehouse = ".$warehouse_id;
2068
+        $sql.= " WHERE rowid=".$this->id;
2069
+
2070
+        if ($this->db->query($sql)) {
2071
+            $this->warehouse_id = ($warehouse_id=='NULL')?null:$warehouse_id;
2072
+            return 1;
2073
+        } else {
2074
+            dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2075
+            $this->error=$this->db->error();
2076
+            return 0;
2077
+        }
2078
+    }
2079
+
2080
+
2081
+    /**
2082
+     *		Set last model used by doc generator
2083
+     *
2084
+     *		@param		User	$user		User object that make change
2085
+     *		@param		string	$modelpdf	Modele name
2086
+     *		@return		int					<0 if KO, >0 if OK
2087
+     */
2088
+    function setDocModel($user, $modelpdf)
2089
+    {
2090
+        if (! $this->table_element)
2091
+        {
2092
+            dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined",LOG_ERR);
2093
+            return -1;
2094
+        }
2095
+
2096
+        $newmodelpdf=dol_trunc($modelpdf,255);
2097
+
2098
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2099
+        $sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
2100
+        $sql.= " WHERE rowid = ".$this->id;
2101
+        // if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
2102
+        // if ($this->element == 'propal')  $sql.= " AND fk_statut = 0";
2103
+
2104
+        dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
2105
+        $resql=$this->db->query($sql);
2106
+        if ($resql)
2107
+        {
2108
+            $this->modelpdf=$modelpdf;
2109
+            return 1;
2110
+        }
2111
+        else
2112
+        {
2113
+            dol_print_error($this->db);
2114
+            return 0;
2115
+        }
2116
+    }
2117
+
2118
+
2119
+    /**
2120
+     *  Change the bank account
2121
+     *
2122
+     *  @param		int		$fk_account		Id of bank account
2123
+     *  @param      bool    $notrigger      false=launch triggers after, true=disable triggers
2124
+     *  @param      User	$userused		Object user
2125
+     *  @return		int				1 if OK, 0 if KO
2126
+     */
2127
+    function setBankAccount($fk_account, $notrigger=false, $userused=null)
2128
+    {
2129
+        global $user;
2130
+
2131
+        if (empty($userused)) $userused=$user;
2132
+
2133
+        $error = 0;
2134
+
2135
+        if (! $this->table_element) {
2136
+            dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined",LOG_ERR);
2137
+            return -1;
2138
+        }
2139
+        $this->db->begin();
2140
+
2141
+        if ($fk_account<0) $fk_account='NULL';
2142
+        dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
2143
+
2144
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2145
+        $sql.= " SET fk_account = ".$fk_account;
2146
+        $sql.= " WHERE rowid=".$this->id;
2147
+
2148
+        $resql = $this->db->query($sql);
2149
+        if (! $resql)
2150
+        {
2151
+            dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
2152
+            $this->error = $this->db->lasterror();
2153
+            $error++;
2154
+        }
2155
+        else
2156
+        {
2157
+            if (!$notrigger)
2158
+            {
2159
+                // Call trigger
2160
+                $this->context=array('bankaccountupdate'=>1);
2161
+                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2162
+                if ($result < 0) $error++;
2163
+                // End call trigger
2164
+            }
2165
+        }
2166
+        if ($error)
2167
+        {
2168
+            $this->db->rollback();
2169
+            return -1;
2170
+        }
2171
+        else
2172
+        {
2173
+            $this->fk_account = ($fk_account=='NULL')?null:$fk_account;
2174
+            $this->db->commit();
2175
+            return 1;
2176
+        }
2177
+    }
2178
+
2179
+
2180
+    // TODO: Move line related operations to CommonObjectLine?
2181
+
2182
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2183
+    /**
2184
+     *  Save a new position (field rang) for details lines.
2185
+     *  You can choose to set position for lines with already a position or lines without any position defined.
2186
+     *
2187
+     * 	@param		boolean		$renum			   True to renum all already ordered lines, false to renum only not already ordered lines.
2188
+     * 	@param		string		$rowidorder		   ASC or DESC
2189
+     * 	@param		boolean		$fk_parent_line    Table with fk_parent_line field or not
2190
+     * 	@return		int                            <0 if KO, >0 if OK
2191
+     */
2192
+    function line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
2193
+    {
2194
+        // phpcs:enable
2195
+        if (! $this->table_element_line)
2196
+        {
2197
+            dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined",LOG_ERR);
2198
+            return -1;
2199
+        }
2200
+        if (! $this->fk_element)
2201
+        {
2202
+            dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined",LOG_ERR);
2203
+            return -1;
2204
+        }
2205
+
2206
+        // Count number of lines to reorder (according to choice $renum)
2207
+        $nl=0;
2208
+        $sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2209
+        $sql.= ' WHERE '.$this->fk_element.'='.$this->id;
2210
+        if (! $renum) $sql.= ' AND rang = 0';
2211
+        if ($renum) $sql.= ' AND rang <> 0';
2212
+
2213
+        dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
2214
+        $resql = $this->db->query($sql);
2215
+        if ($resql)
2216
+        {
2217
+            $row = $this->db->fetch_row($resql);
2218
+            $nl = $row[0];
2219
+        }
2220
+        else dol_print_error($this->db);
2221
+        if ($nl > 0)
2222
+        {
2223
+            // The goal of this part is to reorder all lines, with all children lines sharing the same
2224
+            // counter that parents.
2225
+            $rows=array();
2226
+
2227
+            // We first search all lines that are parent lines (for multilevel details lines)
2228
+            $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2229
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2230
+            if ($fk_parent_line) $sql.= ' AND fk_parent_line IS NULL';
2231
+            $sql.= ' ORDER BY rang ASC, rowid '.$rowidorder;
2232
+
2233
+            dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
2234
+            $resql = $this->db->query($sql);
2235
+            if ($resql)
2236
+            {
2237
+                $i=0;
2238
+                $num = $this->db->num_rows($resql);
2239
+                while ($i < $num)
2240
+                {
2241
+                    $row = $this->db->fetch_row($resql);
2242
+                    $rows[] = $row[0];	// Add parent line into array rows
2243
+                    $childrens = $this->getChildrenOfLine($row[0]);
2244
+                    if (! empty($childrens))
2245
+                    {
2246
+                        foreach($childrens as $child)
2247
+                        {
2248
+                            array_push($rows, $child);
2249
+                        }
2250
+                    }
2251
+                    $i++;
2252
+                }
2253
+
2254
+                // Now we set a new number for each lines (parent and children with children included into parent tree)
2255
+                if (! empty($rows))
2256
+                {
2257
+                    foreach($rows as $key => $row)
2258
+                    {
2259
+                        $this->updateRangOfLine($row, ($key+1));
2260
+                    }
2261
+                }
2262
+            }
2263
+            else
2264
+            {
2265
+                dol_print_error($this->db);
2266
+            }
2267
+        }
2268
+        return 1;
2269
+    }
2270
+
2271
+    /**
2272
+     * 	Get children of line
2273
+     *
2274
+     * 	@param	int		$id		Id of parent line
2275
+     * 	@return	array			Array with list of children lines id
2276
+     */
2277
+    function getChildrenOfLine($id)
2278
+    {
2279
+        $rows=array();
2280
+
2281
+        $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2282
+        $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2283
+        $sql.= ' AND fk_parent_line = '.$id;
2284
+        $sql.= ' ORDER BY rang ASC';
2285
+
2286
+        dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id."", LOG_DEBUG);
2287
+        $resql = $this->db->query($sql);
2288
+        if ($resql)
2289
+        {
2290
+            $i=0;
2291
+            $num = $this->db->num_rows($resql);
2292
+            while ($i < $num)
2293
+            {
2294
+                $row = $this->db->fetch_row($resql);
2295
+                $rows[$i] = $row[0];
2296
+                $i++;
2297
+            }
2298
+        }
2299
+
2300
+        return $rows;
2301
+    }
2302
+
2303
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2304
+    /**
2305
+     * 	Update a line to have a lower rank
2306
+     *
2307
+     * 	@param 	int			$rowid				Id of line
2308
+     * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2309
+     * 	@return	void
2310
+     */
2311
+    function line_up($rowid, $fk_parent_line=true)
2312
+    {
2313
+        // phpcs:enable
2314
+        $this->line_order(false, 'ASC', $fk_parent_line);
2315
+
2316
+        // Get rang of line
2317
+        $rang = $this->getRangOfLine($rowid);
2318
+
2319
+        // Update position of line
2320
+        $this->updateLineUp($rowid, $rang);
2321
+    }
2322
+
2323
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2324
+    /**
2325
+     * 	Update a line to have a higher rank
2326
+     *
2327
+     * 	@param	int			$rowid				Id of line
2328
+     * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2329
+     * 	@return	void
2330
+     */
2331
+    function line_down($rowid, $fk_parent_line=true)
2332
+    {
2333
+        // phpcs:enable
2334
+        $this->line_order(false, 'ASC', $fk_parent_line);
2335
+
2336
+        // Get rang of line
2337
+        $rang = $this->getRangOfLine($rowid);
2338
+
2339
+        // Get max value for rang
2340
+        $max = $this->line_max();
2341
+
2342
+        // Update position of line
2343
+        $this->updateLineDown($rowid, $rang, $max);
2344
+    }
2345
+
2346
+    /**
2347
+     * 	Update position of line (rang)
2348
+     *
2349
+     * 	@param	int		$rowid		Id of line
2350
+     * 	@param	int		$rang		Position
2351
+     * 	@return	void
2352
+     */
2353
+    function updateRangOfLine($rowid,$rang)
2354
+    {
2355
+        $fieldposition = 'rang';
2356
+        if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2357
+
2358
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2359
+        $sql.= ' WHERE rowid = '.$rowid;
2360
+
2361
+        dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
2362
+        if (! $this->db->query($sql))
2363
+        {
2364
+            dol_print_error($this->db);
2365
+        }
2366
+    }
2367
+
2368
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2369
+    /**
2370
+     * 	Update position of line with ajax (rang)
2371
+     *
2372
+     * 	@param	array	$rows	Array of rows
2373
+     * 	@return	void
2374
+     */
2375
+    function line_ajaxorder($rows)
2376
+    {
2377
+        // phpcs:enable
2378
+        $num = count($rows);
2379
+        for ($i = 0 ; $i < $num ; $i++)
2380
+        {
2381
+            $this->updateRangOfLine($rows[$i], ($i+1));
2382
+        }
2383
+    }
2384
+
2385
+    /**
2386
+     * 	Update position of line up (rang)
2387
+     *
2388
+     * 	@param	int		$rowid		Id of line
2389
+     * 	@param	int		$rang		Position
2390
+     * 	@return	void
2391
+     */
2392
+    function updateLineUp($rowid,$rang)
2393
+    {
2394
+        if ($rang > 1)
2395
+        {
2396
+            $fieldposition = 'rang';
2397
+            if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2398
+
2399
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang ;
2400
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2401
+            $sql.= ' AND rang = '.($rang - 1);
2402
+            if ($this->db->query($sql) )
2403
+            {
2404
+                $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang - 1);
2405
+                $sql.= ' WHERE rowid = '.$rowid;
2406
+                if (! $this->db->query($sql) )
2407
+                {
2408
+                    dol_print_error($this->db);
2409
+                }
2410
+            }
2411
+            else
2412
+            {
2413
+                dol_print_error($this->db);
2414
+            }
2415
+        }
2416
+    }
2417
+
2418
+    /**
2419
+     * 	Update position of line down (rang)
2420
+     *
2421
+     * 	@param	int		$rowid		Id of line
2422
+     * 	@param	int		$rang		Position
2423
+     * 	@param	int		$max		Max
2424
+     * 	@return	void
2425
+     */
2426
+    function updateLineDown($rowid,$rang,$max)
2427
+    {
2428
+        if ($rang < $max)
2429
+        {
2430
+            $fieldposition = 'rang';
2431
+            if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2432
+
2433
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2434
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2435
+            $sql.= ' AND rang = '.($rang+1);
2436
+            if ($this->db->query($sql) )
2437
+            {
2438
+                $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang+1);
2439
+                $sql.= ' WHERE rowid = '.$rowid;
2440
+                if (! $this->db->query($sql) )
2441
+                {
2442
+                    dol_print_error($this->db);
2443
+                }
2444
+            }
2445
+            else
2446
+            {
2447
+                dol_print_error($this->db);
2448
+            }
2449
+        }
2450
+    }
2451
+
2452
+    /**
2453
+     * 	Get position of line (rang)
2454
+     *
2455
+     * 	@param		int		$rowid		Id of line
2456
+     *  @return		int     			Value of rang in table of lines
2457
+     */
2458
+    function getRangOfLine($rowid)
2459
+    {
2460
+        $sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2461
+        $sql.= ' WHERE rowid ='.$rowid;
2462
+
2463
+        dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
2464
+        $resql = $this->db->query($sql);
2465
+        if ($resql)
2466
+        {
2467
+            $row = $this->db->fetch_row($resql);
2468
+            return $row[0];
2469
+        }
2470
+    }
2471
+
2472
+    /**
2473
+     * 	Get rowid of the line relative to its position
2474
+     *
2475
+     * 	@param		int		$rang		Rang value
2476
+     *  @return     int     			Rowid of the line
2477
+     */
2478
+    function getIdOfLine($rang)
2479
+    {
2480
+        $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2481
+        $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2482
+        $sql.= ' AND rang = '.$rang;
2483
+        $resql = $this->db->query($sql);
2484
+        if ($resql)
2485
+        {
2486
+            $row = $this->db->fetch_row($resql);
2487
+            return $row[0];
2488
+        }
2489
+    }
2490
+
2491
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2492
+    /**
2493
+     * 	Get max value used for position of line (rang)
2494
+     *
2495
+     * 	@param		int		$fk_parent_line		Parent line id
2496
+     *  @return     int  			   			Max value of rang in table of lines
2497
+     */
2498
+    function line_max($fk_parent_line=0)
2499
+    {
2500
+        // phpcs:enable
2501
+        // Search the last rang with fk_parent_line
2502
+        if ($fk_parent_line)
2503
+        {
2504
+            $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2505
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2506
+            $sql.= ' AND fk_parent_line = '.$fk_parent_line;
2507
+
2508
+            dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2509
+            $resql = $this->db->query($sql);
2510
+            if ($resql)
2511
+            {
2512
+                $row = $this->db->fetch_row($resql);
2513
+                if (! empty($row[0]))
2514
+                {
2515
+                    return $row[0];
2516
+                }
2517
+                else
2518
+                {
2519
+                    return $this->getRangOfLine($fk_parent_line);
2520
+                }
2521
+            }
2522
+        }
2523
+        // If not, search the last rang of element
2524
+        else
2525
+        {
2526
+            $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2527
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2528
+
2529
+            dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2530
+            $resql = $this->db->query($sql);
2531
+            if ($resql)
2532
+            {
2533
+                $row = $this->db->fetch_row($resql);
2534
+                return $row[0];
2535
+            }
2536
+        }
2537
+    }
2538
+
2539
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2540
+    /**
2541
+     *  Update external ref of element
2542
+     *
2543
+     *  @param      string		$ref_ext	Update field ref_ext
2544
+     *  @return     int      		   		<0 if KO, >0 if OK
2545
+     */
2546
+    function update_ref_ext($ref_ext)
2547
+    {
2548
+        // phpcs:enable
2549
+        if (! $this->table_element)
2550
+        {
2551
+            dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
2552
+            return -1;
2553
+        }
2554
+
2555
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2556
+        $sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
2557
+        $sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id;
2558
+
2559
+        dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
2560
+        if ($this->db->query($sql))
2561
+        {
2562
+            $this->ref_ext = $ref_ext;
2563
+            return 1;
2564
+        }
2565
+        else
2566
+        {
2567
+            $this->error=$this->db->error();
2568
+            return -1;
2569
+        }
2570
+    }
2571
+
2572
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2573
+    /**
2574
+     *  Update note of element
2575
+     *
2576
+     *  @param      string		$note		New value for note
2577
+     *  @param		string		$suffix		'', '_public' or '_private'
2578
+     *  @return     int      		   		<0 if KO, >0 if OK
2579
+     */
2580
+    function update_note($note, $suffix='')
2581
+    {
2582
+        // phpcs:enable
2583
+        global $user;
2584
+
2585
+        if (! $this->table_element)
2586
+        {
2587
+            $this->error='update_note was called on objet with property table_element not defined';
2588
+            dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
2589
+            return -1;
2590
+        }
2591
+        if (! in_array($suffix,array('','_public','_private')))
2592
+        {
2593
+            $this->error='update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
2594
+            dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
2595
+            return -2;
2596
+        }
2597
+        // Special cas
2598
+        //var_dump($this->table_element);exit;
2599
+        if ($this->table_element == 'product') $suffix='';
2600
+
2601
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2602
+        $sql.= " SET note".$suffix." = ".(!empty($note)?("'".$this->db->escape($note)."'"):"NULL");
2603
+        $sql.= " ,".(in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))?"fk_user_mod":"fk_user_modif")." = ".$user->id;
2604
+        $sql.= " WHERE rowid =". $this->id;
2605
+
2606
+        dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
2607
+        if ($this->db->query($sql))
2608
+        {
2609
+            if ($suffix == '_public') $this->note_public = $note;
2610
+            else if ($suffix == '_private') $this->note_private = $note;
2611
+            else
2612
+            {
2613
+                $this->note = $note;      // deprecated
2614
+                $this->note_private = $note;
2615
+            }
2616
+            return 1;
2617
+        }
2618
+        else
2619
+        {
2620
+            $this->error=$this->db->lasterror();
2621
+            return -1;
2622
+        }
2623
+    }
2624
+
2625
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2626
+    /**
2627
+     * 	Update public note (kept for backward compatibility)
2628
+     *
2629
+     * @param      string		$note		New value for note
2630
+     * @return     int      		   		<0 if KO, >0 if OK
2631
+     * @deprecated
2632
+     * @see update_note()
2633
+     */
2634
+    function update_note_public($note)
2635
+    {
2636
+        // phpcs:enable
2637
+        return $this->update_note($note,'_public');
2638
+    }
2639
+
2640
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2641
+    /**
2642
+     *	Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
2643
+     *  Must be called at end of methods addline or updateline.
2644
+     *
2645
+     *	@param	int		$exclspec          	>0 = Exclude special product (product_type=9)
2646
+     *  @param  string	$roundingadjust    	'none'=Do nothing, 'auto'=Use default method (MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND if defined, or '0'), '0'=Force mode total of rounding, '1'=Force mode rounding of total
2647
+     *  @param	int		$nodatabaseupdate	1=Do not update database. Update only properties of object.
2648
+     *  @param	Societe	$seller				If roundingadjust is '0' or '1' or maybe 'auto', it means we recalculate total for lines before calculating total for object and for this, we need seller object.
2649
+     *	@return	int    			           	<0 if KO, >0 if OK
2650
+     */
2651
+    function update_price($exclspec=0,$roundingadjust='none',$nodatabaseupdate=0,$seller=null)
2652
+    {
2653
+        // phpcs:enable
2654
+        global $conf, $hookmanager, $action;
2655
+
2656
+        // Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
2657
+        $MODULE = "";
2658
+        if ($this->element == 'propal')
2659
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
2660
+        elseif ($this->element == 'order')
2661
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
2662
+        elseif ($this->element == 'facture')
2663
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
2664
+        elseif ($this->element == 'facture_fourn')
2665
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
2666
+        elseif ($this->element == 'order_supplier')
2667
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
2668
+        elseif ($this->element == 'supplier_proposal')
2669
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
2670
+
2671
+        if (! empty($MODULE)) {
2672
+            if (! empty($conf->global->$MODULE)) {
2673
+                $modsactivated = explode(',', $conf->global->$MODULE);
2674
+                foreach ($modsactivated as $mod) {
2675
+                    if ($conf->$mod->enabled)
2676
+                        return 1; // update was disabled by specific setup
2677
+                }
2678
+            }
2679
+        }
2680
+
2681
+        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2682
+
2683
+        if ($roundingadjust == '-1') $roundingadjust='auto';	// For backward compatibility
2684
+
2685
+        $forcedroundingmode=$roundingadjust;
2686
+        if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) $forcedroundingmode=$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND;
2687
+        elseif ($forcedroundingmode == 'auto') $forcedroundingmode='0';
2688
+
2689
+        $error=0;
2690
+
2691
+        $multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
2692
+
2693
+        // Define constants to find lines to sum
2694
+        $fieldtva='total_tva';
2695
+        $fieldlocaltax1='total_localtax1';
2696
+        $fieldlocaltax2='total_localtax2';
2697
+        $fieldup='subprice';
2698
+        if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
2699
+        {
2700
+            $fieldtva='tva';
2701
+            $fieldup='pu_ht';
2702
+        }
2703
+        if ($this->element == 'expensereport')
2704
+        {
2705
+            $fieldup='value_unit';
2706
+        }
2707
+
2708
+        $sql = 'SELECT rowid, qty, '.$fieldup.' as up, remise_percent, total_ht, '.$fieldtva.' as total_tva, total_ttc, '.$fieldlocaltax1.' as total_localtax1, '.$fieldlocaltax2.' as total_localtax2,';
2709
+        $sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
2710
+            if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent';
2711
+            $sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
2712
+        $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2713
+        $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2714
+        if ($exclspec)
2715
+        {
2716
+            $product_field='product_type';
2717
+            if ($this->table_element_line == 'contratdet') $product_field='';    // contratdet table has no product_type field
2718
+            if ($product_field) $sql.= ' AND '.$product_field.' <> 9';
2719
+        }
2720
+        $sql.= ' ORDER by rowid';	// We want to be sure to always use same order of line to not change lines differently when option MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND is used
2721
+
2722
+        dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2723
+        $resql = $this->db->query($sql);
2724
+        if ($resql)
2725
+        {
2726
+            $this->total_ht  = 0;
2727
+            $this->total_tva = 0;
2728
+            $this->total_localtax1 = 0;
2729
+            $this->total_localtax2 = 0;
2730
+            $this->total_ttc = 0;
2731
+            $total_ht_by_vats  = array();
2732
+            $total_tva_by_vats = array();
2733
+            $total_ttc_by_vats = array();
2734
+            $this->multicurrency_total_ht	= 0;
2735
+            $this->multicurrency_total_tva	= 0;
2736
+            $this->multicurrency_total_ttc	= 0;
2737
+
2738
+            $num = $this->db->num_rows($resql);
2739
+            $i = 0;
2740
+            while ($i < $num)
2741
+            {
2742
+                $obj = $this->db->fetch_object($resql);
2743
+
2744
+                // Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
2745
+                $parameters=array('fk_element' => $obj->rowid);
2746
+                $reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2747
+
2748
+                if (empty($reshook) && $forcedroundingmode == '0')	// Check if data on line are consistent. This may solve lines that were not consistent because set with $forcedroundingmode='auto'
2749
+                {
2750
+                    $localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx);
2751
+                    $tmpcal=calcul_price_total($obj->qty, $obj->up, $obj->remise_percent, $obj->vatrate, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $obj->info_bits, $obj->product_type, $seller, $localtax_array, (isset($obj->situation_percent) ? $obj->situation_percent : 100), $multicurrency_tx);
2752
+                    $diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1);
2753
+                    if ($diff)
2754
+                    {
2755
+                        $sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid;
2756
+                        dol_syslog('We found unconsistent data into detailed line (difference of '.$diff.') for line rowid = '.$obj->rowid." (total vat of line calculated=".$tmpcal[1].", database=".$obj->total_tva."). We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix);
2757
+                                $resqlfix=$this->db->query($sqlfix);
2758
+                                if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2759
+                                $obj->total_tva = $tmpcal[1];
2760
+                                $obj->total_ttc = $tmpcal[2];
2761
+                        //
2762
+                    }
2763
+                }
2764
+
2765
+                $this->total_ht        += $obj->total_ht;		// The field visible at end of line detail
2766
+                $this->total_tva       += $obj->total_tva;
2767
+                $this->total_localtax1 += $obj->total_localtax1;
2768
+                $this->total_localtax2 += $obj->total_localtax2;
2769
+                $this->total_ttc       += $obj->total_ttc;
2770
+                $this->multicurrency_total_ht        += $obj->multicurrency_total_ht;		// The field visible at end of line detail
2771
+                $this->multicurrency_total_tva       += $obj->multicurrency_total_tva;
2772
+                $this->multicurrency_total_ttc       += $obj->multicurrency_total_ttc;
2773
+
2774
+                if (! isset($total_ht_by_vats[$obj->vatrate]))  $total_ht_by_vats[$obj->vatrate]=0;
2775
+                if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0;
2776
+                if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0;
2777
+                $total_ht_by_vats[$obj->vatrate]  += $obj->total_ht;
2778
+                $total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
2779
+                $total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
2780
+
2781
+                if ($forcedroundingmode == '1')	// Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency
2782
+                {
2783
+                    $tmpvat=price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
2784
+                    $diff=price2num($total_tva_by_vats[$obj->vatrate]-$tmpvat, 'MT', 1);
2785
+                    //print 'Line '.$i.' rowid='.$obj->rowid.' vat_rate='.$obj->vatrate.' total_ht='.$obj->total_ht.' total_tva='.$obj->total_tva.' total_ttc='.$obj->total_ttc.' total_ht_by_vats='.$total_ht_by_vats[$obj->vatrate].' total_tva_by_vats='.$total_tva_by_vats[$obj->vatrate].' (new calculation = '.$tmpvat.') total_ttc_by_vats='.$total_ttc_by_vats[$obj->vatrate].($diff?" => DIFF":"")."<br>\n";
2786
+                    if ($diff)
2787
+                    {
2788
+                        if (abs($diff) > 0.1) { dol_syslog('A rounding difference was detected into TOTAL but is too high to be corrected', LOG_WARNING); exit; }
2789
+                        $sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".($obj->total_tva - $diff).", total_ttc = ".($obj->total_ttc - $diff)." WHERE rowid = ".$obj->rowid;
2790
+                        dol_syslog('We found a difference of '.$diff.' for line rowid = '.$obj->rowid.". We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix);
2791
+                                $resqlfix=$this->db->query($sqlfix);
2792
+                                if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2793
+                                $this->total_tva -= $diff;
2794
+                                $this->total_ttc -= $diff;
2795
+                                $total_tva_by_vats[$obj->vatrate] -= $diff;
2796
+                                $total_ttc_by_vats[$obj->vatrate] -= $diff;
2797
+                    }
2798
+                }
2799
+
2800
+                $i++;
2801
+            }
2802
+
2803
+            // Add revenue stamp to total
2804
+            $this->total_ttc       			+= isset($this->revenuestamp)?$this->revenuestamp:0;
2805
+            $this->multicurrency_total_ttc  += isset($this->revenuestamp)?($this->revenuestamp * $multicurrency_tx):0;
2806
+
2807
+            // Situations totals
2808
+            if ($this->situation_cycle_ref && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE )
2809
+            {
2810
+                $prev_sits = $this->get_prev_sits();
2811
+
2812
+                foreach ($prev_sits as $sit) {				// $sit is an object Facture loaded with a fetch.
2813
+                    $this->total_ht -= $sit->total_ht;
2814
+                    $this->total_tva -= $sit->total_tva;
2815
+                    $this->total_localtax1 -= $sit->total_localtax1;
2816
+                    $this->total_localtax2 -= $sit->total_localtax2;
2817
+                    $this->total_ttc -= $sit->total_ttc;
2818
+                    $this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
2819
+                    $this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
2820
+                    $this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
2821
+                }
2822
+            }
2823
+
2824
+            $this->db->free($resql);
2825
+
2826
+            // Now update global field total_ht, total_ttc and tva
2827
+            $fieldht='total_ht';
2828
+            $fieldtva='tva';
2829
+            $fieldlocaltax1='localtax1';
2830
+            $fieldlocaltax2='localtax2';
2831
+            $fieldttc='total_ttc';
2832
+            // Specific code for backward compatibility with old field names
2833
+            if ($this->element == 'facture' || $this->element == 'facturerec')             $fieldht='total';
2834
+            if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva';
2835
+            if ($this->element == 'propal')                                                $fieldttc='total';
2836
+            if ($this->element == 'expensereport')                                         $fieldtva='total_tva';
2837
+            if ($this->element == 'supplier_proposal')                                     $fieldttc='total';
2838
+
2839
+            if (empty($nodatabaseupdate))
2840
+            {
2841
+                $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
2842
+                $sql .= " ".$fieldht."='".price2num($this->total_ht)."',";
2843
+                $sql .= " ".$fieldtva."='".price2num($this->total_tva)."',";
2844
+                $sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',";
2845
+                $sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',";
2846
+                $sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'";
2847
+                        $sql .= ", multicurrency_total_ht='".price2num($this->multicurrency_total_ht, 'MT', 1)."'";
2848
+                        $sql .= ", multicurrency_total_tva='".price2num($this->multicurrency_total_tva, 'MT', 1)."'";
2849
+                        $sql .= ", multicurrency_total_ttc='".price2num($this->multicurrency_total_ttc, 'MT', 1)."'";
2850
+                $sql .= ' WHERE rowid = '.$this->id;
2851
+
2852
+
2853
+                dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2854
+                $resql=$this->db->query($sql);
2855
+                if (! $resql)
2856
+                {
2857
+                    $error++;
2858
+                    $this->error=$this->db->lasterror();
2859
+                    $this->errors[]=$this->db->lasterror();
2860
+                }
2861
+            }
2862
+
2863
+            if (! $error)
2864
+            {
2865
+                return 1;
2866
+            }
2867
+            else
2868
+            {
2869
+                return -1;
2870
+            }
2871
+        }
2872
+        else
2873
+        {
2874
+            dol_print_error($this->db,'Bad request in update_price');
2875
+            return -1;
2876
+        }
2877
+    }
2878
+
2879
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2880
+    /**
2881
+     *	Add objects linked in llx_element_element.
2882
+     *
2883
+     *	@param		string	$origin		Linked element type
2884
+     *	@param		int		$origin_id	Linked element id
2885
+     *	@return		int					<=0 if KO, >0 if OK
2886
+     *	@see		fetchObjectLinked, updateObjectLinked, deleteObjectLinked
2887
+     */
2888
+    function add_object_linked($origin=null, $origin_id=null)
2889
+    {
2890
+        // phpcs:enable
2891
+        $origin = (! empty($origin) ? $origin : $this->origin);
2892
+        $origin_id = (! empty($origin_id) ? $origin_id : $this->origin_id);
2893
+
2894
+        // Special case
2895
+        if ($origin == 'order') $origin='commande';
2896
+        if ($origin == 'invoice') $origin='facture';
2897
+        if ($origin == 'invoice_template') $origin='facturerec';
2898
+        if ($origin == 'supplierorder') $origin='order_supplier';
2899
+        $this->db->begin();
2900
+
2901
+        $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
2902
+        $sql.= "fk_source";
2903
+        $sql.= ", sourcetype";
2904
+        $sql.= ", fk_target";
2905
+        $sql.= ", targettype";
2906
+        $sql.= ") VALUES (";
2907
+        $sql.= $origin_id;
2908
+        $sql.= ", '".$this->db->escape($origin)."'";
2909
+        $sql.= ", ".$this->id;
2910
+        $sql.= ", '".$this->db->escape($this->element)."'";
2911
+        $sql.= ")";
2912
+
2913
+        dol_syslog(get_class($this)."::add_object_linked", LOG_DEBUG);
2914
+        if ($this->db->query($sql))
2915
+            {
2916
+                $this->db->commit();
2917
+                return 1;
2918
+            }
2919
+            else
2920
+            {
2921
+                $this->error=$this->db->lasterror();
2922
+                $this->db->rollback();
2923
+                return 0;
2924
+            }
2925
+    }
2926
+
2927
+    /**
2928
+     *	Fetch array of objects linked to current object (object of enabled modules only). Links are loaded into
2929
+     *		this->linkedObjectsIds array and
2930
+     *		this->linkedObjects array if $loadalsoobjects = 1
2931
+     *  Possible usage for parameters:
2932
+     *  - all parameters empty -> we look all link to current object (current object can be source or target)
2933
+     *  - source id+type -> will get target list linked to source
2934
+     *  - target id+type -> will get source list linked to target
2935
+     *  - source id+type + target type -> will get target list of the type
2936
+     *  - target id+type + target source -> will get source list of the type
2937
+     *
2938
+     *	@param	int		$sourceid			Object source id (if not defined, id of object)
2939
+     *	@param  string	$sourcetype			Object source type (if not defined, element name of object)
2940
+     *	@param  int		$targetid			Object target id (if not defined, id of object)
2941
+     *	@param  string	$targettype			Object target type (if not defined, elemennt name of object)
2942
+     *	@param  string	$clause				'OR' or 'AND' clause used when both source id and target id are provided
2943
+     *  @param  int		$alsosametype		0=Return only links to object that differs from source type. 1=Include also link to objects of same type.
2944
+     *  @param  string	$orderby			SQL 'ORDER BY' clause
2945
+     *  @param	int		$loadalsoobjects	Load also array this->linkedObjects (Use 0 to increase performances)
2946
+     *	@return int							<0 if KO, >0 if OK
2947
+     *  @see	add_object_linked, updateObjectLinked, deleteObjectLinked
2948
+     */
2949
+    function fetchObjectLinked($sourceid=null,$sourcetype='',$targetid=null,$targettype='',$clause='OR',$alsosametype=1,$orderby='sourcetype',$loadalsoobjects=1)
2950
+    {
2951
+        global $conf;
2952
+
2953
+        $this->linkedObjectsIds=array();
2954
+        $this->linkedObjects=array();
2955
+
2956
+        $justsource=false;
2957
+        $justtarget=false;
2958
+        $withtargettype=false;
2959
+        $withsourcetype=false;
2960
+
2961
+        if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid))
2962
+        {
2963
+            $justsource=true;  // the source (id and type) is a search criteria
2964
+            if (! empty($targettype)) $withtargettype=true;
2965
+        }
2966
+        if (! empty($targetid) && ! empty($targettype) && empty($sourceid))
2967
+        {
2968
+            $justtarget=true;  // the target (id and type) is a search criteria
2969
+            if (! empty($sourcetype)) $withsourcetype=true;
2970
+        }
2971
+
2972
+        $sourceid = (! empty($sourceid) ? $sourceid : $this->id);
2973
+        $targetid = (! empty($targetid) ? $targetid : $this->id);
2974
+        $sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
2975
+        $targettype = (! empty($targettype) ? $targettype : $this->element);
2976
+
2977
+        /*if (empty($sourceid) && empty($targetid))
2978
+		 {
2979
+		 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
2980
+		 return -1;
2981
+		 }*/
2982
+
2983
+        // Links between objects are stored in table element_element
2984
+        $sql = 'SELECT rowid, fk_source, sourcetype, fk_target, targettype';
2985
+        $sql.= ' FROM '.MAIN_DB_PREFIX.'element_element';
2986
+        $sql.= " WHERE ";
2987
+        if ($justsource || $justtarget)
2988
+        {
2989
+            if ($justsource)
2990
+            {
2991
+                $sql.= "fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."'";
2992
+                if ($withtargettype) $sql.= " AND targettype = '".$targettype."'";
2993
+            }
2994
+            else if ($justtarget)
2995
+            {
2996
+                $sql.= "fk_target = ".$targetid." AND targettype = '".$targettype."'";
2997
+                if ($withsourcetype) $sql.= " AND sourcetype = '".$sourcetype."'";
2998
+            }
2999
+        }
3000
+        else
3001
+        {
3002
+            $sql.= "(fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."')";
3003
+            $sql.= " ".$clause." (fk_target = ".$targetid." AND targettype = '".$targettype."')";
3004
+        }
3005
+        $sql .= ' ORDER BY '.$orderby;
3006
+
3007
+        dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG);
3008
+        $resql = $this->db->query($sql);
3009
+        if ($resql)
3010
+        {
3011
+            $num = $this->db->num_rows($resql);
3012
+            $i = 0;
3013
+            while ($i < $num)
3014
+            {
3015
+                $obj = $this->db->fetch_object($resql);
3016
+                if ($justsource || $justtarget)
3017
+                {
3018
+                    if ($justsource)
3019
+                    {
3020
+                        $this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3021
+                    }
3022
+                    else if ($justtarget)
3023
+                    {
3024
+                        $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3025
+                    }
3026
+                }
3027
+                else
3028
+                {
3029
+                    if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype)
3030
+                    {
3031
+                        $this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3032
+                    }
3033
+                    if ($obj->fk_target == $targetid && $obj->targettype == $targettype)
3034
+                    {
3035
+                        $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3036
+                    }
3037
+                }
3038
+                $i++;
3039
+            }
3040
+
3041
+            if (! empty($this->linkedObjectsIds))
3042
+            {
3043
+                $tmparray = $this->linkedObjectsIds;
3044
+                foreach($tmparray as $objecttype => $objectids)       // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
3045
+                {
3046
+                    // Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
3047
+                    $module = $element = $subelement = $objecttype;
3048
+                    if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
3049
+                        && preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
3050
+                    {
3051
+                        $module = $element = $regs[1];
3052
+                        $subelement = $regs[2];
3053
+                    }
3054
+
3055
+                    $classpath = $element.'/class';
3056
+                    // To work with non standard classpath or module name
3057
+                    if ($objecttype == 'facture')			{
3058
+                        $classpath = 'compta/facture/class';
3059
+                    }
3060
+                    else if ($objecttype == 'facturerec')			{
3061
+                        $classpath = 'compta/facture/class'; $module = 'facture';
3062
+                    }
3063
+                    else if ($objecttype == 'propal')			{
3064
+                        $classpath = 'comm/propal/class';
3065
+                    }
3066
+                    else if ($objecttype == 'supplier_proposal')			{
3067
+                        $classpath = 'supplier_proposal/class';
3068
+                    }
3069
+                    else if ($objecttype == 'shipping')			{
3070
+                        $classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon';
3071
+                    }
3072
+                    else if ($objecttype == 'delivery')			{
3073
+                        $classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon';
3074
+                    }
3075
+                    else if ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier')	{
3076
+                        $classpath = 'fourn/class'; $module = 'fournisseur';
3077
+                    }
3078
+                    else if ($objecttype == 'fichinter')			{
3079
+                        $classpath = 'fichinter/class'; $subelement = 'fichinter'; $module = 'ficheinter';
3080
+                    }
3081
+                    else if ($objecttype == 'subscription')			{
3082
+                        $classpath = 'adherents/class'; $module = 'adherent';
3083
+                    }
3084
+
3085
+                    // Set classfile
3086
+                    $classfile = strtolower($subelement); $classname = ucfirst($subelement);
3087
+
3088
+                    if ($objecttype == 'order') {
3089
+                        $classfile = 'commande'; $classname = 'Commande';
3090
+                    }
3091
+                    else if ($objecttype == 'invoice_supplier') {
3092
+                        $classfile = 'fournisseur.facture'; $classname = 'FactureFournisseur';
3093
+                    }
3094
+                    else if ($objecttype == 'order_supplier')   {
3095
+                        $classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur';
3096
+                    }
3097
+                    else if ($objecttype == 'supplier_proposal')   {
3098
+                        $classfile = 'supplier_proposal'; $classname = 'SupplierProposal';
3099
+                    }
3100
+                    else if ($objecttype == 'facturerec')   {
3101
+                        $classfile = 'facture-rec'; $classname = 'FactureRec';
3102
+                    }
3103
+                    else if ($objecttype == 'subscription')   {
3104
+                        $classfile = 'subscription'; $classname = 'Subscription';
3105
+                    }
3106
+
3107
+                    // Here $module, $classfile and $classname are set
3108
+                    if ($conf->$module->enabled && (($element != $this->element) || $alsosametype))
3109
+                    {
3110
+                        if ($loadalsoobjects)
3111
+                        {
3112
+                            dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
3113
+                            //print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
3114
+                            if (class_exists($classname))
3115
+                            {
3116
+                                foreach($objectids as $i => $objectid)	// $i is rowid into llx_element_element
3117
+                                {
3118
+                                    $object = new $classname($this->db);
3119
+                                    $ret = $object->fetch($objectid);
3120
+                                    if ($ret >= 0)
3121
+                                    {
3122
+                                        $this->linkedObjects[$objecttype][$i] = $object;
3123
+                                    }
3124
+                                }
3125
+                            }
3126
+                        }
3127
+                    }
3128
+                    else
3129
+                    {
3130
+                        unset($this->linkedObjectsIds[$objecttype]);
3131
+                    }
3132
+                }
3133
+            }
3134
+            return 1;
3135
+        }
3136
+        else
3137
+        {
3138
+            dol_print_error($this->db);
3139
+            return -1;
3140
+        }
3141
+    }
3142
+
3143
+    /**
3144
+     *	Update object linked of a current object
3145
+     *
3146
+     *	@param	int		$sourceid		Object source id
3147
+     *	@param  string	$sourcetype		Object source type
3148
+     *	@param  int		$targetid		Object target id
3149
+     *	@param  string	$targettype		Object target type
3150
+     *	@return							int	>0 if OK, <0 if KO
3151
+     *	@see	add_object_linked, fetObjectLinked, deleteObjectLinked
3152
+     */
3153
+    function updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='')
3154
+    {
3155
+        $updatesource=false;
3156
+        $updatetarget=false;
3157
+
3158
+        if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $updatesource=true;
3159
+        else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $updatetarget=true;
3160
+
3161
+        $sql = "UPDATE ".MAIN_DB_PREFIX."element_element SET ";
3162
+        if ($updatesource)
3163
+        {
3164
+            $sql.= "fk_source = ".$sourceid;
3165
+            $sql.= ", sourcetype = '".$this->db->escape($sourcetype)."'";
3166
+            $sql.= " WHERE fk_target = ".$this->id;
3167
+            $sql.= " AND targettype = '".$this->db->escape($this->element)."'";
3168
+        }
3169
+        else if ($updatetarget)
3170
+        {
3171
+            $sql.= "fk_target = ".$targetid;
3172
+            $sql.= ", targettype = '".$this->db->escape($targettype)."'";
3173
+            $sql.= " WHERE fk_source = ".$this->id;
3174
+            $sql.= " AND sourcetype = '".$this->db->escape($this->element)."'";
3175
+        }
3176
+
3177
+        dol_syslog(get_class($this)."::updateObjectLinked", LOG_DEBUG);
3178
+        if ($this->db->query($sql))
3179
+        {
3180
+            return 1;
3181
+        }
3182
+        else
3183
+        {
3184
+            $this->error=$this->db->lasterror();
3185
+            return -1;
3186
+        }
3187
+    }
3188
+
3189
+    /**
3190
+     *	Delete all links between an object $this
3191
+     *
3192
+     *	@param	int		$sourceid		Object source id
3193
+     *	@param  string	$sourcetype		Object source type
3194
+     *	@param  int		$targetid		Object target id
3195
+     *	@param  string	$targettype		Object target type
3196
+     *  @param	int		$rowid			Row id of line to delete. If defined, other parameters are not used.
3197
+     *	@return     					int	>0 if OK, <0 if KO
3198
+     *	@see	add_object_linked, updateObjectLinked, fetchObjectLinked
3199
+     */
3200
+    function deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
3201
+    {
3202
+        $deletesource=false;
3203
+        $deletetarget=false;
3204
+
3205
+        if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $deletesource=true;
3206
+        else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $deletetarget=true;
3207
+
3208
+        $sourceid = (! empty($sourceid) ? $sourceid : $this->id);
3209
+        $sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
3210
+        $targetid = (! empty($targetid) ? $targetid : $this->id);
3211
+        $targettype = (! empty($targettype) ? $targettype : $this->element);
3212
+
3213
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_element";
3214
+        $sql.= " WHERE";
3215
+        if ($rowid > 0)
3216
+        {
3217
+            $sql.=" rowid = ".$rowid;
3218
+        }
3219
+        else
3220
+        {
3221
+            if ($deletesource)
3222
+            {
3223
+                $sql.= " fk_source = ".$sourceid." AND sourcetype = '".$this->db->escape($sourcetype)."'";
3224
+                $sql.= " AND fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."'";
3225
+            }
3226
+            else if ($deletetarget)
3227
+            {
3228
+                $sql.= " fk_target = ".$targetid." AND targettype = '".$this->db->escape($targettype)."'";
3229
+                $sql.= " AND fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."'";
3230
+            }
3231
+            else
3232
+            {
3233
+                $sql.= " (fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."')";
3234
+                $sql.= " OR";
3235
+                $sql.= " (fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."')";
3236
+            }
3237
+        }
3238
+
3239
+        dol_syslog(get_class($this)."::deleteObjectLinked", LOG_DEBUG);
3240
+        if ($this->db->query($sql))
3241
+        {
3242
+            return 1;
3243
+        }
3244
+        else
3245
+        {
3246
+            $this->error=$this->db->lasterror();
3247
+            $this->errors[]=$this->error;
3248
+            return -1;
3249
+        }
3250
+    }
3251
+
3252
+    /**
3253
+     *      Set status of an object
3254
+     *
3255
+     *      @param	int		$status			Status to set
3256
+     *      @param	int		$elementId		Id of element to force (use this->id by default)
3257
+     *      @param	string	$elementType	Type of element to force (use this->table_element by default)
3258
+     *      @param	string	$trigkey		Trigger key to use for trigger
3259
+     *      @return int						<0 if KO, >0 if OK
3260
+     */
3261
+    function setStatut($status, $elementId=null, $elementType='', $trigkey='')
3262
+    {
3263
+        global $user,$langs,$conf;
3264
+
3265
+        $savElementId=$elementId;  // To be used later to know if we were using the method using the id of this or not.
3266
+
3267
+        $elementId = (!empty($elementId)?$elementId:$this->id);
3268
+        $elementTable = (!empty($elementType)?$elementType:$this->table_element);
3269
+
3270
+        $this->db->begin();
3271
+
3272
+        $fieldstatus="fk_statut";
3273
+        if ($elementTable == 'facture_rec') $fieldstatus="suspended";
3274
+        if ($elementTable == 'mailing') $fieldstatus="statut";
3275
+        if ($elementTable == 'cronjob') $fieldstatus="status";
3276
+        if ($elementTable == 'user') $fieldstatus="statut";
3277
+        if ($elementTable == 'expensereport') $fieldstatus="fk_statut";
3278
+        if ($elementTable == 'commande_fournisseur_dispatch') $fieldstatus="status";
3279
+
3280
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable;
3281
+        $sql.= " SET ".$fieldstatus." = ".$status;
3282
+        // If status = 1 = validated, update also fk_user_valid
3283
+        if ($status == 1 && $elementTable == 'expensereport') $sql.=", fk_user_valid = ".$user->id;
3284
+        $sql.= " WHERE rowid=".$elementId;
3285
+
3286
+        dol_syslog(get_class($this)."::setStatut", LOG_DEBUG);
3287
+        if ($this->db->query($sql))
3288
+        {
3289
+            $error = 0;
3290
+
3291
+            // Try autoset of trigkey
3292
+            if (empty($trigkey))
3293
+            {
3294
+                if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_SIGN';   // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
3295
+                if ($this->element == 'supplier_proposal' && $status == 3) $trigkey='SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
3296
+                if ($this->element == 'supplier_proposal' && $status == 4) $trigkey='SUPPLIER_PROPOSAL_CLOSE';  // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
3297
+                if ($this->element == 'fichinter' && $status == 3) $trigkey='FICHINTER_CLASSIFY_DONE';
3298
+                if ($this->element == 'fichinter' && $status == 2) $trigkey='FICHINTER_CLASSIFY_BILLED';
3299
+                if ($this->element == 'fichinter' && $status == 1) $trigkey='FICHINTER_CLASSIFY_UNBILLED';
3300
+            }
3301
+
3302
+            if ($trigkey)
3303
+            {
3304
+                // Appel des triggers
3305
+                include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
3306
+                $interface=new Interfaces($this->db);
3307
+                $result=$interface->run_triggers($trigkey,$this,$user,$langs,$conf);
3308
+                if ($result < 0) {
3309
+                    $error++; $this->errors=$interface->errors;
3310
+                }
3311
+                // Fin appel triggers
3312
+            }
3313
+
3314
+            if (! $error)
3315
+            {
3316
+                $this->db->commit();
3317
+
3318
+                if (empty($savElementId))    // If the element we update was $this (so $elementId is null)
3319
+                {
3320
+                    $this->statut = $status;
3321
+                    $this->status = $status;
3322
+                }
3323
+
3324
+                return 1;
3325
+            }
3326
+            else
3327
+            {
3328
+                $this->db->rollback();
3329
+                dol_syslog(get_class($this)."::setStatus ".$this->error,LOG_ERR);
3330
+                return -1;
3331
+            }
3332
+        }
3333
+        else
3334
+        {
3335
+            $this->error=$this->db->lasterror();
3336
+            $this->db->rollback();
3337
+            return -1;
3338
+        }
3339
+    }
3340
+
3341
+
3342
+    /**
3343
+     *  Load type of canvas of an object if it exists
3344
+     *
3345
+     *  @param      int		$id     Record id
3346
+     *  @param      string	$ref    Record ref
3347
+     *  @return		int				<0 if KO, 0 if nothing done, >0 if OK
3348
+     */
3349
+    function getCanvas($id=0,$ref='')
3350
+    {
3351
+        global $conf;
3352
+
3353
+        if (empty($id) && empty($ref)) return 0;
3354
+        if (! empty($conf->global->MAIN_DISABLE_CANVAS)) return 0;    // To increase speed. Not enabled by default.
3355
+
3356
+        // Clean parameters
3357
+        $ref = trim($ref);
3358
+
3359
+        $sql = "SELECT rowid, canvas";
3360
+        $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
3361
+        $sql.= " WHERE entity IN (".getEntity($this->element).")";
3362
+        if (! empty($id))  $sql.= " AND rowid = ".$id;
3363
+        if (! empty($ref)) $sql.= " AND ref = '".$this->db->escape($ref)."'";
3364
+
3365
+        $resql = $this->db->query($sql);
3366
+        if ($resql)
3367
+        {
3368
+            $obj = $this->db->fetch_object($resql);
3369
+            if ($obj)
3370
+            {
3371
+                $this->canvas   = $obj->canvas;
3372
+                return 1;
3373
+            }
3374
+            else return 0;
3375
+        }
3376
+        else
3377
+        {
3378
+            dol_print_error($this->db);
3379
+            return -1;
3380
+        }
3381
+    }
3382
+
3383
+
3384
+    /**
3385
+     * 	Get special code of a line
3386
+     *
3387
+     * 	@param	int		$lineid		Id of line
3388
+     * 	@return	int					Special code
3389
+     */
3390
+    function getSpecialCode($lineid)
3391
+    {
3392
+        $sql = 'SELECT special_code FROM '.MAIN_DB_PREFIX.$this->table_element_line;
3393
+        $sql.= ' WHERE rowid = '.$lineid;
3394
+        $resql = $this->db->query($sql);
3395
+        if ($resql)
3396
+        {
3397
+            $row = $this->db->fetch_row($resql);
3398
+            return $row[0];
3399
+        }
3400
+    }
3401
+
3402
+    /**
3403
+     *  Function to check if an object is used by others.
3404
+     *  Check is done into this->childtables. There is no check into llx_element_element.
3405
+     *
3406
+     *  @param	int		$id			Force id of object
3407
+     *  @return	int					<0 if KO, 0 if not used, >0 if already used
3408
+     */
3409
+    function isObjectUsed($id=0)
3410
+    {
3411
+        global $langs;
3412
+
3413
+        if (empty($id)) $id=$this->id;
3414
+
3415
+        // Check parameters
3416
+        if (! isset($this->childtables) || ! is_array($this->childtables) || count($this->childtables) == 0)
3417
+        {
3418
+            dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
3419
+            return -1;
3420
+        }
3421
+
3422
+        $arraytoscan = $this->childtables;
3423
+        // For backward compatibility, we check if array is old format array('table1', 'table2', ...)
3424
+        $tmparray=array_keys($this->childtables);
3425
+        if (is_numeric($tmparray[0]))
3426
+        {
3427
+            $arraytoscan = array_flip($this->childtables);
3428
+        }
3429
+
3430
+        // Test if child exists
3431
+        $haschild=0;
3432
+        foreach($arraytoscan as $table => $elementname)
3433
+        {
3434
+            //print $id.'-'.$table.'-'.$elementname.'<br>';
3435
+            // Check if third party can be deleted
3436
+            $sql = "SELECT COUNT(*) as nb from ".MAIN_DB_PREFIX.$table;
3437
+            $sql.= " WHERE ".$this->fk_element." = ".$id;
3438
+            $resql=$this->db->query($sql);
3439
+            if ($resql)
3440
+            {
3441
+                $obj=$this->db->fetch_object($resql);
3442
+                if ($obj->nb > 0)
3443
+                {
3444
+                    $langs->load("errors");
3445
+                    //print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
3446
+                    $haschild += $obj->nb;
3447
+                    if (is_numeric($elementname))	// old usage
3448
+                    {
3449
+                        $this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $table);
3450
+                    }
3451
+                    else	// new usage: $elementname=Translation key
3452
+                    {
3453
+                        $this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $langs->transnoentitiesnoconv($elementname));
3454
+                    }
3455
+                    break;    // We found at least one, we stop here
3456
+                }
3457
+            }
3458
+            else
3459
+            {
3460
+                $this->errors[]=$this->db->lasterror();
3461
+                return -1;
3462
+            }
3463
+        }
3464
+        if ($haschild > 0)
3465
+        {
3466
+            $this->errors[]="ErrorRecordHasChildren";
3467
+            return $haschild;
3468
+        }
3469
+        else return 0;
3470
+    }
3471
+
3472
+    /**
3473
+     *  Function to say how many lines object contains
3474
+     *
3475
+     *	@param	int		$predefined		-1=All, 0=Count free product/service only, 1=Count predefined product/service only, 2=Count predefined product, 3=Count predefined service
3476
+     *  @return	int						<0 if KO, 0 if no predefined products, nb of lines with predefined products if found
3477
+     */
3478
+    function hasProductsOrServices($predefined=-1)
3479
+    {
3480
+        $nb=0;
3481
+
3482
+        foreach($this->lines as $key => $val)
3483
+        {
3484
+            $qualified=0;
3485
+            if ($predefined == -1) $qualified=1;
3486
+            if ($predefined == 1 && $val->fk_product > 0) $qualified=1;
3487
+            if ($predefined == 0 && $val->fk_product <= 0) $qualified=1;
3488
+            if ($predefined == 2 && $val->fk_product > 0 && $val->product_type==0) $qualified=1;
3489
+            if ($predefined == 3 && $val->fk_product > 0 && $val->product_type==1) $qualified=1;
3490
+            if ($qualified) $nb++;
3491
+        }
3492
+        dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
3493
+        return $nb;
3494
+    }
3495
+
3496
+    /**
3497
+     * Function that returns the total amount HT of discounts applied for all lines.
3498
+     *
3499
+     * @return 	float
3500
+     */
3501
+    function getTotalDiscount()
3502
+    {
3503
+        $total_discount=0.00;
3504
+
3505
+        $sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
3506
+        $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."det";
3507
+        $sql.= " WHERE ".$this->fk_element." = ".$this->id;
3508
+
3509
+        dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
3510
+        $resql = $this->db->query($sql);
3511
+        if ($resql)
3512
+        {
3513
+            $num=$this->db->num_rows($resql);
3514
+            $i=0;
3515
+            while ($i < $num)
3516
+            {
3517
+                $obj = $this->db->fetch_object($resql);
3518
+
3519
+                $pu_ht = $obj->pu_ht;
3520
+                $qty= $obj->qty;
3521
+                $total_ht = $obj->total_ht;
3522
+
3523
+                $total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
3524
+                $total_discount += $total_discount_line;
3525
+
3526
+                $i++;
3527
+            }
3528
+        }
3529
+
3530
+        //print $total_discount; exit;
3531
+        return price2num($total_discount);
3532
+    }
3533
+
3534
+
3535
+    /**
3536
+     * Return into unit=0, the calculated total of weight and volume of all lines * qty
3537
+     * Calculate by adding weight and volume of each product line, so properties ->volume/volume_units/weight/weight_units must be loaded on line.
3538
+     *
3539
+     * @return  array                           array('weight'=>...,'volume'=>...)
3540
+     */
3541
+    function getTotalWeightVolume()
3542
+    {
3543
+        $totalWeight = 0;
3544
+        $totalVolume = 0;
3545
+        // defined for shipment only
3546
+        $totalOrdered = '';
3547
+        // defined for shipment only
3548
+        $totalToShip = '';
3549
+
3550
+        foreach ($this->lines as $line)
3551
+        {
3552
+            if (isset($line->qty_asked))
3553
+            {
3554
+                if (empty($totalOrdered)) $totalOrdered=0;  // Avoid warning because $totalOrdered is ''
3555
+                $totalOrdered+=$line->qty_asked;    // defined for shipment only
3556
+            }
3557
+            if (isset($line->qty_shipped))
3558
+            {
3559
+                if (empty($totalToShip)) $totalToShip=0;    // Avoid warning because $totalToShip is ''
3560
+                $totalToShip+=$line->qty_shipped;   // defined for shipment only
3561
+            }else if ($line->element == 'commandefournisseurdispatch' && isset($line->qty))
3562
+            {
3563
+                if (empty($totalToShip)) $totalToShip=0;
3564
+                $totalToShip+=$line->qty;   // defined for reception only
3565
+            }
3566
+
3567
+            // Define qty, weight, volume, weight_units, volume_units
3568
+            if ($this->element == 'shipping') {
3569
+                // for shipments
3570
+                $qty = $line->qty_shipped ? $line->qty_shipped : 0;
3571
+            }
3572
+            else {
3573
+                $qty = $line->qty ? $line->qty : 0;
3574
+            }
3575
+
3576
+            $weight = $line->weight ? $line->weight : 0;
3577
+            ($weight==0 && !empty($line->product->weight))? $weight=$line->product->weight: 0;
3578
+            $volume = $line->volume ? $line->volume : 0;
3579
+            ($volume==0 && !empty($line->product->volume))? $volume=$line->product->volume: 0;
3580
+
3581
+            $weight_units=$line->weight_units;
3582
+            ($weight_units==0 && !empty($line->product->weight_units))? $weight_units=$line->product->weight_units: 0;
3583
+            $volume_units=$line->volume_units;
3584
+            ($volume_units==0 && !empty($line->product->volume_units))? $volume_units=$line->product->volume_units: 0;
3585
+
3586
+            $weightUnit=0;
3587
+            $volumeUnit=0;
3588
+            if (! empty($weight_units)) $weightUnit = $weight_units;
3589
+            if (! empty($volume_units)) $volumeUnit = $volume_units;
3590
+
3591
+            if (empty($totalWeight)) $totalWeight=0;  // Avoid warning because $totalWeight is ''
3592
+            if (empty($totalVolume)) $totalVolume=0;  // Avoid warning because $totalVolume is ''
3593
+
3594
+            //var_dump($line->volume_units);
3595
+            if ($weight_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3596
+            {
3597
+                $trueWeightUnit=pow(10, $weightUnit);
3598
+                $totalWeight += $weight * $qty * $trueWeightUnit;
3599
+            }
3600
+            else {
3601
+        if ($weight_units == 99) {
3602
+            // conversion 1 Pound = 0.45359237 KG
3603
+            $trueWeightUnit = 0.45359237;
3604
+            $totalWeight += $weight * $qty * $trueWeightUnit;
3605
+        } elseif ($weight_units == 98) {
3606
+            // conversion 1 Ounce = 0.0283495 KG
3607
+            $trueWeightUnit = 0.0283495;
3608
+            $totalWeight += $weight * $qty * $trueWeightUnit;
3609
+        }
3610
+        else
3611
+                    $totalWeight += $weight * $qty;   // This may be wrong if we mix different units
3612
+            }
3613
+            if ($volume_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3614
+            {
3615
+                //print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
3616
+                $trueVolumeUnit=pow(10, $volumeUnit);
3617
+                //print $line->volume;
3618
+                $totalVolume += $volume * $qty * $trueVolumeUnit;
3619
+            }
3620
+            else
3621
+            {
3622
+                $totalVolume += $volume * $qty;   // This may be wrong if we mix different units
3623
+            }
3624
+        }
3625
+
3626
+        return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
3627
+    }
3628
+
3629
+
3630
+    /**
3631
+     *	Set extra parameters
3632
+     *
3633
+     *	@return	int      <0 if KO, >0 if OK
3634
+     */
3635
+    function setExtraParameters()
3636
+    {
3637
+        $this->db->begin();
3638
+
3639
+        $extraparams = (! empty($this->extraparams) ? json_encode($this->extraparams) : null);
3640
+
3641
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3642
+        $sql.= " SET extraparams = ".(! empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
3643
+        $sql.= " WHERE rowid = ".$this->id;
3644
+
3645
+        dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG);
3646
+        $resql = $this->db->query($sql);
3647
+        if (! $resql)
3648
+        {
3649
+            $this->error=$this->db->lasterror();
3650
+            $this->db->rollback();
3651
+            return -1;
3652
+        }
3653
+        else
3654
+        {
3655
+            $this->db->commit();
3656
+            return 1;
3657
+        }
3658
+    }
3659
+
3660
+
3661
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3662
+    /**
3663
+     *    Return incoterms informations
3664
+     *    TODO Use a cache for label get
3665
+     *
3666
+     *    @return	string	incoterms info
3667
+     */
3668
+    function display_incoterms()
3669
+    {
3670
+        // phpcs:enable
3671
+        $out = '';
3672
+        $this->libelle_incoterms = '';
3673
+        if (!empty($this->fk_incoterms))
3674
+        {
3675
+            $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3676
+            $result = $this->db->query($sql);
3677
+            if ($result)
3678
+            {
3679
+                $res = $this->db->fetch_object($result);
3680
+                $out .= $res->code;
3681
+            }
3682
+        }
3683
+
3684
+        $out .= (($res->code && $this->location_incoterms)?' - ':'').$this->location_incoterms;
3685
+
3686
+        return $out;
3687
+    }
3688
+
3689
+    /**
3690
+     *    Return incoterms informations for pdf display
3691
+     *
3692
+     *    @return	string		incoterms info
3693
+     */
3694
+    function getIncotermsForPDF()
3695
+    {
3696
+        $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3697
+        $resql = $this->db->query($sql);
3698
+        if ($resql)
3699
+        {
3700
+            $num = $this->db->num_rows($resql);
3701
+            if ($num > 0)
3702
+            {
3703
+                $res = $this->db->fetch_object($resql);
3704
+                return 'Incoterm : '.$res->code.' - '.$this->location_incoterms;
3705
+            }
3706
+            else
3707
+            {
3708
+                return '';
3709
+            }
3710
+        }
3711
+        else
3712
+        {
3713
+            $this->errors[] = $this->db->lasterror();
3714
+            return false;
3715
+        }
3716
+    }
3717
+
3718
+    /**
3719
+     *    Define incoterms values of current object
3720
+     *
3721
+     *    @param	int		$id_incoterm     Id of incoterm to set or '' to remove
3722
+     * 	  @param 	string  $location		 location of incoterm
3723
+     *    @return	int     		<0 if KO, >0 if OK
3724
+     */
3725
+    function setIncoterms($id_incoterm, $location)
3726
+    {
3727
+        if ($this->id && $this->table_element)
3728
+        {
3729
+            $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3730
+            $sql.= " SET fk_incoterms = ".($id_incoterm > 0 ? $id_incoterm : "null");
3731
+            $sql.= ", location_incoterms = ".($id_incoterm > 0 ? "'".$this->db->escape($location)."'" : "null");
3732
+            $sql.= " WHERE rowid = " . $this->id;
3733
+            dol_syslog(get_class($this).'::setIncoterms', LOG_DEBUG);
3734
+            $resql=$this->db->query($sql);
3735
+            if ($resql)
3736
+            {
3737
+                $this->fk_incoterms = $id_incoterm;
3738
+                $this->location_incoterms = $location;
3739
+
3740
+                $sql = 'SELECT libelle FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3741
+                $res = $this->db->query($sql);
3742
+                if ($res)
3743
+                {
3744
+                    $obj = $this->db->fetch_object($res);
3745
+                    $this->libelle_incoterms = $obj->libelle;
3746
+                }
3747
+                return 1;
3748
+            }
3749
+            else
3750
+            {
3751
+                $this->errors[] = $this->db->lasterror();
3752
+                return -1;
3753
+            }
3754
+        }
3755
+        else return -1;
3756
+    }
3757
+
3758
+
3759
+    // --------------------
3760
+    // TODO: All functions here must be redesigned and moved as they are not business functions but output functions
3761
+    // --------------------
3762
+
3763
+    /* This is to show add lines */
3764
+
3765
+    /**
3766
+     *	Show add free and predefined products/services form
3767
+     *
3768
+     *  @param	int		        $dateSelector       1=Show also date range input fields
3769
+     *  @param	Societe			$seller				Object thirdparty who sell
3770
+     *  @param	Societe			$buyer				Object thirdparty who buy
3771
+     *	@return	void
3772
+     */
3773
+    function formAddObjectLine($dateSelector, $seller, $buyer)
3774
+    {
3775
+        global $conf,$user,$langs,$object,$hookmanager;
3776
+        global $form,$bcnd,$var;
3777
+
3778
+        // Line extrafield
3779
+        require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3780
+        $extrafieldsline = new ExtraFields($this->db);
3781
+        $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3782
+
3783
+        // Output template part (modules that overwrite templates must declare this into descriptor)
3784
+        // Use global variables + $dateSelector + $seller and $buyer
3785
+        $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
3786
+        foreach($dirtpls as $reldir)
3787
+        {
3788
+            $tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
3789
+            if (empty($conf->file->strict_mode)) {
3790
+                $res=@include $tpl;
3791
+            } else {
3792
+                $res=include $tpl; // for debug
3793
+            }
3794
+            if ($res) break;
3795
+        }
3796
+    }
3797
+
3798
+
3799
+
3800
+    /* This is to show array of line of details */
3801
+
3802
+
3803
+    /**
3804
+     *	Return HTML table for object lines
3805
+     *	TODO Move this into an output class file (htmlline.class.php)
3806
+     *	If lines are into a template, title must also be into a template
3807
+     *	But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
3808
+     *
3809
+     *	@param	string		$action				Action code
3810
+     *	@param  string		$seller            	Object of seller third party
3811
+     *	@param  string  	$buyer             	Object of buyer third party
3812
+     *	@param	int			$selected		   	Object line selected
3813
+     *	@param  int	    	$dateSelector      	1=Show also date range input fields
3814
+     *	@return	void
3815
+     */
3816
+    function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0)
3817
+    {
3818
+        global $conf, $hookmanager, $langs, $user;
3819
+        // TODO We should not use global var for this !
3820
+        global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
3821
+
3822
+        // Define usemargins
3823
+        $usemargins=0;
3824
+        if (! empty($conf->margin->enabled) && ! empty($this->element) && in_array($this->element,array('facture','propal','commande'))) $usemargins=1;
3825
+
3826
+        $num = count($this->lines);
3827
+
3828
+        // Line extrafield
3829
+        require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3830
+        $extrafieldsline = new ExtraFields($this->db);
3831
+        $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3832
+
3833
+        $parameters = array('num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3834
+        $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3835
+        if (empty($reshook))
3836
+        {
3837
+            // Title line
3838
+            print "<thead>\n";
3839
+
3840
+            print '<tr class="liste_titre nodrag nodrop">';
3841
+
3842
+            // Adds a line numbering column
3843
+            if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) print '<td class="linecolnum" align="center" width="5">&nbsp;</td>';
3844
+
3845
+            // Description
3846
+            print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
3847
+
3848
+            if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier')
3849
+            {
3850
+                print '<td class="linerefsupplier"><span id="title_fourn_ref">'.$langs->trans("SupplierRef").'</span></td>';
3851
+            }
3852
+
3853
+            // VAT
3854
+            print '<td class="linecolvat" align="right" width="80">'.$langs->trans('VAT').'</td>';
3855
+
3856
+            // Price HT
3857
+            print '<td class="linecoluht" align="right" width="80">'.$langs->trans('PriceUHT').'</td>';
3858
+
3859
+            // Multicurrency
3860
+            if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoluht_currency" align="right" width="80">'.$langs->trans('PriceUHTCurrency', $this->multicurrency_code).'</td>';
3861
+
3862
+            if ($inputalsopricewithtax) print '<td align="right" width="80">'.$langs->trans('PriceUTTC').'</td>';
3863
+
3864
+            // Qty
3865
+            print '<td class="linecolqty" align="right">'.$langs->trans('Qty').'</td>';
3866
+
3867
+            if($conf->global->PRODUCT_USE_UNITS)
3868
+            {
3869
+                print '<td class="linecoluseunit" align="left">'.$langs->trans('Unit').'</td>';
3870
+            }
3871
+
3872
+            // Reduction short
3873
+            print '<td class="linecoldiscount" align="right">'.$langs->trans('ReductionShort').'</td>';
3874
+
3875
+            if ($this->situation_cycle_ref) {
3876
+                print '<td class="linecolcycleref" align="right">' . $langs->trans('Progress') . '</td>';
3877
+            }
3878
+
3879
+            if ($usemargins && ! empty($conf->margin->enabled) && empty($user->societe_id))
3880
+            {
3881
+                if (!empty($user->rights->margins->creer))
3882
+                {
3883
+                    if ($conf->global->MARGIN_TYPE == "1")
3884
+                        print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('BuyingPrice').'</td>';
3885
+                    else
3886
+                        print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('CostPrice').'</td>';
3887
+                }
3888
+
3889
+                if (! empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous)
3890
+                    print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarginRate').'</td>';
3891
+                if (! empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous)
3892
+                    print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarkRate').'</td>';
3893
+            }
3894
+
3895
+            // Total HT
3896
+            print '<td class="linecolht" align="right">'.$langs->trans('TotalHTShort').'</td>';
3897
+
3898
+            // Multicurrency
3899
+            if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoltotalht_currency" align="right">'.$langs->trans('TotalHTShortCurrency', $this->multicurrency_code).'</td>';
3900
+
3901
+            if ($outputalsopricetotalwithtax) print '<td align="right" width="80">'.$langs->trans('TotalTTCShort').'</td>';
3902
+
3903
+            print '<td class="linecoledit"></td>';  // No width to allow autodim
3904
+
3905
+            print '<td class="linecoldelete" width="10"></td>';
3906
+
3907
+            print '<td class="linecolmove" width="10"></td>';
3908
+
3909
+            if($action == 'selectlines')
3910
+            {
3911
+                print '<td class="linecolcheckall" align="center">';
3912
+                print '<input type="checkbox" class="linecheckboxtoggle" />';
3913
+                print '<script type="text/javascript">$(document).ready(function() {$(".linecheckboxtoggle").click(function() {var checkBoxes = $(".linecheckbox");checkBoxes.prop("checked", this.checked);})});</script>';
3914
+                print '</td>';
3915
+            }
3916
+
3917
+            print "</tr>\n";
3918
+            print "</thead>\n";
3919
+        }
3920
+
3921
+        $var = true;
3922
+        $i	 = 0;
3923
+
3924
+        print "<tbody>\n";
3925
+        foreach ($this->lines as $line)
3926
+        {
3927
+            //Line extrafield
3928
+            $line->fetch_optionals();
3929
+
3930
+            //if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
3931
+            if (is_object($hookmanager))   // Old code is commented on preceding line.
3932
+            {
3933
+                if (empty($line->fk_parent_line))
3934
+                {
3935
+                    $parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3936
+                    $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3937
+                }
3938
+                else
3939
+                {
3940
+                    $parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline, 'fk_parent_line'=>$line->fk_parent_line);
3941
+                    $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3942
+                }
3943
+            }
3944
+            if (empty($reshook))
3945
+            {
3946
+                $this->printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected,$extrafieldsline);
3947
+            }
3948
+
3949
+            $i++;
3950
+        }
3951
+        print "</tbody>\n";
3952
+    }
3953
+
3954
+    /**
3955
+     *	Return HTML content of a detail line
3956
+     *	TODO Move this into an output class file (htmlline.class.php)
3957
+     *
3958
+     *	@param	string		$action				GET/POST action
3959
+     *	@param CommonObjectLine $line		       	Selected object line to output
3960
+     *	@param  string	    $var               	Is it a an odd line (true)
3961
+     *	@param  int		    $num               	Number of line (0)
3962
+     *	@param  int		    $i					I
3963
+     *	@param  int		    $dateSelector      	1=Show also date range input fields
3964
+     *	@param  string	    $seller            	Object of seller third party
3965
+     *	@param  string	    $buyer             	Object of buyer third party
3966
+     *	@param	int			$selected		   	Object line selected
3967
+     *  @param  int			$extrafieldsline	Object of extrafield line attribute
3968
+     *	@return	void
3969
+     */
3970
+    function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0)
3971
+    {
3972
+        global $conf,$langs,$user,$object,$hookmanager;
3973
+        global $form,$bc,$bcdd;
3974
+        global $object_rights, $disableedit, $disablemove, $disableremove;   // TODO We should not use global var for this !
3975
+
3976
+        $object_rights = $this->getRights();
3977
+
3978
+        $element=$this->element;
3979
+
3980
+        $text=''; $description=''; $type=0;
3981
+
3982
+        // Show product and description
3983
+        $type=(! empty($line->product_type)?$line->product_type:$line->fk_product_type);
3984
+        // Try to enhance type detection using date_start and date_end for free lines where type was not saved.
3985
+        if (! empty($line->date_start)) $type=1; // deprecated
3986
+        if (! empty($line->date_end)) $type=1; // deprecated
3987
+
3988
+        // Ligne en mode visu
3989
+        if ($action != 'editline' || $selected != $line->id)
3990
+        {
3991
+            // Product
3992
+            if ($line->fk_product > 0)
3993
+            {
3994
+                $product_static = new Product($this->db);
3995
+                $product_static->fetch($line->fk_product);
3996
+
3997
+                $product_static->ref = $line->ref; //can change ref in hook
3998
+                $product_static->label = $line->label; //can change label in hook
3999
+                $text=$product_static->getNomUrl(1);
4000
+
4001
+                // Define output language and label
4002
+                if (! empty($conf->global->MAIN_MULTILANGS))
4003
+                {
4004
+                    if (! is_object($this->thirdparty))
4005
+                    {
4006
+                        dol_print_error('','Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
4007
+                        return;
4008
+                    }
4009
+
4010
+                    $prod = new Product($this->db);
4011
+                    $prod->fetch($line->fk_product);
4012
+
4013
+                    $outputlangs = $langs;
4014
+                    $newlang='';
4015
+                    if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09');
4016
+                    if (! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang)) $newlang=$this->thirdparty->default_lang;		// For language to language of customer
4017
+                    if (! empty($newlang))
4018
+                    {
4019
+                        $outputlangs = new Translate("",$conf);
4020
+                        $outputlangs->setDefaultLang($newlang);
4021
+                    }
4022
+
4023
+                    $label = (! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
4024
+                }
4025
+                else
4026
+                {
4027
+                    $label = $line->product_label;
4028
+                }
4029
+
4030
+                $text.= ' - '.(! empty($line->label)?$line->label:$label);
4031
+                $description.=(! empty($conf->global->PRODUIT_DESC_IN_FORM)?'':dol_htmlentitiesbr($line->description));	// Description is what to show on popup. We shown nothing if already into desc.
4032
+            }
4033
+
4034
+            $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4035
+
4036
+            // Output template part (modules that overwrite templates must declare this into descriptor)
4037
+            // Use global variables + $dateSelector + $seller and $buyer
4038
+            $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4039
+            foreach($dirtpls as $reldir)
4040
+            {
4041
+                $tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
4042
+                if (empty($conf->file->strict_mode)) {
4043
+                    $res=@include $tpl;
4044
+                } else {
4045
+                    $res=include $tpl; // for debug
4046
+                }
4047
+                if ($res) break;
4048
+            }
4049
+        }
4050
+
4051
+        // Ligne en mode update
4052
+        if ($this->statut == 0 && $action == 'editline' && $selected == $line->id)
4053
+        {
4054
+            $label = (! empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
4055
+            $placeholder=' placeholder="'.$langs->trans("Label").'"';
4056
+
4057
+            $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4058
+
4059
+            // Output template part (modules that overwrite templates must declare this into descriptor)
4060
+            // Use global variables + $dateSelector + $seller and $buyer
4061
+            $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4062
+            foreach($dirtpls as $reldir)
4063
+            {
4064
+                $tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
4065
+                if (empty($conf->file->strict_mode)) {
4066
+                    $res=@include $tpl;
4067
+                } else {
4068
+                    $res=include $tpl; // for debug
4069
+                }
4070
+                if ($res) break;
4071
+            }
4072
+        }
4073
+    }
4074
+
4075
+
4076
+    /* This is to show array of line of details of source object */
4077
+
4078
+
4079
+    /**
4080
+     * 	Return HTML table table of source object lines
4081
+     *  TODO Move this and previous function into output html class file (htmlline.class.php).
4082
+     *  If lines are into a template, title must also be into a template
4083
+     *  But for the moment we don't know if it's possible, so we keep the method available on overloaded objects.
4084
+     *
4085
+     *	@param	string		$restrictlist		''=All lines, 'services'=Restrict to services only
4086
+     *  @return	void
4087
+     */
4088
+    function printOriginLinesList($restrictlist='')
4089
+    {
4090
+        global $langs, $hookmanager, $conf;
4091
+
4092
+        print '<tr class="liste_titre">';
4093
+        print '<td>'.$langs->trans('Ref').'</td>';
4094
+        print '<td>'.$langs->trans('Description').'</td>';
4095
+        print '<td align="right">'.$langs->trans('VATRate').'</td>';
4096
+        print '<td align="right">'.$langs->trans('PriceUHT').'</td>';
4097
+        if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('PriceUHTCurrency').'</td>';
4098
+        print '<td align="right">'.$langs->trans('Qty').'</td>';
4099
+        if($conf->global->PRODUCT_USE_UNITS)
4100
+        {
4101
+            print '<td align="left">'.$langs->trans('Unit').'</td>';
4102
+        }
4103
+        print '<td align="right">'.$langs->trans('ReductionShort').'</td></tr>';
4104
+
4105
+        $var = true;
4106
+        $i	 = 0;
4107
+
4108
+        if (! empty($this->lines))
4109
+        {
4110
+            foreach ($this->lines as $line)
4111
+            {
4112
+                if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
4113
+                {
4114
+                    if (empty($line->fk_parent_line))
4115
+                    {
4116
+                        $parameters=array('line'=>$line,'var'=>$var,'i'=>$i);
4117
+                        $action='';
4118
+                        $hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
4119
+                    }
4120
+                }
4121
+                else
4122
+                {
4123
+                    $this->printOriginLine($line, $var, $restrictlist);
4124
+                }
4125
+
4126
+                $i++;
4127
+            }
4128
+        }
4129
+    }
4130
+
4131
+    /**
4132
+     * 	Return HTML with a line of table array of source object lines
4133
+     *  TODO Move this and previous function into output html class file (htmlline.class.php).
4134
+     *  If lines are into a template, title must also be into a template
4135
+     *  But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
4136
+     *
4137
+     * 	@param	CommonObjectLine	$line				Line
4138
+     * 	@param	string				$var				Var
4139
+     *	@param	string				$restrictlist		''=All lines, 'services'=Restrict to services only (strike line if not)
4140
+     * 	@return	void
4141
+     */
4142
+    function printOriginLine($line, $var, $restrictlist='')
4143
+    {
4144
+        global $langs, $conf;
4145
+
4146
+        //var_dump($line);
4147
+        if (!empty($line->date_start))
4148
+        {
4149
+            $date_start=$line->date_start;
4150
+        }
4151
+        else
4152
+        {
4153
+            $date_start=$line->date_debut_prevue;
4154
+            if ($line->date_debut_reel) $date_start=$line->date_debut_reel;
4155
+        }
4156
+        if (!empty($line->date_end))
4157
+        {
4158
+            $date_end=$line->date_end;
4159
+        }
4160
+        else
4161
+        {
4162
+            $date_end=$line->date_fin_prevue;
4163
+            if ($line->date_fin_reel) $date_end=$line->date_fin_reel;
4164
+        }
4165
+
4166
+        $this->tpl['label'] = '';
4167
+        if (! empty($line->fk_parent_line)) $this->tpl['label'].= img_picto('', 'rightarrow');
4168
+
4169
+        if (($line->info_bits & 2) == 2)  // TODO Not sure this is used for source object
4170
+        {
4171
+            $discount=new DiscountAbsolute($this->db);
4172
+            $discount->fk_soc = $this->socid;
4173
+            $this->tpl['label'].= $discount->getNomUrl(0,'discount');
4174
+        }
4175
+        else if (! empty($line->fk_product))
4176
+        {
4177
+            $productstatic = new Product($this->db);
4178
+            $productstatic->id = $line->fk_product;
4179
+            $productstatic->ref = $line->ref;
4180
+            $productstatic->type = $line->fk_product_type;
4181
+            if(empty($productstatic->ref)){
4182
+                $line->fetch_product();
4183
+                $productstatic = $line->product;
4184
+            }
4185
+			
4186
+            $this->tpl['label'].= $productstatic->getNomUrl(1);
4187
+            $this->tpl['label'].= ' - '.(! empty($line->label)?$line->label:$line->product_label);
4188
+            // Dates
4189
+            if ($line->product_type == 1 && ($date_start || $date_end))
4190
+            {
4191
+                $this->tpl['label'].= get_date_range($date_start,$date_end);
4192
+            }
4193
+        }
4194
+        else
4195
+        {
4196
+            $this->tpl['label'].= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''),'service') : img_object($langs->trans(''),'product')));
4197
+            if (!empty($line->desc)) {
4198
+                $this->tpl['label'].=$line->desc;
4199
+            }else {
4200
+                $this->tpl['label'].= ($line->label ? '&nbsp;'.$line->label : '');
4201
+            }
4202
+			
4203
+            // Dates
4204
+            if ($line->product_type == 1 && ($date_start || $date_end))
4205
+            {
4206
+                $this->tpl['label'].= get_date_range($date_start,$date_end);
4207
+            }
4208
+        }
4209
+
4210
+        if (! empty($line->desc))
4211
+        {
4212
+            if ($line->desc == '(CREDIT_NOTE)')  // TODO Not sure this is used for source object
4213
+            {
4214
+                $discount=new DiscountAbsolute($this->db);
4215
+                $discount->fetch($line->fk_remise_except);
4216
+                $this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote",$discount->getNomUrl(0));
4217
+            }
4218
+            elseif ($line->desc == '(DEPOSIT)')  // TODO Not sure this is used for source object
4219
+            {
4220
+                $discount=new DiscountAbsolute($this->db);
4221
+                $discount->fetch($line->fk_remise_except);
4222
+                $this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit",$discount->getNomUrl(0));
4223
+            }
4224
+            elseif ($line->desc == '(EXCESS RECEIVED)')
4225
+            {
4226
+                $discount=new DiscountAbsolute($this->db);
4227
+                $discount->fetch($line->fk_remise_except);
4228
+                $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived",$discount->getNomUrl(0));
4229
+            }
4230
+            elseif ($line->desc == '(EXCESS PAID)')
4231
+            {
4232
+                $discount=new DiscountAbsolute($this->db);
4233
+                $discount->fetch($line->fk_remise_except);
4234
+                $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid",$discount->getNomUrl(0));
4235
+            }
4236
+            else
4237
+            {
4238
+                $this->tpl['description'] = dol_trunc($line->desc,60);
4239
+            }
4240
+        }
4241
+        else
4242
+        {
4243
+            $this->tpl['description'] = '&nbsp;';
4244
+        }
4245
+
4246
+        // VAT Rate
4247
+        $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
4248
+        $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
4249
+        if (! empty($line->vat_src_code) && ! preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'].=' ('.$line->vat_src_code.')';
4250
+
4251
+        $this->tpl['price'] = price($line->subprice);
4252
+        $this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
4253
+        $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
4254
+        if ($conf->global->PRODUCT_USE_UNITS) $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
4255
+        $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
4256
+
4257
+        // Is the line strike or not
4258
+        $this->tpl['strike']=0;
4259
+        if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) $this->tpl['strike']=1;
4260
+
4261
+        // Output template part (modules that overwrite templates must declare this into descriptor)
4262
+        // Use global variables + $dateSelector + $seller and $buyer
4263
+        $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4264
+        foreach($dirtpls as $reldir)
4265
+        {
4266
+            $tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
4267
+            if (empty($conf->file->strict_mode)) {
4268
+                $res=@include $tpl;
4269
+            } else {
4270
+                $res=include $tpl; // for debug
4271
+            }
4272
+            if ($res) break;
4273
+        }
4274
+    }
4275
+
4276
+
4277
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4278
+    /**
4279
+     *	Add resources to the current object : add entry into llx_element_resources
4280
+     *	Need $this->element & $this->id
4281
+     *
4282
+     *	@param		int		$resource_id		Resource id
4283
+     *	@param		string	$resource_type		'resource'
4284
+     *	@param		int		$busy				Busy or not
4285
+     *	@param		int		$mandatory			Mandatory or not
4286
+     *	@return		int							<=0 if KO, >0 if OK
4287
+     */
4288
+    function add_element_resource($resource_id, $resource_type, $busy=0, $mandatory=0)
4289
+    {
4290
+        // phpcs:enable
4291
+        $this->db->begin();
4292
+
4293
+        $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_resources (";
4294
+        $sql.= "resource_id";
4295
+        $sql.= ", resource_type";
4296
+        $sql.= ", element_id";
4297
+        $sql.= ", element_type";
4298
+        $sql.= ", busy";
4299
+        $sql.= ", mandatory";
4300
+        $sql.= ") VALUES (";
4301
+        $sql.= $resource_id;
4302
+        $sql.= ", '".$this->db->escape($resource_type)."'";
4303
+        $sql.= ", '".$this->db->escape($this->id)."'";
4304
+        $sql.= ", '".$this->db->escape($this->element)."'";
4305
+        $sql.= ", '".$this->db->escape($busy)."'";
4306
+        $sql.= ", '".$this->db->escape($mandatory)."'";
4307
+        $sql.= ")";
4308
+
4309
+        dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG);
4310
+        if ($this->db->query($sql))
4311
+        {
4312
+            $this->db->commit();
4313
+            return 1;
4314
+        }
4315
+        else
4316
+        {
4317
+            $this->error=$this->db->lasterror();
4318
+            $this->db->rollback();
4319
+            return  0;
4320
+        }
4321
+    }
4322
+
4323
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4324
+    /**
4325
+     *    Delete a link to resource line
4326
+     *
4327
+     *    @param	int		$rowid			Id of resource line to delete
4328
+     *    @param	int		$element		element name (for trigger) TODO: use $this->element into commonobject class
4329
+     *    @param	int		$notrigger		Disable all triggers
4330
+     *    @return   int						>0 if OK, <0 if KO
4331
+     */
4332
+    function delete_resource($rowid, $element, $notrigger=0)
4333
+    {
4334
+        // phpcs:enable
4335
+        global $user;
4336
+
4337
+        $this->db->begin();
4338
+
4339
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_resources";
4340
+        $sql.= " WHERE rowid=".$rowid;
4341
+
4342
+        dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG);
4343
+
4344
+        $resql=$this->db->query($sql);
4345
+        if (! $resql)
4346
+        {
4347
+            $this->error=$this->db->lasterror();
4348
+            $this->db->rollback();
4349
+            return -1;
4350
+        }
4351
+        else
4352
+        {
4353
+            if (! $notrigger)
4354
+            {
4355
+                $result=$this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
4356
+                if ($result < 0) { $this->db->rollback(); return -1; }
4357
+            }
4358
+            $this->db->commit();
4359
+            return 1;
4360
+        }
4361
+    }
4362
+
4363
+
4364
+    /**
4365
+     * Overwrite magic function to solve problem of cloning object that are kept as references
4366
+     *
4367
+     * @return void
4368
+     */
4369
+    function __clone()
4370
+    {
4371
+        // Force a copy of this->lines, otherwise it will point to same object.
4372
+        if (isset($this->lines) && is_array($this->lines))
4373
+        {
4374
+            $nboflines=count($this->lines);
4375
+            for($i=0; $i < $nboflines; $i++)
4376
+            {
4377
+                $this->lines[$i] = clone $this->lines[$i];
4378
+            }
4379
+        }
4380
+    }
4381
+
4382
+    /**
4383
+     * Common function for all objects extending CommonObject for generating documents
4384
+     *
4385
+     * @param 	string 		$modelspath 	Relative folder where generators are placed
4386
+     * @param 	string 		$modele 		Generator to use. Caller must set it to obj->modelpdf or GETPOST('modelpdf') for example.
4387
+     * @param 	Translate 	$outputlangs 	Output language to use
4388
+     * @param 	int 		$hidedetails 	1 to hide details. 0 by default
4389
+     * @param 	int 		$hidedesc 		1 to hide product description. 0 by default
4390
+     * @param 	int 		$hideref 		1 to hide product reference. 0 by default
4391
+     * @param   null|array  $moreparams     Array to provide more information
4392
+     * @return 	int 						>0 if OK, <0 if KO
4393
+     * @see	addFileIntoDatabaseIndex
4394
+     */
4395
+    protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
4396
+    {
4397
+        global $conf, $langs, $user;
4398
+
4399
+        $srctemplatepath='';
4400
+
4401
+        // Increase limit for PDF build
4402
+        $err=error_reporting();
4403
+        error_reporting(0);
4404
+        @set_time_limit(120);
4405
+        error_reporting($err);
4406
+
4407
+        // If selected model is a filename template (then $modele="modelname" or "modelname:filename")
4408
+        $tmp=explode(':',$modele,2);
4409
+        if (! empty($tmp[1]))
4410
+        {
4411
+            $modele=$tmp[0];
4412
+            $srctemplatepath=$tmp[1];
4413
+        }
4414
+
4415
+        // Search template files
4416
+        $file=''; $classname=''; $filefound=0;
4417
+        $dirmodels=array('/');
4418
+        if (is_array($conf->modules_parts['models'])) $dirmodels=array_merge($dirmodels,$conf->modules_parts['models']);
4419
+        foreach($dirmodels as $reldir)
4420
+        {
4421
+            foreach(array('doc','pdf') as $prefix)
4422
+            {
4423
+                if (in_array(get_class($this), array('Adherent'))) $file = $prefix."_".$modele.".class.php";     // Member module use prefix_module.class.php
4424
+                else $file = $prefix."_".$modele.".modules.php";
4425
+
4426
+                // On verifie l'emplacement du modele
4427
+                $file=dol_buildpath($reldir.$modelspath.$file,0);
4428
+                if (file_exists($file))
4429
+                {
4430
+                    $filefound=1;
4431
+                    $classname=$prefix.'_'.$modele;
4432
+                    break;
4433
+                }
4434
+            }
4435
+            if ($filefound) break;
4436
+        }
4437
+
4438
+        // If generator was found
4439
+        if ($filefound)
4440
+        {
4441
+            global $db;  // Required to solve a conception default in commonstickergenerator.class.php making an include of code using $db
4442
+
4443
+            require_once $file;
4444
+
4445
+            $obj = new $classname($this->db);
4446
+
4447
+            // If generator is ODT, we must have srctemplatepath defined, if not we set it.
4448
+            if ($obj->type == 'odt' && empty($srctemplatepath))
4449
+            {
4450
+                $varfortemplatedir=$obj->scandir;
4451
+                if ($varfortemplatedir && ! empty($conf->global->$varfortemplatedir))
4452
+                {
4453
+                    $dirtoscan=$conf->global->$varfortemplatedir;
4454
+
4455
+                    $listoffiles=array();
4456
+
4457
+                    // Now we add first model found in directories scanned
4458
+                    $listofdir=explode(',',$dirtoscan);
4459
+                    foreach($listofdir as $key => $tmpdir)
4460
+                    {
4461
+                        $tmpdir=trim($tmpdir);
4462
+                        $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
4463
+                        if (! $tmpdir) { unset($listofdir[$key]); continue; }
4464
+                        if (is_dir($tmpdir))
4465
+                        {
4466
+                            $tmpfiles=dol_dir_list($tmpdir,'files',0,'\.od(s|t)$','','name',SORT_ASC,0);
4467
+                            if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles);
4468
+                        }
4469
+                    }
4470
+
4471
+                    if (count($listoffiles))
4472
+                    {
4473
+                        foreach($listoffiles as $record)
4474
+                        {
4475
+                            $srctemplatepath=$record['fullname'];
4476
+                            break;
4477
+                        }
4478
+                    }
4479
+                }
4480
+
4481
+                if (empty($srctemplatepath))
4482
+                {
4483
+                    $this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
4484
+                    return -1;
4485
+                }
4486
+            }
4487
+
4488
+            if ($obj->type == 'odt' && ! empty($srctemplatepath))
4489
+            {
4490
+                if (! dol_is_file($srctemplatepath))
4491
+                {
4492
+                    $this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
4493
+                    return -1;
4494
+                }
4495
+            }
4496
+
4497
+            // We save charset_output to restore it because write_file can change it if needed for
4498
+            // output format that does not support UTF8.
4499
+            $sav_charset_output=$outputlangs->charset_output;
4500
+
4501
+            if (in_array(get_class($this), array('Adherent')))
4502
+            {
4503
+                $arrayofrecords = array();   // The write_file of templates of adherent class need this var
4504
+                $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams);
4505
+            }
4506
+            else
4507
+            {
4508
+                $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
4509
+            }
4510
+            // After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
4511
+
4512
+            if ($resultwritefile > 0)
4513
+            {
4514
+                $outputlangs->charset_output=$sav_charset_output;
4515
+
4516
+                // We delete old preview
4517
+                require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
4518
+                dol_delete_preview($this);
4519
+
4520
+                // Index file in database
4521
+                if (! empty($obj->result['fullpath']))
4522
+                {
4523
+                    $destfull = $obj->result['fullpath'];
4524
+                    $upload_dir = dirname($destfull);
4525
+                    $destfile = basename($destfull);
4526
+                    $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir);
4527
+
4528
+                    if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir))     // If not a tmp dir
4529
+                    {
4530
+                        $filename = basename($destfile);
4531
+                        $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
4532
+                        $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
4533
+
4534
+                        include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
4535
+                        $ecmfile=new EcmFiles($this->db);
4536
+                        $result = $ecmfile->fetch(0, '', ($rel_dir?$rel_dir.'/':'').$filename);
4537
+
4538
+                        // Set the public "share" key
4539
+                        $setsharekey = false;
4540
+                        if ($this->element == 'propal')
4541
+                        {
4542
+                            $useonlinesignature = $conf->global->MAIN_FEATURES_LEVEL;	// Replace this with 1 when feature to make online signature is ok
4543
+                            if ($useonlinesignature) $setsharekey=true;
4544
+                            if (! empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4545
+                        }
4546
+                        if ($this->element == 'commande'     && ! empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD))        $setsharekey=true;
4547
+                        if ($this->element == 'facture'      && ! empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD))      $setsharekey=true;
4548
+                        if ($this->element == 'bank_account' && ! empty($conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4549
+
4550
+                        if ($setsharekey)
4551
+                        {
4552
+                            if (empty($ecmfile->share))	// Because object not found or share not set yet
4553
+                            {
4554
+                                require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
4555
+                                $ecmfile->share = getRandomPassword(true);
4556
+                            }
4557
+                        }
4558
+
4559
+                        if ($result > 0)
4560
+                        {
4561
+                            $ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4562
+                            $ecmfile->fullpath_orig = '';
4563
+                            $ecmfile->gen_or_uploaded = 'generated';
4564
+                            $ecmfile->description = '';    // indexed content
4565
+                            $ecmfile->keyword = '';        // keyword content
4566
+                            $result = $ecmfile->update($user);
4567
+                            if ($result < 0)
4568
+                            {
4569
+                                setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4570
+                            }
4571
+                        }
4572
+                        else
4573
+                        {
4574
+                            $ecmfile->entity = $conf->entity;
4575
+                            $ecmfile->filepath = $rel_dir;
4576
+                            $ecmfile->filename = $filename;
4577
+                            $ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4578
+                            $ecmfile->fullpath_orig = '';
4579
+                            $ecmfile->gen_or_uploaded = 'generated';
4580
+                            $ecmfile->description = '';    // indexed content
4581
+                            $ecmfile->keyword = '';        // keyword content
4582
+                            $ecmfile->src_object_type = $this->table_element;
4583
+                            $ecmfile->src_object_id   = $this->id;
4584
+
4585
+                            $result = $ecmfile->create($user);
4586
+                            if ($result < 0)
4587
+                            {
4588
+                                setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4589
+                            }
4590
+                        }
4591
+
4592
+                        /*$this->result['fullname']=$destfull;
4593
+						$this->result['filepath']=$ecmfile->filepath;
4594
+						$this->result['filename']=$ecmfile->filename;*/
4595
+                        //var_dump($obj->update_main_doc_field);exit;
4596
+
4597
+                        // Update the last_main_doc field into main object (if documenent generator has property ->update_main_doc_field set)
4598
+                        $update_main_doc_field=0;
4599
+                        if (! empty($obj->update_main_doc_field)) $update_main_doc_field=1;
4600
+                        if ($update_main_doc_field && ! empty($this->table_element))
4601
+                        {
4602
+                            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET last_main_doc = '".($ecmfile->filepath.'/'.$ecmfile->filename)."'";
4603
+                            $sql.= ' WHERE rowid = '.$this->id;
4604
+                            $resql = $this->db->query($sql);
4605
+                            if (! $resql) dol_print_error($this->db);
4606
+                        }
4607
+                    }
4608
+                }
4609
+                else
4610
+                {
4611
+                    dol_syslog('Method ->write_file was called on object '.get_class($obj).' and return a success but the return array ->result["fullpath"] was not set.', LOG_WARNING);
4612
+                }
4613
+
4614
+                // Success in building document. We build meta file.
4615
+                dol_meta_create($this);
4616
+
4617
+                return 1;
4618
+            }
4619
+            else
4620
+            {
4621
+                $outputlangs->charset_output=$sav_charset_output;
4622
+                dol_print_error($this->db, "Error generating document for ".__CLASS__.". Error: ".$obj->error, $obj->errors);
4623
+                return -1;
4624
+            }
4625
+        }
4626
+        else
4627
+        {
4628
+            $this->error=$langs->trans("Error")." ".$langs->trans("ErrorFileDoesNotExists",$file);
4629
+            dol_print_error('',$this->error);
4630
+            return -1;
4631
+        }
4632
+    }
4633
+
4634
+    /**
4635
+     *  Build thumb
4636
+     *  @TODO Move this into files.lib.php
4637
+     *
4638
+     *  @param      string	$file           Path file in UTF8 to original file to create thumbs from.
4639
+     *	@return		void
4640
+     */
4641
+    function addThumbs($file)
4642
+    {
4643
+        global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini, $quality;
4644
+
4645
+        require_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';		// This define also $maxwidthsmall, $quality, ...
4646
+
4647
+        $file_osencoded=dol_osencode($file);
4648
+        if (file_exists($file_osencoded))
4649
+        {
4650
+            // Create small thumbs for company (Ratio is near 16/9)
4651
+            // Used on logon for example
4652
+            vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
4653
+
4654
+            // Create mini thumbs for company (Ratio is near 16/9)
4655
+            // Used on menu or for setup page for example
4656
+            vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
4657
+        }
4658
+    }
4659
+
4660
+
4661
+    /* Functions common to commonobject and commonobjectline */
4662
+
4663
+    /* For default values */
4664
+
4665
+    /**
4666
+     * Return the default value to use for a field when showing the create form of object.
4667
+     * Return values in this order:
4668
+     * 1) If parameter is available into POST, we return it first.
4669
+     * 2) If not but an alternate value was provided as parameter of function, we return it.
4670
+     * 3) If not but a constant $conf->global->OBJECTELEMENT_FIELDNAME is set, we return it (It is better to use the dedicated table).
4671
+     * 4) Return value found into database (TODO No yet implemented)
4672
+     *
4673
+     * @param   string              $fieldname          Name of field
4674
+     * @param   string              $alternatevalue     Alternate value to use
4675
+     * @return  string|string[]                         Default value (can be an array if the GETPOST return an array)
4676
+     **/
4677
+    function getDefaultCreateValueFor($fieldname, $alternatevalue=null)
4678
+    {
4679
+        global $conf, $_POST;
4680
+
4681
+        // If param here has been posted, we use this value first.
4682
+        if (isset($_POST[$fieldname])) return GETPOST($fieldname, 2);
4683
+
4684
+        if (isset($alternatevalue)) return $alternatevalue;
4685
+
4686
+        $newelement=$this->element;
4687
+        if ($newelement == 'facture') $newelement='invoice';
4688
+        if ($newelement == 'commande') $newelement='order';
4689
+        if (empty($newelement))
4690
+        {
4691
+            dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
4692
+            return '';
4693
+        }
4694
+
4695
+        $keyforfieldname=strtoupper($newelement.'_DEFAULT_'.$fieldname);
4696
+        //var_dump($keyforfieldname);
4697
+        if (isset($conf->global->$keyforfieldname)) return $conf->global->$keyforfieldname;
4698
+
4699
+        // TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
4700
+    }
4701
+
4702
+
4703
+    /* For triggers */
4704
+
4705
+
4706
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4707
+    /**
4708
+     * Call trigger based on this instance.
4709
+     * Some context information may also be provided into array property this->context.
4710
+     * NB:  Error from trigger are stacked in interface->errors
4711
+     * NB2: If return code of triggers are < 0, action calling trigger should cancel all transaction.
4712
+     *
4713
+     * @param   string    $trigger_name   trigger's name to execute
4714
+     * @param   User      $user           Object user
4715
+     * @return  int                       Result of run_triggers
4716
+     */
4717
+    function call_trigger($trigger_name, $user)
4718
+    {
4719
+        // phpcs:enable
4720
+        global $langs,$conf;
4721
+
4722
+        include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
4723
+        $interface=new Interfaces($this->db);
4724
+        $result=$interface->run_triggers($trigger_name,$this,$user,$langs,$conf);
4725
+
4726
+        if ($result < 0)
4727
+        {
4728
+            if (!empty($this->errors))
4729
+            {
4730
+                $this->errors=array_unique(array_merge($this->errors,$interface->errors));   // We use array_unique because when a trigger call another trigger on same object, this->errors is added twice.
4731
+            }
4732
+            else
4733
+            {
4734
+                $this->errors=$interface->errors;
4735
+            }
4736
+        }
4737
+        return $result;
4738
+    }
4739
+
4740
+
4741
+    /* Functions for extrafields */
4742
+
4743
+
4744
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4745
+    /**
4746
+     *  Function to get extra fields of an object into $this->array_options
4747
+     *  This method is in most cases called by method fetch of objects but you can call it separately.
4748
+     *
4749
+     *  @param	int		$rowid			Id of line. Use the id of object if not defined. Deprecated. Function must be called without parameters.
4750
+     *  @param  array	$optionsArray   Array resulting of call of extrafields->fetch_name_optionals_label(). Deprecated. Function must be called without parameters.
4751
+     *  @return	int						<0 if error, 0 if no values of extrafield to find nor found, 1 if an attribute is found and value loaded
4752
+     */
4753
+    function fetch_optionals($rowid=null, $optionsArray=null)
4754
+    {
4755
+        // phpcs:enable
4756
+        if (empty($rowid)) $rowid=$this->id;
4757
+
4758
+        // To avoid SQL errors. Probably not the better solution though
4759
+        if (!$this->table_element) {
4760
+            return 0;
4761
+        }
4762
+
4763
+        $this->array_options=array();
4764
+
4765
+        if (! is_array($optionsArray))
4766
+        {
4767
+            // If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
4768
+            // TODO Use of existing $extrafield is not yet ready (must mutualize code that use extrafields in form first)
4769
+            // global $extrafields;
4770
+            //if (! is_object($extrafields))
4771
+            //{
4772
+                // require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4773
+            $extrafields = new ExtraFields();
4774
+            //}
4775
+
4776
+            // Load array of extrafields for elementype = $this->table_element
4777
+            if (empty($extrafields->attributes[$this->table_element]['loaded']))
4778
+            {
4779
+                $extrafields->fetch_name_optionals_label($this->table_element);
4780
+            }
4781
+            $optionsArray = (! empty($extrafields->attributes[$this->table_element]['label'])?$extrafields->attributes[$this->table_element]['label']:null);
4782
+        }
4783
+        else
4784
+        {
4785
+            global $extrafields;
4786
+            dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
4787
+        }
4788
+
4789
+        $table_element = $this->table_element;
4790
+        if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4791
+
4792
+        // Request to get complementary values
4793
+        if (is_array($optionsArray) && count($optionsArray) > 0)
4794
+        {
4795
+            $sql = "SELECT rowid";
4796
+            foreach ($optionsArray as $name => $label)
4797
+            {
4798
+                if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate')
4799
+                {
4800
+                    $sql.= ", ".$name;
4801
+                }
4802
+            }
4803
+            $sql.= " FROM ".MAIN_DB_PREFIX.$table_element."_extrafields";
4804
+            $sql.= " WHERE fk_object = ".$rowid;
4805
+
4806
+            //dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG);		// Too verbose
4807
+            $resql=$this->db->query($sql);
4808
+            if ($resql)
4809
+            {
4810
+                $this->array_options = array();
4811
+                $numrows=$this->db->num_rows($resql);
4812
+                if ($numrows)
4813
+                {
4814
+                    $tab = $this->db->fetch_array($resql);
4815
+
4816
+                    foreach ($tab as $key => $value)
4817
+                    {
4818
+                        // Test fetch_array ! is_int($key) because fetch_array result is a mix table with Key as alpha and Key as int (depend db engine)
4819
+                        if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && ! is_int($key))
4820
+                        {
4821
+                            // we can add this attribute to object
4822
+                            if (! empty($extrafields) && in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date','datetime')))
4823
+                            {
4824
+                                //var_dump($extrafields->attributes[$this->table_element]['type'][$key]);
4825
+                                $this->array_options["options_".$key]=$this->db->jdate($value);
4826
+                            }
4827
+                            else
4828
+                            {
4829
+                                $this->array_options["options_".$key]=$value;
4830
+                            }
4831
+
4832
+                            //var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_".$key]);
4833
+                        }
4834
+                    }
4835
+                }
4836
+
4837
+                $this->db->free($resql);
4838
+
4839
+                if ($numrows) return $numrows;
4840
+                else return 0;
4841
+            }
4842
+            else
4843
+            {
4844
+                dol_print_error($this->db);
4845
+                return -1;
4846
+            }
4847
+        }
4848
+        return 0;
4849
+    }
4850
+
4851
+    /**
4852
+     *	Delete all extra fields values for the current object.
4853
+     *
4854
+     *  @return	int		<0 if KO, >0 if OK
4855
+     */
4856
+    function deleteExtraFields()
4857
+    {
4858
+        $this->db->begin();
4859
+
4860
+        $table_element = $this->table_element;
4861
+        if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4862
+
4863
+        $sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
4864
+        dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG);
4865
+        $resql=$this->db->query($sql_del);
4866
+        if (! $resql)
4867
+        {
4868
+            $this->error=$this->db->lasterror();
4869
+            $this->db->rollback();
4870
+            return -1;
4871
+        }
4872
+        else
4873
+        {
4874
+            $this->db->commit();
4875
+            return 1;
4876
+        }
4877
+    }
4878
+
4879
+    /**
4880
+     *	Add/Update all extra fields values for the current object.
4881
+     *  Data to describe values to insert/update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
4882
+     *  This function delete record with all extrafields and insert them again from the array $this->array_options.
4883
+     *
4884
+     *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
4885
+     *  @param	User		$userused		Object user
4886
+     *  @return int 						-1=error, O=did nothing, 1=OK
4887
+     *  @see updateExtraField, setValueFrom
4888
+     */
4889
+    function insertExtraFields($trigger='', $userused=null)
4890
+    {
4891
+        global $conf,$langs,$user;
4892
+
4893
+        if (empty($userused)) $userused=$user;
4894
+
4895
+        $error=0;
4896
+
4897
+        if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
4898
+
4899
+        if (! empty($this->array_options))
4900
+        {
4901
+            // Check parameters
4902
+            $langs->load('admin');
4903
+            require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4904
+            $extrafields = new ExtraFields($this->db);
4905
+            $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
4906
+
4907
+            //Eliminate copied source object extra_fields that do not exist in target object
4908
+            $new_array_options=array();
4909
+            foreach ($this->array_options as $key => $value) {
4910
+                if (in_array(substr($key,8), array_keys($target_extrafields)))	// We remove the 'options_' from $key for test
4911
+                    $new_array_options[$key] = $value;
4912
+                elseif (in_array($key, array_keys($target_extrafields)))		// We test on $key that does not contains the 'options_' prefix
4913
+                    $new_array_options['options_'.$key] = $value;
4914
+            }
4915
+
4916
+            foreach($new_array_options as $key => $value)
4917
+            {
4918
+                    $attributeKey      = substr($key,8);   // Remove 'options_' prefix
4919
+                    $attributeType     = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
4920
+                    $attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$attributeKey];
4921
+                    $attributeParam    = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
4922
+                    $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
4923
+
4924
+                    if ($attributeRequired)
4925
+                    {
4926
+                        $mandatorypb=false;
4927
+                        if ($attributeType == 'link' && $this->array_options[$key] == '-1') $mandatorypb=true;
4928
+                        if ($this->array_options[$key] === '') $mandatorypb=true;
4929
+                        if ($mandatorypb)
4930
+                        {
4931
+                            dol_syslog($this->error);
4932
+                            $this->errors[]=$langs->trans('ErrorFieldRequired', $attributeLabel);
4933
+                            return -1;
4934
+                        }
4935
+                    }
4936
+
4937
+                //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
4938
+                //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
4939
+
4940
+                    switch ($attributeType)
4941
+                    {
4942
+                        case 'int':
4943
+                          if (!is_numeric($value) && $value!='')
4944
+                            {
4945
+                                $this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4946
+                                return -1;
4947
+                            }
4948
+                            elseif ($value=='')
4949
+                            {
4950
+                                $new_array_options[$key] = null;
4951
+                            }
4952
+                            break;
4953
+                    case 'double':
4954
+                        $value = price2num($value);
4955
+                        if (!is_numeric($value) && $value!='')
4956
+                        {
4957
+                            dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
4958
+                            $this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4959
+                            return -1;
4960
+                        }
4961
+                        elseif ($value=='')
4962
+                        {
4963
+                            $new_array_options[$key] = null;
4964
+                        }
4965
+                        //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
4966
+                        $new_array_options[$key] = $value;
4967
+                        break;
4968
+                        /*case 'select':	// Not required, we chosed value='0' for undefined values
4969
+             			if ($value=='-1')
4970
+             			{
4971
+             				$this->array_options[$key] = null;
4972
+             			}
4973
+             			break;*/
4974
+                        case 'password':
4975
+                           $algo='';
4976
+                            if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']))
4977
+                            {
4978
+                                // If there is an encryption choice, we use it to crypt data before insert
4979
+                                $tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
4980
+                                $algo=reset($tmparrays);
4981
+                                if ($algo != '')
4982
+                                {
4983
+                                    //global $action;		// $action may be 'create', 'update', 'update_extras'...
4984
+                                    //var_dump($action);
4985
+                                    //var_dump($this->oldcopy);exit;
4986
+                                    if (is_object($this->oldcopy))		// If this->oldcopy is not defined, we can't know if we change attribute or not, so we must keep value
4987
+                                    {
4988
+                                        //var_dump($this->oldcopy->array_options[$key]); var_dump($this->array_options[$key]);
4989
+                                        if ($this->array_options[$key] == $this->oldcopy->array_options[$key])	// If old value crypted in database is same than submited new value, it means we don't change it, so we don't update.
4990
+                                        {
4991
+                                            $new_array_options[$key] = $this->array_options[$key];	// Value is kept
4992
+                                        }
4993
+                                    else
4994
+                                    {
4995
+                                        // var_dump($algo);
4996
+                                        $newvalue = dol_hash($this->array_options[$key], $algo);
4997
+                                        $new_array_options[$key] = $newvalue;
4998
+                                    }
4999
+                                    }
5000
+                                    else
5001
+                                    {
5002
+                                        $new_array_options[$key] = $this->array_options[$key];	// Value is kept
5003
+                                    }
5004
+                                }
5005
+                            }
5006
+                            else	// Common usage
5007
+                            {
5008
+                                $new_array_options[$key] = $this->array_options[$key];
5009
+                            }
5010
+                            break;
5011
+                        case 'price':
5012
+                        $new_array_options[$key] = price2num($this->array_options[$key]);
5013
+                        break;
5014
+                    case 'date':
5015
+                        $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5016
+                        break;
5017
+                    case 'datetime':
5018
+                        // If data is a string instead of a timestamp, we convert it
5019
+                        if (! is_int($this->array_options[$key])) {
5020
+                            $this->array_options[$key] = strtotime($this->array_options[$key]);
5021
+                        }
5022
+                        $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5023
+                        break;
5024
+                        case 'link':
5025
+                        $param_list=array_keys($attributeParam['options']);
5026
+                        // 0 : ObjectName
5027
+                        // 1 : classPath
5028
+                        $InfoFieldList = explode(":", $param_list[0]);
5029
+                        dol_include_once($InfoFieldList[1]);
5030
+                        if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
5031
+                        {
5032
+                            if ($value == '-1')	// -1 is key for no defined in combo list of objects
5033
+                            {
5034
+                                $new_array_options[$key]='';
5035
+                            }
5036
+                            elseif ($value)
5037
+                            {
5038
+                                $object = new $InfoFieldList[0]($this->db);
5039
+                                if (is_numeric($value)) $res=$object->fetch($value);
5040
+                                else $res=$object->fetch('',$value);
5041
+
5042
+                                if ($res > 0) $new_array_options[$key]=$object->id;
5043
+                                else
5044
+                                {
5045
+                                    $this->error="Id/Ref '".$value."' for object '".$object->element."' not found";
5046
+                                    $this->db->rollback();
5047
+                                    return -1;
5048
+                                }
5049
+                            }
5050
+                        }
5051
+                        else
5052
+                        {
5053
+                            dol_syslog('Error bad setup of extrafield', LOG_WARNING);
5054
+                        }
5055
+                        break;
5056
+                    }
5057
+            }
5058
+
5059
+            $this->db->begin();
5060
+
5061
+            $table_element = $this->table_element;
5062
+            if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
5063
+
5064
+            $sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
5065
+            dol_syslog(get_class($this)."::insertExtraFields delete", LOG_DEBUG);
5066
+            $this->db->query($sql_del);
5067
+
5068
+            $sql = "INSERT INTO ".MAIN_DB_PREFIX.$table_element."_extrafields (fk_object";
5069
+            foreach($new_array_options as $key => $value)
5070
+            {
5071
+                $attributeKey = substr($key,8);   // Remove 'options_' prefix
5072
+                // Add field of attribut
5073
+                if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator
5074
+                    $sql.=",".$attributeKey;
5075
+            }
5076
+            $sql .= ") VALUES (".$this->id;
5077
+
5078
+            foreach($new_array_options as $key => $value)
5079
+            {
5080
+                $attributeKey = substr($key,8);   // Remove 'options_' prefix
5081
+                // Add field of attribute
5082
+                if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator)
5083
+                {
5084
+                    if ($new_array_options[$key] != '')
5085
+                    {
5086
+                        $sql.=",'".$this->db->escape($new_array_options[$key])."'";
5087
+                    }
5088
+                    else
5089
+                    {
5090
+                        $sql.=",null";
5091
+                    }
5092
+                }
5093
+            }
5094
+            $sql.=")";
5095
+
5096
+            dol_syslog(get_class($this)."::insertExtraFields insert", LOG_DEBUG);
5097
+            $resql = $this->db->query($sql);
5098
+            if (! $resql)
5099
+            {
5100
+                $this->error=$this->db->lasterror();
5101
+                $error++;
5102
+            }
5103
+
5104
+            if (! $error && $trigger)
5105
+            {
5106
+                // Call trigger
5107
+                $this->context=array('extrafieldaddupdate'=>1);
5108
+                $result=$this->call_trigger($trigger, $userused);
5109
+                if ($result < 0) $error++;
5110
+                // End call trigger
5111
+            }
5112
+
5113
+            if ($error)
5114
+            {
5115
+                $this->db->rollback();
5116
+                return -1;
5117
+            }
5118
+            else
5119
+            {
5120
+                $this->db->commit();
5121
+                return 1;
5122
+            }
5123
+        }
5124
+        else return 0;
5125
+    }
5126
+
5127
+    /**
5128
+     *	Update an extra field value for the current object.
5129
+     *  Data to describe values to update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
5130
+     *
5131
+     *  @param  string      $key    		Key of the extrafield (without starting 'options_')
5132
+     *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
5133
+     *  @param	User		$userused		Object user
5134
+     *  @return int                 		-1=error, O=did nothing, 1=OK
5135
+     *  @see setValueFrom, insertExtraFields
5136
+     */
5137
+    function updateExtraField($key, $trigger=null, $userused=null)
5138
+    {
5139
+        global $conf,$langs,$user;
5140
+
5141
+        if (empty($userused)) $userused=$user;
5142
+
5143
+        $error=0;
5144
+
5145
+        if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
5146
+
5147
+        if (! empty($this->array_options) && isset($this->array_options["options_".$key]))
5148
+        {
5149
+            // Check parameters
5150
+            $langs->load('admin');
5151
+            require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
5152
+            $extrafields = new ExtraFields($this->db);
5153
+            $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
5154
+
5155
+            $value=$this->array_options["options_".$key];
5156
+
5157
+            $attributeType     = $extrafields->attributes[$this->table_element]['type'][$key];
5158
+            $attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$key];
5159
+            $attributeParam    = $extrafields->attributes[$this->table_element]['param'][$key];
5160
+            $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
5161
+
5162
+            //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
5163
+            //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
5164
+
5165
+            switch ($attributeType)
5166
+            {
5167
+                case 'int':
5168
+                    if (!is_numeric($value) && $value!='')
5169
+                    {
5170
+                        $this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel);
5171
+                        return -1;
5172
+                    }
5173
+                    elseif ($value=='')
5174
+                    {
5175
+                        $this->array_options["options_".$key] = null;
5176
+                    }
5177
+                    break;
5178
+                case 'double':
5179
+                    $value = price2num($value);
5180
+                    if (!is_numeric($value) && $value!='')
5181
+                    {
5182
+                        dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
5183
+                        $this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
5184
+                        return -1;
5185
+                    }
5186
+                    elseif ($value=='')
5187
+                    {
5188
+                        $this->array_options["options_".$key] = null;
5189
+                    }
5190
+                    //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
5191
+                    $this->array_options["options_".$key] = $value;
5192
+                    break;
5193
+                    /*case 'select':	// Not required, we chosed value='0' for undefined values
5194
+             		if ($value=='-1')
5195
+             		{
5196
+             			$this->array_options[$key] = null;
5197
+             		}
5198
+             		break;*/
5199
+                case 'price':
5200
+                    $this->array_options["options_".$key] = price2num($this->array_options["options_".$key]);
5201
+                    break;
5202
+                case 'date':
5203
+                    $this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5204
+                    break;
5205
+                case 'datetime':
5206
+                    $this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5207
+                    break;
5208
+                case 'link':
5209
+                    $param_list=array_keys($attributeParam['options']);
5210
+                    // 0 : ObjectName
5211
+                    // 1 : classPath
5212
+                    $InfoFieldList = explode(":", $param_list[0]);
5213
+                    dol_include_once($InfoFieldList[1]);
5214
+                    if ($value)
5215
+                    {
5216
+                        $object = new $InfoFieldList[0]($this->db);
5217
+                        $object->fetch(0,$value);
5218
+                        $this->array_options["options_".$key]=$object->id;
5219
+                    }
5220
+                    break;
5221
+            }
5222
+
5223
+            $this->db->begin();
5224
+            $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element."_extrafields SET ".$key."='".$this->db->escape($this->array_options["options_".$key])."'";
5225
+            $sql .= " WHERE fk_object = ".$this->id;
5226
+            $resql = $this->db->query($sql);
5227
+            if (! $resql)
5228
+            {
5229
+                $error++;
5230
+                $this->error=$this->db->lasterror();
5231
+            }
5232
+
5233
+            if (! $error && $trigger)
5234
+            {
5235
+                // Call trigger
5236
+                $this->context=array('extrafieldupdate'=>1);
5237
+                $result=$this->call_trigger($trigger, $userused);
5238
+                if ($result < 0) $error++;
5239
+                // End call trigger
5240
+            }
5241
+
5242
+            if ($error)
5243
+            {
5244
+                dol_syslog(get_class($this) . "::".__METHOD__ . $this->error, LOG_ERR);
5245
+                $this->db->rollback();
5246
+                return -1;
5247
+            }
5248
+            else
5249
+            {
5250
+                $this->db->commit();
5251
+                return 1;
5252
+            }
5253
+        }
5254
+        else return 0;
5255
+    }
5256
+
5257
+
5258
+    /**
5259
+     * Return HTML string to put an input field into a page
5260
+     * Code very similar with showInputField of extra fields
5261
+     *
5262
+     * @param  array   		$val	       Array of properties for field to show
5263
+     * @param  string  		$key           Key of attribute
5264
+     * @param  string  		$value         Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value)
5265
+     * @param  string  		$moreparam     To add more parameters on html input tag
5266
+     * @param  string  		$keysuffix     Prefix string to add into name and id of field (can be used to avoid duplicate names)
5267
+     * @param  string  		$keyprefix     Suffix string to add into name and id of field (can be used to avoid duplicate names)
5268
+     * @param  string|int		$morecss       Value for css to define style/length of field. May also be a numeric.
5269
+     * @return string
5270
+     */
5271
+    function showInputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss=0)
5272
+    {
5273
+        global $conf,$langs,$form;
5274
+
5275
+        if (! is_object($form))
5276
+        {
5277
+            require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5278
+            $form=new Form($this->db);
5279
+        }
5280
+
5281
+        $val=$this->fields[$key];
5282
+
5283
+        $out='';
5284
+        $type='';
5285
+        $param = array();
5286
+        $param['options']=array();
5287
+        $size =$this->fields[$key]['size'];
5288
+        // Because we work on extrafields
5289
+        if(preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)){
5290
+            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5291
+            $type ='link';
5292
+        } elseif(preg_match('/^link:(.*):(.*)/i', $val['type'], $reg)) {
5293
+            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5294
+            $type ='link';
5295
+        } elseif(preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
5296
+            $param['options']=array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4]=>'N');
5297
+            $type ='sellist';
5298
+        } elseif(preg_match('/varchar\((\d+)\)/', $val['type'],$reg)) {
5299
+            $param['options']=array();
5300
+            $type ='varchar';
5301
+            $size=$reg[1];
5302
+        } elseif(preg_match('/varchar/', $val['type'])) {
5303
+            $param['options']=array();
5304
+            $type ='varchar';
5305
+        } elseif(is_array($this->fields[$key]['arrayofkeyval'])) {
5306
+            $param['options']=$this->fields[$key]['arrayofkeyval'];
5307
+            $type ='select';
5308
+        } else {
5309
+            $param['options']=array();
5310
+            $type =$this->fields[$key]['type'];
5311
+        }
5693 5312
 
5694
-				$fields_label = explode('|', $InfoFieldList[1]);
5695
-				if (is_array($fields_label)) {
5696
-					$keyList .= ', ';
5697
-					$keyList .= implode(', ', $fields_label);
5698
-				}
5313
+        $label=$this->fields[$key]['label'];
5314
+        //$elementtype=$this->fields[$key]['elementtype'];	// Seems not used
5315
+        $default=$this->fields[$key]['default'];
5316
+        $computed=$this->fields[$key]['computed'];
5317
+        $unique=$this->fields[$key]['unique'];
5318
+        $required=$this->fields[$key]['required'];
5319
+
5320
+        $langfile=$this->fields[$key]['langfile'];
5321
+        $list=$this->fields[$key]['list'];
5322
+        $hidden=abs($this->fields[$key]['visible'])!=1?1:0;
5323
+
5324
+        $objectid = $this->id;
5325
+
5326
+
5327
+        if ($computed)
5328
+        {
5329
+            if (! preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
5330
+            else return '';
5331
+        }
5332
+
5333
+
5334
+        // Use in priority showsize from parameters, then $val['css'] then autodefine
5335
+        if (empty($morecss) && ! empty($val['css']))
5336
+        {
5337
+            $showsize = $val['css'];
5338
+        }
5339
+        if (empty($morecss))
5340
+        {
5341
+            if ($type == 'date')
5342
+            {
5343
+                $morecss = 'minwidth100imp';
5344
+            }
5345
+            elseif ($type == 'datetime')
5346
+            {
5347
+                $morecss = 'minwidth200imp';
5348
+            }
5349
+            elseif (in_array($type,array('int','integer','price')) || preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5350
+            {
5351
+                $morecss = 'maxwidth75';
5352
+                        }elseif ($type == 'url')
5353
+            {
5354
+                $morecss='minwidth400';
5355
+            }
5356
+            elseif ($type == 'boolean')
5357
+            {
5358
+                $morecss='';
5359
+            }
5360
+            else
5361
+            {
5362
+                if (round($size) < 12)
5363
+                {
5364
+                    $morecss = 'minwidth100';
5365
+                }
5366
+                else if (round($size) <= 48)
5367
+                {
5368
+                    $morecss = 'minwidth200';
5369
+                }
5370
+                else
5371
+                {
5372
+                    $morecss = 'minwidth400';
5373
+                }
5374
+            }
5375
+        }
5376
+
5377
+        if (in_array($type,array('date','datetime')))
5378
+        {
5379
+            $tmp=explode(',',$size);
5380
+            $newsize=$tmp[0];
5381
+
5382
+            $showtime = in_array($type,array('datetime')) ? 1 : 0;
5383
+
5384
+            // Do not show current date when field not required (see selectDate() method)
5385
+            if (!$required && $value == '') $value = '-1';
5386
+
5387
+            // TODO Must also support $moreparam
5388
+            $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
5389
+        }
5390
+        elseif (in_array($type,array('int','integer')))
5391
+        {
5392
+            $tmp=explode(',',$size);
5393
+            $newsize=$tmp[0];
5394
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$newsize.'" value="'.dol_escape_htmltag($value).'"'.($moreparam?$moreparam:'').'>';
5395
+        }
5396
+        elseif (preg_match('/varchar/', $type))
5397
+        {
5398
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$size.'" value="'.dol_escape_htmltag($value).'"'.($moreparam?$moreparam:'').'>';
5399
+        }
5400
+        elseif (in_array($type, array('mail', 'phone', 'url')))
5401
+        {
5402
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5403
+        }
5404
+        elseif ($type == 'text')
5405
+        {
5406
+            if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5407
+            {
5408
+                require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5409
+                $doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,false,ROWS_5,'90%');
5410
+                $out=$doleditor->Create(1);
5411
+            }
5412
+            else
5413
+            {
5414
+                $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5415
+            }
5416
+        }
5417
+        elseif ($type == 'html')
5418
+        {
5419
+            if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5420
+            {
5421
+                require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5422
+                $doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,! empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE,ROWS_5,'90%');
5423
+                $out=$doleditor->Create(1);
5424
+            }
5425
+            else
5426
+            {
5427
+                $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5428
+            }
5429
+        }
5430
+        elseif ($type == 'boolean')
5431
+        {
5432
+            $checked='';
5433
+            if (!empty($value)) {
5434
+                $checked=' checked value="1" ';
5435
+            } else {
5436
+                $checked=' value="1" ';
5437
+            }
5438
+            $out='<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
5439
+        }
5440
+        elseif ($type == 'price')
5441
+        {
5442
+            if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5443
+                $value=price($value);
5444
+            }
5445
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> '.$langs->getCurrencySymbol($conf->currency);
5446
+        }
5447
+        elseif (preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5448
+        {
5449
+            if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5450
+                $value=price($value);
5451
+            }
5452
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
5453
+        }
5454
+        elseif ($type == 'select')
5455
+        {
5456
+            $out = '';
5457
+            if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5458
+            {
5459
+                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5460
+                $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5461
+            }
5462
+
5463
+            $out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5464
+                if((! isset($this->fields[$key]['default'])) ||($this->fields[$key]['notnull']!=1))$out.='<option value="0">&nbsp;</option>';
5465
+            foreach ($param['options'] as $key => $val)
5466
+            {
5467
+                if ((string) $key == '') continue;
5468
+                list($val, $parent) = explode('|', $val);
5469
+                $out.='<option value="'.$key.'"';
5470
+                $out.= (((string) $value == (string) $key)?' selected':'');
5471
+                $out.= (!empty($parent)?' parent="'.$parent.'"':'');
5472
+                $out.='>'.$val.'</option>';
5473
+            }
5474
+            $out.='</select>';
5475
+        }
5476
+        elseif ($type == 'sellist')
5477
+        {
5478
+            $out = '';
5479
+            if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5480
+            {
5481
+                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5482
+                $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5483
+            }
5484
+
5485
+            $out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5486
+            if (is_array($param['options']))
5487
+            {
5488
+                $param_list=array_keys($param['options']);
5489
+                $InfoFieldList = explode(":", $param_list[0]);
5490
+                $parentName='';
5491
+                $parentField='';
5492
+                // 0 : tableName
5493
+                // 1 : label field name
5494
+                // 2 : key fields name (if differ of rowid)
5495
+                // 3 : key field parent (for dependent lists)
5496
+                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5497
+                $keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
5498
+
5499
+
5500
+                if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
5501
+                {
5502
+                    if (strpos($InfoFieldList[4], 'extra.') !== false)
5503
+                    {
5504
+                        $keyList='main.'.$InfoFieldList[2].' as rowid';
5505
+                    } else {
5506
+                        $keyList=$InfoFieldList[2].' as rowid';
5507
+                    }
5508
+                }
5509
+                if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
5510
+                {
5511
+                    list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
5512
+                    $keyList.= ', '.$parentField;
5513
+                }
5514
+
5515
+                $fields_label = explode('|',$InfoFieldList[1]);
5516
+                if (is_array($fields_label))
5517
+                {
5518
+                    $keyList .=', ';
5519
+                    $keyList .= implode(', ', $fields_label);
5520
+                }
5521
+
5522
+                $sqlwhere='';
5523
+                $sql = 'SELECT '.$keyList;
5524
+                $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
5525
+                if (!empty($InfoFieldList[4]))
5526
+                {
5527
+                    // can use SELECT request
5528
+                    if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5529
+                        $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5530
+                    }
5531
+
5532
+                    // current object id can be use into filter
5533
+                    if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5534
+                        $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5535
+                    } else {
5536
+                        $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5537
+                    }
5538
+                    //We have to join on extrafield table
5539
+                    if (strpos($InfoFieldList[4], 'extra')!==false)
5540
+                    {
5541
+                        $sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
5542
+                        $sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
5543
+                    }
5544
+                    else
5545
+                    {
5546
+                        $sqlwhere.= ' WHERE '.$InfoFieldList[4];
5547
+                    }
5548
+                }
5549
+                else
5550
+                {
5551
+                    $sqlwhere.= ' WHERE 1=1';
5552
+                }
5553
+                // Some tables may have field, some other not. For the moment we disable it.
5554
+                if (in_array($InfoFieldList[0],array('tablewithentity')))
5555
+                {
5556
+                    $sqlwhere.= ' AND entity = '.$conf->entity;
5557
+                }
5558
+                $sql.=$sqlwhere;
5559
+                //print $sql;
5560
+
5561
+                $sql .= ' ORDER BY ' . implode(', ', $fields_label);
5562
+
5563
+                dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
5564
+                $resql = $this->db->query($sql);
5565
+                if ($resql)
5566
+                {
5567
+                    $out.='<option value="0">&nbsp;</option>';
5568
+                    $num = $this->db->num_rows($resql);
5569
+                    $i = 0;
5570
+                    while ($i < $num)
5571
+                    {
5572
+                        $labeltoshow='';
5573
+                        $obj = $this->db->fetch_object($resql);
5574
+
5575
+                        // Several field into label (eq table:code|libelle:rowid)
5576
+                        $notrans = false;
5577
+                        $fields_label = explode('|',$InfoFieldList[1]);
5578
+                        if (is_array($fields_label))
5579
+                        {
5580
+                            $notrans = true;
5581
+                            foreach ($fields_label as $field_toshow)
5582
+                            {
5583
+                                $labeltoshow.= $obj->$field_toshow.' ';
5584
+                            }
5585
+                        }
5586
+                        else
5587
+                        {
5588
+                            $labeltoshow=$obj->{$InfoFieldList[1]};
5589
+                        }
5590
+                        $labeltoshow=dol_trunc($labeltoshow,45);
5591
+
5592
+                        if ($value == $obj->rowid)
5593
+                        {
5594
+                            foreach ($fields_label as $field_toshow)
5595
+                            {
5596
+                                $translabel=$langs->trans($obj->$field_toshow);
5597
+                                if ($translabel!=$obj->$field_toshow) {
5598
+                                    $labeltoshow=dol_trunc($translabel,18).' ';
5599
+                                }else {
5600
+                                    $labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
5601
+                                }
5602
+                            }
5603
+                            $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5604
+                        }
5605
+                        else
5606
+                        {
5607
+                            if (! $notrans)
5608
+                            {
5609
+                                $translabel=$langs->trans($obj->{$InfoFieldList[1]});
5610
+                                if ($translabel!=$obj->{$InfoFieldList[1]}) {
5611
+                                    $labeltoshow=dol_trunc($translabel,18);
5612
+                                }
5613
+                                else {
5614
+                                    $labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
5615
+                                }
5616
+                            }
5617
+                            if (empty($labeltoshow)) $labeltoshow='(not defined)';
5618
+                            if ($value==$obj->rowid)
5619
+                            {
5620
+                                $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5621
+                            }
5622
+
5623
+                            if (!empty($InfoFieldList[3]) && $parentField)
5624
+                            {
5625
+                                $parent = $parentName.':'.$obj->{$parentField};
5626
+                            }
5627
+
5628
+                            $out.='<option value="'.$obj->rowid.'"';
5629
+                            $out.= ($value==$obj->rowid?' selected':'');
5630
+                            $out.= (!empty($parent)?' parent="'.$parent.'"':'');
5631
+                            $out.='>'.$labeltoshow.'</option>';
5632
+                        }
5633
+
5634
+                        $i++;
5635
+                    }
5636
+                    $this->db->free($resql);
5637
+                }
5638
+                else {
5639
+                    print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
5640
+                }
5641
+            }
5642
+            $out.='</select>';
5643
+        }
5644
+        elseif ($type == 'checkbox')
5645
+        {
5646
+            $value_arr=explode(',',$value);
5647
+            $out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
5648
+        }
5649
+        elseif ($type == 'radio')
5650
+        {
5651
+            $out='';
5652
+            foreach ($param['options'] as $keyopt => $val)
5653
+            {
5654
+                $out.='<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'');
5655
+                $out.=' value="'.$keyopt.'"';
5656
+                $out.=' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
5657
+                $out.= ($value==$keyopt?'checked':'');
5658
+                $out.='/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
5659
+            }
5660
+        }
5661
+        elseif ($type == 'chkbxlst')
5662
+        {
5663
+            if (is_array($value)) {
5664
+                $value_arr = $value;
5665
+            }
5666
+            else {
5667
+                $value_arr = explode(',', $value);
5668
+            }
5669
+
5670
+            if (is_array($param['options'])) {
5671
+                $param_list = array_keys($param['options']);
5672
+                $InfoFieldList = explode(":", $param_list[0]);
5673
+                $parentName='';
5674
+                $parentField='';
5675
+                // 0 : tableName
5676
+                // 1 : label field name
5677
+                // 2 : key fields name (if differ of rowid)
5678
+                // 3 : key field parent (for dependent lists)
5679
+                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5680
+                $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
5681
+
5682
+                if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
5683
+                    list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
5684
+                    $keyList .= ', ' . $parentField;
5685
+                }
5686
+                if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
5687
+                    if (strpos($InfoFieldList[4], 'extra.') !== false) {
5688
+                        $keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
5689
+                    } else {
5690
+                        $keyList = $InfoFieldList[2] . ' as rowid';
5691
+                    }
5692
+                }
5693
+
5694
+                $fields_label = explode('|', $InfoFieldList[1]);
5695
+                if (is_array($fields_label)) {
5696
+                    $keyList .= ', ';
5697
+                    $keyList .= implode(', ', $fields_label);
5698
+                }
5699
+
5700
+                $sqlwhere = '';
5701
+                $sql = 'SELECT ' . $keyList;
5702
+                $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5703
+                if (! empty($InfoFieldList[4])) {
5704
+
5705
+                    // can use SELECT request
5706
+                    if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5707
+                        $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5708
+                    }
5709
+
5710
+                    // current object id can be use into filter
5711
+                    if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5712
+                        $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5713
+                    } else {
5714
+                        $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5715
+                    }
5716
+
5717
+                    // We have to join on extrafield table
5718
+                    if (strpos($InfoFieldList[4], 'extra') !== false) {
5719
+                        $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
5720
+                        $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
5721
+                    } else {
5722
+                        $sqlwhere .= ' WHERE ' . $InfoFieldList[4];
5723
+                    }
5724
+                } else {
5725
+                    $sqlwhere .= ' WHERE 1=1';
5726
+                }
5727
+                // Some tables may have field, some other not. For the moment we disable it.
5728
+                if (in_array($InfoFieldList[0], array ('tablewithentity')))
5729
+                {
5730
+                    $sqlwhere .= ' AND entity = ' . $conf->entity;
5731
+                }
5732
+                // $sql.=preg_replace('/^ AND /','',$sqlwhere);
5733
+                // print $sql;
5734
+
5735
+                $sql .= $sqlwhere;
5736
+                dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
5737
+                $resql = $this->db->query($sql);
5738
+                if ($resql) {
5739
+                    $num = $this->db->num_rows($resql);
5740
+                    $i = 0;
5741
+
5742
+                    $data=array();
5743
+
5744
+                    while ( $i < $num ) {
5745
+                        $labeltoshow = '';
5746
+                        $obj = $this->db->fetch_object($resql);
5747
+
5748
+                        $notrans = false;
5749
+                        // Several field into label (eq table:code|libelle:rowid)
5750
+                        $fields_label = explode('|', $InfoFieldList[1]);
5751
+                        if (is_array($fields_label)) {
5752
+                            $notrans = true;
5753
+                            foreach ( $fields_label as $field_toshow ) {
5754
+                                $labeltoshow .= $obj->$field_toshow . ' ';
5755
+                            }
5756
+                        } else {
5757
+                            $labeltoshow = $obj->{$InfoFieldList[1]};
5758
+                        }
5759
+                        $labeltoshow = dol_trunc($labeltoshow, 45);
5760
+
5761
+                        if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5762
+                            foreach ( $fields_label as $field_toshow ) {
5763
+                                $translabel = $langs->trans($obj->$field_toshow);
5764
+                                if ($translabel != $obj->$field_toshow) {
5765
+                                    $labeltoshow = dol_trunc($translabel, 18) . ' ';
5766
+                                } else {
5767
+                                    $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
5768
+                                }
5769
+                            }
5770
+
5771
+                            $data[$obj->rowid]=$labeltoshow;
5772
+                        } else {
5773
+                            if (! $notrans) {
5774
+                                $translabel = $langs->trans($obj->{$InfoFieldList[1]});
5775
+                                if ($translabel != $obj->{$InfoFieldList[1]}) {
5776
+                                    $labeltoshow = dol_trunc($translabel, 18);
5777
+                                } else {
5778
+                                    $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
5779
+                                }
5780
+                            }
5781
+                            if (empty($labeltoshow))
5782
+                                $labeltoshow = '(not defined)';
5783
+
5784
+                                if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5785
+                                    $data[$obj->rowid]=$labeltoshow;
5786
+                                }
5787
+
5788
+                                if (! empty($InfoFieldList[3]) && $parentField) {
5789
+                                    $parent = $parentName . ':' . $obj->{$parentField};
5790
+                                }
5791
+
5792
+                                $data[$obj->rowid]=$labeltoshow;
5793
+                        }
5794
+
5795
+                        $i ++;
5796
+                    }
5797
+                    $this->db->free($resql);
5798
+
5799
+                    $out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
5800
+                } else {
5801
+                    print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
5802
+                }
5803
+            }
5804
+        }
5805
+        elseif ($type == 'link')
5806
+        {
5807
+            $param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
5808
+            $showempty=(($required && $default != '')?0:1);
5809
+            $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty);
5810
+            if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
5811
+            {
5812
+                        list($class,$classfile)=explode(':',$param_list[0]);
5813
+                        if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) $url_path=dol_buildpath(dirname(dirname($classfile)).'/card.php',1);
5814
+                        else $url_path=dol_buildpath(dirname(dirname($classfile)).'/'.$class.'_card.php',1);
5815
+                        $out.='<a class="butActionNew" href="'.$url_path.'?action=create&backtopage='.$_SERVER['PHP_SELF'].'"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5816
+                        // TODO Add Javascript code to add input fields contents to new elements urls
5817
+            }
5818
+        }
5819
+        elseif ($type == 'password')
5820
+        {
5821
+            // If prefix is 'search_', field is used as a filter, we use a common text field.
5822
+            $out='<input type="'.($keyprefix=='search_'?'text':'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
5823
+        }
5824
+        elseif ($type == 'array')
5825
+        {
5826
+            $newval = $val;
5827
+            $newval['type'] = 'varchar(256)';
5828
+
5829
+            $out='';
5830
+
5831
+            $inputs = array();
5832
+            if(! empty($value)) {
5833
+                foreach($value as $option) {
5834
+                    $out.= '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5835
+                    $out.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', $option, $moreparam, '', '', $showsize).'<br></span>';
5836
+                }
5837
+            }
5838
+
5839
+            $out.= '<a id="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_add" href="javascript:;"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5840
+
5841
+            $newInput = '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5842
+            $newInput.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', '', $moreparam, '', '', $showsize).'<br></span>';
5843
+
5844
+            if(! empty($conf->use_javascript_ajax)) {
5845
+                $out.= '
5846
+					<script type="text/javascript">
5847
+					$(document).ready(function() {
5848
+						$("a#'.dol_escape_js($keyprefix.$key.$keysuffix).'_add").click(function() {
5849
+							$("'.dol_escape_js($newInput).'").insertBefore(this);
5850
+						});
5851
+
5852
+						$(document).on("click", "a.'.dol_escape_js($keyprefix.$key.$keysuffix).'_del", function() {
5853
+							$(this).parent().remove();
5854
+						});
5855
+					});
5856
+					</script>';
5857
+            }
5858
+        }
5859
+        if (!empty($hidden)) {
5860
+            $out='<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
5861
+        }
5862
+        /* Add comments
5863
+		 if ($type == 'date') $out.=' (YYYY-MM-DD)';
5864
+		 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
5865
+		 */
5866
+        return $out;
5867
+    }
5868
+
5869
+    /**
5870
+     * Return HTML string to show a field into a page
5871
+     * Code very similar with showOutputField of extra fields
5872
+     *
5873
+     * @param  array   $val		       Array of properties of field to show
5874
+     * @param  string  $key            Key of attribute
5875
+     * @param  string  $value          Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value)
5876
+     * @param  string  $moreparam      To add more parametes on html input tag
5877
+     * @param  string  $keysuffix      Prefix string to add into name and id of field (can be used to avoid duplicate names)
5878
+     * @param  string  $keyprefix      Suffix string to add into name and id of field (can be used to avoid duplicate names)
5879
+     * @param  mixed   $showsize       Value for css to define size. May also be a numeric.
5880
+     * @return string
5881
+     */
5882
+    function showOutputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0)
5883
+    {
5884
+        global $conf,$langs,$form;
5885
+
5886
+        if (! is_object($form))
5887
+        {
5888
+            require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5889
+            $form=new Form($this->db);
5890
+        }
5891
+
5892
+        $objectid = $this->id;
5893
+        $label = $val['label'];
5894
+        $type  = $val['type'];
5895
+        $size  = $val['css'];
5896
+
5897
+        // Convert var to be able to share same code than showOutputField of extrafields
5898
+        if (preg_match('/varchar\((\d+)\)/', $type, $reg))
5899
+        {
5900
+            $type = 'varchar';		// convert varchar(xx) int varchar
5901
+            $size = $reg[1];
5902
+        }
5903
+        elseif (preg_match('/varchar/', $type)) $type = 'varchar';		// convert varchar(xx) int varchar
5904
+        if (is_array($val['arrayofkeyval'])) $type='select';
5905
+        if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link';
5906
+
5907
+        $default=$val['default'];
5908
+        $computed=$val['computed'];
5909
+        $unique=$val['unique'];
5910
+        $required=$val['required'];
5911
+        $param=$val['param'];
5912
+        if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval'];
5913
+        if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg))
5914
+        {
5915
+            $type='link';
5916
+            $param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
5917
+        }
5918
+        $langfile=$val['langfile'];
5919
+        $list=$val['list'];
5920
+        $help=$val['help'];
5921
+        $hidden=(($val['visible'] == 0) ? 1 : 0);			// If zero, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
5922
+
5923
+        if ($hidden) return '';
5924
+
5925
+        // If field is a computed field, value must become result of compute
5926
+        if ($computed)
5927
+        {
5928
+            // Make the eval of compute string
5929
+            //var_dump($computed);
5930
+            $value = dol_eval($computed, 1, 0);
5931
+        }
5932
+
5933
+        if (empty($showsize))
5934
+        {
5935
+            if ($type == 'date')
5936
+            {
5937
+                //$showsize=10;
5938
+                $showsize = 'minwidth100imp';
5939
+            }
5940
+            elseif ($type == 'datetime')
5941
+            {
5942
+                //$showsize=19;
5943
+                $showsize = 'minwidth200imp';
5944
+            }
5945
+            elseif (in_array($type,array('int','double','price')))
5946
+            {
5947
+                //$showsize=10;
5948
+                $showsize = 'maxwidth75';
5949
+            }
5950
+            elseif ($type == 'url')
5951
+            {
5952
+                $showsize='minwidth400';
5953
+            }
5954
+            elseif ($type == 'boolean')
5955
+            {
5956
+                $showsize='';
5957
+            }
5958
+            else
5959
+            {
5960
+                if (round($size) < 12)
5961
+                {
5962
+                    $showsize = 'minwidth100';
5963
+                }
5964
+                else if (round($size) <= 48)
5965
+                {
5966
+                    $showsize = 'minwidth200';
5967
+                }
5968
+                else
5969
+                {
5970
+                    //$showsize=48;
5971
+                    $showsize = 'minwidth400';
5972
+                }
5973
+            }
5974
+        }
5975
+
5976
+        // Format output value differently according to properties of field
5977
+        if ($key == 'ref' && method_exists($this, 'getNomUrl')) $value=$this->getNomUrl(1, '', 0, '', 1);
5978
+        elseif ($key == 'status' && method_exists($this, 'getLibStatut')) $value=$this->getLibStatut(3);
5979
+        elseif ($type == 'date')
5980
+        {
5981
+            if(! empty($value)) {
5982
+                $value=dol_print_date($value,'day');
5983
+            } else {
5984
+                $value='';
5985
+            }
5986
+        }
5987
+        elseif ($type == 'datetime')
5988
+        {
5989
+            if(! empty($value)) {
5990
+                $value=dol_print_date($value,'dayhour');
5991
+            } else {
5992
+                $value='';
5993
+            }
5994
+        }
5995
+        elseif ($type == 'double')
5996
+        {
5997
+            if (!empty($value)) {
5998
+                $value=price($value);
5999
+            }
6000
+        }
6001
+        elseif ($type == 'boolean')
6002
+        {
6003
+            $checked='';
6004
+            if (!empty($value)) {
6005
+                $checked=' checked ';
6006
+            }
6007
+            $value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
6008
+        }
6009
+        elseif ($type == 'mail')
6010
+        {
6011
+            $value=dol_print_email($value,0,0,0,64,1,1);
6012
+        }
6013
+        elseif ($type == 'url')
6014
+        {
6015
+            $value=dol_print_url($value,'_blank',32,1);
6016
+        }
6017
+        elseif ($type == 'phone')
6018
+        {
6019
+            $value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
6020
+        }
6021
+        elseif ($type == 'price')
6022
+        {
6023
+            $value=price($value,0,$langs,0,0,-1,$conf->currency);
6024
+        }
6025
+        elseif ($type == 'select')
6026
+        {
6027
+            $value=$param['options'][$value];
6028
+        }
6029
+        elseif ($type == 'sellist')
6030
+        {
6031
+            $param_list=array_keys($param['options']);
6032
+            $InfoFieldList = explode(":", $param_list[0]);
6033
+
6034
+            $selectkey="rowid";
6035
+            $keyList='rowid';
6036
+
6037
+            if (count($InfoFieldList)>=3)
6038
+            {
6039
+                $selectkey = $InfoFieldList[2];
6040
+                $keyList=$InfoFieldList[2].' as rowid';
6041
+            }
6042
+
6043
+            $fields_label = explode('|',$InfoFieldList[1]);
6044
+            if(is_array($fields_label)) {
6045
+                $keyList .=', ';
6046
+                $keyList .= implode(', ', $fields_label);
6047
+            }
6048
+
6049
+            $sql = 'SELECT '.$keyList;
6050
+            $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
6051
+            if (strpos($InfoFieldList[4], 'extra')!==false)
6052
+            {
6053
+                $sql.= ' as main';
6054
+            }
6055
+            if ($selectkey=='rowid' && empty($value)) {
6056
+                $sql.= " WHERE ".$selectkey."=0";
6057
+            } elseif ($selectkey=='rowid') {
6058
+                $sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
6059
+            }else {
6060
+                $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6061
+            }
6062
+
6063
+            //$sql.= ' AND entity = '.$conf->entity;
6064
+
6065
+            dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
6066
+            $resql = $this->db->query($sql);
6067
+            if ($resql)
6068
+            {
6069
+                $value='';	// value was used, so now we reste it to use it to build final output
6070
+
6071
+                $obj = $this->db->fetch_object($resql);
6072
+
6073
+                // Several field into label (eq table:code|libelle:rowid)
6074
+                $fields_label = explode('|',$InfoFieldList[1]);
6075
+
6076
+                if(is_array($fields_label) && count($fields_label)>1)
6077
+                {
6078
+                    foreach ($fields_label as $field_toshow)
6079
+                    {
6080
+                        $translabel='';
6081
+                        if (!empty($obj->$field_toshow)) {
6082
+                            $translabel=$langs->trans($obj->$field_toshow);
6083
+                        }
6084
+                        if ($translabel!=$field_toshow) {
6085
+                            $value.=dol_trunc($translabel,18).' ';
6086
+                        }else {
6087
+                            $value.=$obj->$field_toshow.' ';
6088
+                        }
6089
+                    }
6090
+                }
6091
+                else
6092
+                {
6093
+                    $translabel='';
6094
+                    if (!empty($obj->{$InfoFieldList[1]})) {
6095
+                        $translabel=$langs->trans($obj->{$InfoFieldList[1]});
6096
+                    }
6097
+                    if ($translabel!=$obj->{$InfoFieldList[1]}) {
6098
+                        $value=dol_trunc($translabel,18);
6099
+                    }else {
6100
+                        $value=$obj->{$InfoFieldList[1]};
6101
+                    }
6102
+                }
6103
+            }
6104
+            else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
6105
+        }
6106
+        elseif ($type == 'radio')
6107
+        {
6108
+            $value=$param['options'][$value];
6109
+        }
6110
+        elseif ($type == 'checkbox')
6111
+        {
6112
+            $value_arr=explode(',',$value);
6113
+            $value='';
6114
+            if (is_array($value_arr) && count($value_arr)>0)
6115
+            {
6116
+                foreach ($value_arr as $keyval=>$valueval) {
6117
+                    $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$param['options'][$valueval].'</li>';
6118
+                }
6119
+                $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6120
+            }
6121
+        }
6122
+        elseif ($type == 'chkbxlst')
6123
+        {
6124
+            $value_arr = explode(',', $value);
6125
+
6126
+            $param_list = array_keys($param['options']);
6127
+            $InfoFieldList = explode(":", $param_list[0]);
6128
+
6129
+            $selectkey = "rowid";
6130
+            $keyList = 'rowid';
6131
+
6132
+            if (count($InfoFieldList) >= 3) {
6133
+                $selectkey = $InfoFieldList[2];
6134
+                $keyList = $InfoFieldList[2] . ' as rowid';
6135
+            }
6136
+
6137
+            $fields_label = explode('|', $InfoFieldList[1]);
6138
+            if (is_array($fields_label)) {
6139
+                $keyList .= ', ';
6140
+                $keyList .= implode(', ', $fields_label);
6141
+            }
6142
+
6143
+            $sql = 'SELECT ' . $keyList;
6144
+            $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
6145
+            if (strpos($InfoFieldList[4], 'extra') !== false) {
6146
+                $sql .= ' as main';
6147
+            }
6148
+            // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6149
+            // $sql.= ' AND entity = '.$conf->entity;
6150
+
6151
+            dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
6152
+            $resql = $this->db->query($sql);
6153
+            if ($resql) {
6154
+                $value = ''; // value was used, so now we reste it to use it to build final output
6155
+                $toprint=array();
6156
+                while ( $obj = $this->db->fetch_object($resql) ) {
6157
+
6158
+                    // Several field into label (eq table:code|libelle:rowid)
6159
+                    $fields_label = explode('|', $InfoFieldList[1]);
6160
+                    if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
6161
+                        if (is_array($fields_label) && count($fields_label) > 1) {
6162
+                            foreach ( $fields_label as $field_toshow ) {
6163
+                                $translabel = '';
6164
+                                if (! empty($obj->$field_toshow)) {
6165
+                                    $translabel = $langs->trans($obj->$field_toshow);
6166
+                                }
6167
+                                if ($translabel != $field_toshow) {
6168
+                                    $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6169
+                                } else {
6170
+                                    $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
6171
+                                }
6172
+                            }
6173
+                        } else {
6174
+                            $translabel = '';
6175
+                            if (! empty($obj->{$InfoFieldList[1]})) {
6176
+                                $translabel = $langs->trans($obj->{$InfoFieldList[1]});
6177
+                            }
6178
+                            if ($translabel != $obj->{$InfoFieldList[1]}) {
6179
+                                $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6180
+                            } else {
6181
+                                $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
6182
+                            }
6183
+                        }
6184
+                    }
6185
+                }
6186
+                $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6187
+            } else {
6188
+                dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
6189
+            }
6190
+        }
6191
+        elseif ($type == 'link')
6192
+        {
6193
+            $out='';
6194
+
6195
+            // only if something to display (perf)
6196
+            if ($value)
6197
+            {
6198
+                $param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
6199
+
6200
+                $InfoFieldList = explode(":", $param_list[0]);
6201
+                $classname=$InfoFieldList[0];
6202
+                $classpath=$InfoFieldList[1];
6203
+                $getnomurlparam=(empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
6204
+                if (! empty($classpath))
6205
+                {
6206
+                    dol_include_once($InfoFieldList[1]);
6207
+                    if ($classname && class_exists($classname))
6208
+                    {
6209
+                        $object = new $classname($this->db);
6210
+                        $object->fetch($value);
6211
+                        $value=$object->getNomUrl($getnomurlparam);
6212
+                    }
6213
+                }
6214
+                else
6215
+                {
6216
+                    dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6217
+                    return 'Error bad setup of extrafield';
6218
+                }
6219
+            }
6220
+            else $value='';
6221
+        }
6222
+        elseif ($type == 'text' || $type == 'html')
6223
+        {
6224
+            $value=dol_htmlentitiesbr($value);
6225
+        }
6226
+        elseif ($type == 'password')
6227
+        {
6228
+            $value=preg_replace('/./i','*',$value);
6229
+        }
6230
+        elseif ($type == 'array')
6231
+        {
6232
+            $value = implode('<br>', $value);
6233
+        }
6234
+
6235
+        //print $type.'-'.$size;
6236
+        $out=$value;
6237
+
6238
+        return $out;
6239
+    }
6240
+
6241
+
6242
+    /**
6243
+     * Function to show lines of extrafields with output datas
6244
+     *
6245
+     * @param 	Extrafields $extrafields    Extrafield Object
6246
+     * @param 	string      $mode           Show output (view) or input (edit) for extrafield
6247
+     * @param 	array       $params         Optional parameters. Example: array('style'=>'class="oddeven"', 'colspan'=>$colspan)
6248
+     * @param 	string      $keysuffix      Suffix string to add after name and id of field (can be used to avoid duplicate names)
6249
+     * @param 	string      $keyprefix      Prefix string to add before name and id of field (can be used to avoid duplicate names)
6250
+     * @param	string		$onetrtd		All fields in same tr td
6251
+     * @return 	string
6252
+     */
6253
+    function showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='', $onetrtd=0)
6254
+    {
6255
+        global $db, $conf, $langs, $action, $form;
6256
+
6257
+        if (! is_object($form)) $form=new Form($db);
6258
+
6259
+        $out = '';
6260
+
6261
+        if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label']) > 0)
6262
+        {
6263
+            $out .= "\n";
6264
+            $out .= '<!-- showOptionalsInput --> ';
6265
+            $out .= "\n";
5699 6266
 
5700
-				$sqlwhere = '';
5701
-				$sql = 'SELECT ' . $keyList;
5702
-				$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5703
-				if (! empty($InfoFieldList[4])) {
5704
-
5705
-					// can use SELECT request
5706
-					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5707
-						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5708
-					}
5709
-
5710
-					// current object id can be use into filter
5711
-					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5712
-						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5713
-					} else {
5714
-						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5715
-					}
5716
-
5717
-					// We have to join on extrafield table
5718
-					if (strpos($InfoFieldList[4], 'extra') !== false) {
5719
-						$sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
5720
-						$sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
5721
-					} else {
5722
-						$sqlwhere .= ' WHERE ' . $InfoFieldList[4];
5723
-					}
5724
-				} else {
5725
-					$sqlwhere .= ' WHERE 1=1';
5726
-				}
5727
-				// Some tables may have field, some other not. For the moment we disable it.
5728
-				if (in_array($InfoFieldList[0], array ('tablewithentity')))
5729
-				{
5730
-					$sqlwhere .= ' AND entity = ' . $conf->entity;
5731
-				}
5732
-				// $sql.=preg_replace('/^ AND /','',$sqlwhere);
5733
-				// print $sql;
5734
-
5735
-				$sql .= $sqlwhere;
5736
-				dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
5737
-				$resql = $this->db->query($sql);
5738
-				if ($resql) {
5739
-					$num = $this->db->num_rows($resql);
5740
-					$i = 0;
5741
-
5742
-					$data=array();
5743
-
5744
-					while ( $i < $num ) {
5745
-						$labeltoshow = '';
5746
-						$obj = $this->db->fetch_object($resql);
5747
-
5748
-						$notrans = false;
5749
-						// Several field into label (eq table:code|libelle:rowid)
5750
-						$fields_label = explode('|', $InfoFieldList[1]);
5751
-						if (is_array($fields_label)) {
5752
-							$notrans = true;
5753
-							foreach ( $fields_label as $field_toshow ) {
5754
-								$labeltoshow .= $obj->$field_toshow . ' ';
6267
+            $e = 0;
6268
+            foreach($extrafields->attributes[$this->table_element]['label'] as $key=>$label)
6269
+            {
6270
+                // Show only the key field in params
6271
+                if (is_array($params) && array_key_exists('onlykey',$params) && $key != $params['onlykey']) continue;
6272
+
6273
+                $enabled = 1;
6274
+                if ($enabled && isset($extrafields->attributes[$this->table_element]['list'][$key]))
6275
+                {
6276
+                    $enabled = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1);
6277
+                }
6278
+
6279
+                $perms = 1;
6280
+                if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key]))
6281
+                {
6282
+                    $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1);
6283
+                }
6284
+
6285
+                if (($mode == 'create' || $mode == 'edit') && abs($enabled) != 1 && abs($enabled) != 3) continue;	// <> -1 and <> 1 and <> 3 = not visible on forms, only on list
6286
+                if (empty($perms)) continue;
6287
+
6288
+                // Load language if required
6289
+                if (! empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
6290
+
6291
+                $colspan='3';
6292
+                if (is_array($params) && count($params)>0) {
6293
+                    if (array_key_exists('colspan',$params)) {
6294
+                        $colspan=$params['colspan'];
6295
+                    }
6296
+                }
6297
+
6298
+                switch($mode) {
6299
+                    case "view":
6300
+                        $value=$this->array_options["options_".$key.$keysuffix];
6301
+                        break;
6302
+                    case "edit":
6303
+                        $getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, 'none');				// GETPOST can get value from GET, POST or setup of default values.
6304
+                        // GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
6305
+                        if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix))
6306
+                        {
6307
+                            if (is_array($getposttemp)) {
6308
+                                // $getposttemp is an array but following code expects a comma separated string
6309
+                                $value = implode(",", $getposttemp);
6310
+                            } else {
6311
+                                $value = $getposttemp;
6312
+                            }
6313
+                        } else {
6314
+                            $value = $this->array_options["options_" . $key];			// No GET, no POST, no default value, so we take value of object.
6315
+                        }
6316
+                        //var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
6317
+                        break;
6318
+                }
6319
+
6320
+                if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate')
6321
+                {
6322
+                    $out .= $extrafields->showSeparator($key, $this);
6323
+                }
6324
+                else
6325
+                {
6326
+                    $csstyle='';
6327
+                    $class=(!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
6328
+                    if (is_array($params) && count($params)>0) {
6329
+                        if (array_key_exists('style',$params)) {
6330
+                            $csstyle=$params['style'];
6331
+                        }
6332
+                    }
6333
+
6334
+                    // add html5 elements
6335
+                    $domData  = ' data-element="extrafield"';
6336
+                    $domData .= ' data-targetelement="'.$this->element.'"';
6337
+                    $domData .= ' data-targetid="'.$this->id.'"';
6338
+
6339
+                    $html_id = !empty($this->id) ? 'extrarow-'.$this->element.'_'.$key.'_'.$this->id : '';
6340
+
6341
+                    $out .= '<tr id="'.$html_id.'" '.$csstyle.' class="'.$class.$this->element.'_extras_'.$key.'" '.$domData.' >';
6342
+
6343
+                    if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0)
6344
+                    {
6345
+                        if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) { $colspan='0'; }
6346
+                    }
6347
+
6348
+                    if ($action == 'selectlines') { $colspan++; }
6349
+
6350
+                    // Convert date into timestamp format (value in memory must be a timestamp)
6351
+                    if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('date','datetime')))
6352
+                    {
6353
+                        $datenotinstring = $this->array_options['options_' . $key];
6354
+                        if (! is_numeric($this->array_options['options_' . $key]))	// For backward compatibility
6355
+                        {
6356
+                            $datenotinstring = $this->db->jdate($datenotinstring);
6357
+                        }
6358
+                        $value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?dol_mktime(GETPOST($keyprefix.'options_'.$key.$keysuffix."hour", 'int', 3), GETPOST($keyprefix.'options_'.$key.$keysuffix."min",'int',3), 0, GETPOST($keyprefix.'options_'.$key.$keysuffix."month",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."day",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."year",'int',3)):$datenotinstring;
6359
+                    }
6360
+                    // Convert float submited string into real php numeric (value in memory must be a php numeric)
6361
+                    if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('price','double')))
6362
+                    {
6363
+                        $value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?price2num(GETPOST($keyprefix.'options_'.$key.$keysuffix, 'alpha', 3)):$this->array_options['options_'.$key];
6364
+                    }
6365
+
6366
+                    $labeltoshow = $langs->trans($label);
6367
+
6368
+                    $out .= '<td class="titlefield';
6369
+                    if (GETPOST('action','none') == 'create') $out.='create';
6370
+                    if ($mode != 'view' && ! empty($extrafields->attributes[$this->table_element]['required'][$key])) $out .= ' fieldrequired';
6371
+                    $out .= '">';
6372
+                    if (! empty($extrafields->attributes[$object->table_element]['help'][$key])) $out .= $form->textwithpicto($labeltoshow, $extrafields->attributes[$object->table_element]['help'][$key]);
6373
+                    else $out .= $labeltoshow;
6374
+                    $out .= '</td>';
6375
+
6376
+                    $html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : '';
6377
+                    $out .='<td id="'.$html_id.'" class="'.$this->element.'_extras_'.$key.'" '.($colspan?' colspan="'.$colspan.'"':'').'>';
6378
+
6379
+                    switch($mode) {
6380
+                        case "view":
6381
+                            $out .= $extrafields->showOutputField($key, $value);
6382
+                            break;
6383
+                        case "edit":
6384
+                            $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id);
6385
+                            break;
6386
+                    }
6387
+
6388
+                    $out .= '</td>';
6389
+
6390
+                    if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) $out .= '</tr>';
6391
+                    else $out .= '</tr>';
6392
+                    $e++;
6393
+                }
6394
+            }
6395
+            $out .= "\n";
6396
+            // Add code to manage list depending on others
6397
+            if (! empty($conf->use_javascript_ajax)) {
6398
+                $out .= '
6399
+				<script type="text/javascript">
6400
+				    jQuery(document).ready(function() {
6401
+				    	function showOptions(child_list, parent_list)
6402
+				    	{
6403
+				    		var val = $("select[name=\"options_"+parent_list+"\"]").val();
6404
+				    		var parentVal = parent_list + ":" + val;
6405
+							if(val > 0) {
6406
+					    		$("select[name=\""+child_list+"\"] option[parent]").hide();
6407
+					    		$("select[name=\""+child_list+"\"] option[parent=\""+parentVal+"\"]").show();
6408
+							} else {
6409
+								$("select[name=\""+child_list+"\"] option").show();
5755 6410
 							}
5756
-						} else {
5757
-							$labeltoshow = $obj->{$InfoFieldList[1]};
6411
+				    	}
6412
+						function setListDependencies() {
6413
+					    	jQuery("select option[parent]").parent().each(function() {
6414
+					    		var child_list = $(this).attr("name");
6415
+								var parent = $(this).find("option[parent]:first").attr("parent");
6416
+								var infos = parent.split(":");
6417
+								var parent_list = infos[0];
6418
+								$("select[name=\""+parent_list+"\"]").change(function() {
6419
+									showOptions(child_list, parent_list);
6420
+								});
6421
+					    	});
5758 6422
 						}
5759
-						$labeltoshow = dol_trunc($labeltoshow, 45);
5760
-
5761
-						if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5762
-							foreach ( $fields_label as $field_toshow ) {
5763
-								$translabel = $langs->trans($obj->$field_toshow);
5764
-								if ($translabel != $obj->$field_toshow) {
5765
-									$labeltoshow = dol_trunc($translabel, 18) . ' ';
5766
-								} else {
5767
-									$labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
5768
-								}
5769
-							}
5770 6423
 
5771
-							$data[$obj->rowid]=$labeltoshow;
5772
-						} else {
5773
-							if (! $notrans) {
5774
-								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
5775
-								if ($translabel != $obj->{$InfoFieldList[1]}) {
5776
-									$labeltoshow = dol_trunc($translabel, 18);
5777
-								} else {
5778
-									$labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
5779
-								}
5780
-							}
5781
-							if (empty($labeltoshow))
5782
-								$labeltoshow = '(not defined)';
6424
+						setListDependencies();
6425
+				    });
6426
+				</script>'."\n";
6427
+                $out .= '<!-- /showOptionalsInput --> '."\n";
6428
+            }
6429
+        }
6430
+        return $out;
6431
+    }
5783 6432
 
5784
-								if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5785
-									$data[$obj->rowid]=$labeltoshow;
5786
-								}
5787 6433
 
5788
-								if (! empty($InfoFieldList[3]) && $parentField) {
5789
-									$parent = $parentName . ':' . $obj->{$parentField};
5790
-								}
6434
+    /**
6435
+     * Returns the rights used for this class
6436
+     * @return stdClass
6437
+     */
6438
+    public function getRights()
6439
+    {
6440
+        global $user;
5791 6441
 
5792
-								$data[$obj->rowid]=$labeltoshow;
5793
-						}
6442
+        $element = $this->element;
6443
+        if ($element == 'facturerec') $element='facture';
5794 6444
 
5795
-						$i ++;
5796
-					}
5797
-					$this->db->free($resql);
6445
+        return $user->rights->{$element};
6446
+    }
5798 6447
 
5799
-					$out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
5800
-				} else {
5801
-					print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
5802
-				}
5803
-			}
5804
-		}
5805
-		elseif ($type == 'link')
5806
-		{
5807
-			$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
5808
-			$showempty=(($required && $default != '')?0:1);
5809
-			$out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty);
5810
-			if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
5811
-			{
5812
-            			list($class,$classfile)=explode(':',$param_list[0]);
5813
-            			if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) $url_path=dol_buildpath(dirname(dirname($classfile)).'/card.php',1);
5814
-            			else $url_path=dol_buildpath(dirname(dirname($classfile)).'/'.$class.'_card.php',1);
5815
-            			$out.='<a class="butActionNew" href="'.$url_path.'?action=create&backtopage='.$_SERVER['PHP_SELF'].'"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5816
-            			// TODO Add Javascript code to add input fields contents to new elements urls
5817
-			}
5818
-		}
5819
-		elseif ($type == 'password')
5820
-		{
5821
-			// If prefix is 'search_', field is used as a filter, we use a common text field.
5822
-			$out='<input type="'.($keyprefix=='search_'?'text':'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
5823
-		}
5824
-		elseif ($type == 'array')
5825
-		{
5826
-			$newval = $val;
5827
-			$newval['type'] = 'varchar(256)';
5828
-
5829
-			$out='';
5830
-
5831
-			$inputs = array();
5832
-			if(! empty($value)) {
5833
-				foreach($value as $option) {
5834
-					$out.= '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5835
-					$out.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', $option, $moreparam, '', '', $showsize).'<br></span>';
5836
-				}
5837
-			}
6448
+    /**
6449
+     * Function used to replace a thirdparty id with another one.
6450
+     * This function is meant to be called from replaceThirdparty with the appropiate tables
6451
+     * Column name fk_soc MUST be used to identify thirdparties
6452
+     *
6453
+     * @param  DoliDB 	   $db 			  Database handler
6454
+     * @param  int 		   $origin_id     Old thirdparty id (the thirdparty to delete)
6455
+     * @param  int 		   $dest_id       New thirdparty id (the thirdparty that will received element of the other)
6456
+     * @param  string[]    $tables        Tables that need to be changed
6457
+     * @param  int         $ignoreerrors  Ignore errors. Return true even if errors. We need this when replacement can fails like for categories (categorie of old thirdparty may already exists on new one)
6458
+     * @return bool						  True if success, False if error
6459
+     */
6460
+    public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
6461
+    {
6462
+        foreach ($tables as $table)
6463
+        {
6464
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_soc = '.$dest_id.' WHERE fk_soc = '.$origin_id;
5838 6465
 
5839
-			$out.= '<a id="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_add" href="javascript:;"><span class="fa fa-plus-circle valignmiddle"></span></a>';
6466
+            if (! $db->query($sql))
6467
+            {
6468
+                if ($ignoreerrors) return true;		// TODO Not enough. If there is A-B on kept thirdarty and B-C on old one, we must get A-B-C after merge. Not A-B.
6469
+                //$this->errors = $db->lasterror();
6470
+                return false;
6471
+            }
6472
+        }
5840 6473
 
5841
-			$newInput = '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5842
-			$newInput.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', '', $moreparam, '', '', $showsize).'<br></span>';
6474
+        return true;
6475
+    }
5843 6476
 
5844
-			if(! empty($conf->use_javascript_ajax)) {
5845
-				$out.= '
5846
-					<script type="text/javascript">
5847
-					$(document).ready(function() {
5848
-						$("a#'.dol_escape_js($keyprefix.$key.$keysuffix).'_add").click(function() {
5849
-							$("'.dol_escape_js($newInput).'").insertBefore(this);
5850
-						});
6477
+    /**
6478
+     * Get buy price to use for margin calculation. This function is called when buy price is unknown.
6479
+     *	 Set buy price = sell price if ForceBuyingPriceIfNull configured,
6480
+     *   else if calculation MARGIN_TYPE = 'costprice' and costprice is defined, use costprice as buyprice
6481
+     *	 else if calculation MARGIN_TYPE = 'pmp' and pmp is calculated, use pmp as buyprice
6482
+     *	 else set min buy price as buy price
6483
+     *
6484
+     * @param float		$unitPrice		 Product unit price
6485
+     * @param float		$discountPercent Line discount percent
6486
+     * @param int		$fk_product		 Product id
6487
+     * @return	float                    <0 if KO, buyprice if OK
6488
+     */
6489
+    public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
6490
+    {
6491
+        global $conf;
5851 6492
 
5852
-						$(document).on("click", "a.'.dol_escape_js($keyprefix.$key.$keysuffix).'_del", function() {
5853
-							$(this).parent().remove();
5854
-						});
5855
-					});
5856
-					</script>';
5857
-			}
5858
-		}
5859
-		if (!empty($hidden)) {
5860
-			$out='<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
5861
-		}
5862
-		/* Add comments
5863
-		 if ($type == 'date') $out.=' (YYYY-MM-DD)';
5864
-		 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
5865
-		 */
5866
-		return $out;
5867
-	}
5868
-
5869
-	/**
5870
-	 * Return HTML string to show a field into a page
5871
-	 * Code very similar with showOutputField of extra fields
5872
-	 *
5873
-	 * @param  array   $val		       Array of properties of field to show
5874
-	 * @param  string  $key            Key of attribute
5875
-	 * @param  string  $value          Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value)
5876
-	 * @param  string  $moreparam      To add more parametes on html input tag
5877
-	 * @param  string  $keysuffix      Prefix string to add into name and id of field (can be used to avoid duplicate names)
5878
-	 * @param  string  $keyprefix      Suffix string to add into name and id of field (can be used to avoid duplicate names)
5879
-	 * @param  mixed   $showsize       Value for css to define size. May also be a numeric.
5880
-	 * @return string
5881
-	 */
5882
-	function showOutputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0)
5883
-	{
5884
-		global $conf,$langs,$form;
5885
-
5886
-		if (! is_object($form))
5887
-		{
5888
-			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5889
-			$form=new Form($this->db);
5890
-		}
5891
-
5892
-		$objectid = $this->id;
5893
-		$label = $val['label'];
5894
-		$type  = $val['type'];
5895
-		$size  = $val['css'];
5896
-
5897
-		// Convert var to be able to share same code than showOutputField of extrafields
5898
-		if (preg_match('/varchar\((\d+)\)/', $type, $reg))
5899
-		{
5900
-			$type = 'varchar';		// convert varchar(xx) int varchar
5901
-			$size = $reg[1];
5902
-		}
5903
-		elseif (preg_match('/varchar/', $type)) $type = 'varchar';		// convert varchar(xx) int varchar
5904
-		if (is_array($val['arrayofkeyval'])) $type='select';
5905
-		if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link';
5906
-
5907
-		$default=$val['default'];
5908
-		$computed=$val['computed'];
5909
-		$unique=$val['unique'];
5910
-		$required=$val['required'];
5911
-		$param=$val['param'];
5912
-		if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval'];
5913
-		if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg))
5914
-		{
5915
-			$type='link';
5916
-			$param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
5917
-		}
5918
-		$langfile=$val['langfile'];
5919
-		$list=$val['list'];
5920
-		$help=$val['help'];
5921
-		$hidden=(($val['visible'] == 0) ? 1 : 0);			// If zero, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
5922
-
5923
-		if ($hidden) return '';
5924
-
5925
-		// If field is a computed field, value must become result of compute
5926
-		if ($computed)
5927
-		{
5928
-			// Make the eval of compute string
5929
-			//var_dump($computed);
5930
-			$value = dol_eval($computed, 1, 0);
5931
-		}
5932
-
5933
-		if (empty($showsize))
5934
-		{
5935
-			if ($type == 'date')
5936
-			{
5937
-				//$showsize=10;
5938
-				$showsize = 'minwidth100imp';
5939
-			}
5940
-			elseif ($type == 'datetime')
5941
-			{
5942
-				//$showsize=19;
5943
-				$showsize = 'minwidth200imp';
5944
-			}
5945
-			elseif (in_array($type,array('int','double','price')))
5946
-			{
5947
-				//$showsize=10;
5948
-				$showsize = 'maxwidth75';
5949
-			}
5950
-			elseif ($type == 'url')
5951
-			{
5952
-				$showsize='minwidth400';
5953
-			}
5954
-			elseif ($type == 'boolean')
5955
-			{
5956
-				$showsize='';
5957
-			}
5958
-			else
5959
-			{
5960
-				if (round($size) < 12)
5961
-				{
5962
-					$showsize = 'minwidth100';
5963
-				}
5964
-				else if (round($size) <= 48)
5965
-				{
5966
-					$showsize = 'minwidth200';
5967
-				}
5968
-				else
5969
-				{
5970
-					//$showsize=48;
5971
-					$showsize = 'minwidth400';
5972
-				}
5973
-			}
5974
-		}
5975
-
5976
-		// Format output value differently according to properties of field
5977
-		if ($key == 'ref' && method_exists($this, 'getNomUrl')) $value=$this->getNomUrl(1, '', 0, '', 1);
5978
-		elseif ($key == 'status' && method_exists($this, 'getLibStatut')) $value=$this->getLibStatut(3);
5979
-		elseif ($type == 'date')
5980
-		{
5981
-			if(! empty($value)) {
5982
-				$value=dol_print_date($value,'day');
5983
-			} else {
5984
-				$value='';
5985
-			}
5986
-		}
5987
-		elseif ($type == 'datetime')
5988
-		{
5989
-			if(! empty($value)) {
5990
-				$value=dol_print_date($value,'dayhour');
5991
-			} else {
5992
-				$value='';
5993
-			}
5994
-		}
5995
-		elseif ($type == 'double')
5996
-		{
5997
-			if (!empty($value)) {
5998
-				$value=price($value);
5999
-			}
6000
-		}
6001
-		elseif ($type == 'boolean')
6002
-		{
6003
-			$checked='';
6004
-			if (!empty($value)) {
6005
-				$checked=' checked ';
6006
-			}
6007
-			$value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
6008
-		}
6009
-		elseif ($type == 'mail')
6010
-		{
6011
-			$value=dol_print_email($value,0,0,0,64,1,1);
6012
-		}
6013
-		elseif ($type == 'url')
6014
-		{
6015
-			$value=dol_print_url($value,'_blank',32,1);
6016
-		}
6017
-		elseif ($type == 'phone')
6018
-		{
6019
-			$value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
6020
-		}
6021
-		elseif ($type == 'price')
6022
-		{
6023
-			$value=price($value,0,$langs,0,0,-1,$conf->currency);
6024
-		}
6025
-		elseif ($type == 'select')
6026
-		{
6027
-			$value=$param['options'][$value];
6028
-		}
6029
-		elseif ($type == 'sellist')
6030
-		{
6031
-			$param_list=array_keys($param['options']);
6032
-			$InfoFieldList = explode(":", $param_list[0]);
6033
-
6034
-			$selectkey="rowid";
6035
-			$keyList='rowid';
6036
-
6037
-			if (count($InfoFieldList)>=3)
6038
-			{
6039
-				$selectkey = $InfoFieldList[2];
6040
-				$keyList=$InfoFieldList[2].' as rowid';
6041
-			}
6042
-
6043
-			$fields_label = explode('|',$InfoFieldList[1]);
6044
-			if(is_array($fields_label)) {
6045
-				$keyList .=', ';
6046
-				$keyList .= implode(', ', $fields_label);
6047
-			}
6048
-
6049
-			$sql = 'SELECT '.$keyList;
6050
-			$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
6051
-			if (strpos($InfoFieldList[4], 'extra')!==false)
6052
-			{
6053
-				$sql.= ' as main';
6054
-			}
6055
-			if ($selectkey=='rowid' && empty($value)) {
6056
-				$sql.= " WHERE ".$selectkey."=0";
6057
-			} elseif ($selectkey=='rowid') {
6058
-				$sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
6059
-			}else {
6060
-				$sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6061
-			}
6062
-
6063
-			//$sql.= ' AND entity = '.$conf->entity;
6064
-
6065
-			dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
6066
-			$resql = $this->db->query($sql);
6067
-			if ($resql)
6068
-			{
6069
-				$value='';	// value was used, so now we reste it to use it to build final output
6493
+        $buyPrice = 0;
6494
+
6495
+        if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) // In most cases, test here is false
6496
+        {
6497
+            $buyPrice = $unitPrice * (1 - $discountPercent / 100);
6498
+        }
6499
+        else
6500
+        {
6501
+            // Get cost price for margin calculation
6502
+            if (! empty($fk_product))
6503
+            {
6504
+                if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice')
6505
+                {
6506
+                    require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6507
+                    $product = new Product($this->db);
6508
+                    $result = $product->fetch($fk_product);
6509
+                    if ($result <= 0)
6510
+                    {
6511
+                        $this->errors[] = 'ErrorProductIdDoesNotExists';
6512
+                        return -1;
6513
+                    }
6514
+                    if ($product->cost_price > 0)
6515
+                    {
6516
+                        $buyPrice = $product->cost_price;
6517
+                    }
6518
+                    else if ($product->pmp > 0)
6519
+                    {
6520
+                        $buyPrice = $product->pmp;
6521
+                    }
6522
+                }
6523
+                else if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp')
6524
+                {
6525
+                    require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6526
+                    $product = new Product($this->db);
6527
+                    $result = $product->fetch($fk_product);
6528
+                    if ($result <= 0)
6529
+                    {
6530
+                        $this->errors[] = 'ErrorProductIdDoesNotExists';
6531
+                        return -1;
6532
+                    }
6533
+                    if ($product->pmp > 0)
6534
+                    {
6535
+                        $buyPrice = $product->pmp;
6536
+                    }
6537
+                }
6538
+
6539
+                if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1','pmp','costprice')))
6540
+                {
6541
+                    require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6542
+                    $productFournisseur = new ProductFournisseur($this->db);
6543
+                    if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0)
6544
+                    {
6545
+                        $buyPrice = $productFournisseur->fourn_unitprice;
6546
+                    }
6547
+                    else if ($result < 0)
6548
+                    {
6549
+                        $this->errors[] = $productFournisseur->error;
6550
+                        return -2;
6551
+                    }
6552
+                }
6553
+            }
6554
+        }
6555
+        return $buyPrice;
6556
+    }
6557
+
6558
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
6559
+    /**
6560
+     *  Show photos of an object (nbmax maximum), into several columns
6561
+     *
6562
+     *  @param		string	$modulepart		'product', 'ticket', ...
6563
+     *  @param      string	$sdir        	Directory to scan (full absolute path)
6564
+     *  @param      int		$size        	0=original size, 1='small' use thumbnail if possible
6565
+     *  @param      int		$nbmax       	Nombre maximum de photos (0=pas de max)
6566
+     *  @param      int		$nbbyrow     	Number of image per line or -1 to use div. Used only if size=1.
6567
+     * 	@param		int		$showfilename	1=Show filename
6568
+     * 	@param		int		$showaction		1=Show icon with action links (resize, delete)
6569
+     * 	@param		int		$maxHeight		Max height of original image when size='small' (so we can use original even if small requested). If 0, always use 'small' thumb image.
6570
+     * 	@param		int		$maxWidth		Max width of original image when size='small'
6571
+     *  @param      int     $nolink         Do not add a href link to view enlarged imaged into a new tab
6572
+     *  @param      int     $notitle        Do not add title tag on image
6573
+     *  @param		int		$usesharelink	Use the public shared link of image (if not available, the 'nophoto' image will be shown instead)
6574
+     *  @return     string					Html code to show photo. Number of photos shown is saved in this->nbphoto
6575
+     */
6576
+    function show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $notitle=0, $usesharelink=0)
6577
+    {
6578
+        // phpcs:enable
6579
+        global $conf,$user,$langs;
6580
+
6581
+        include_once DOL_DOCUMENT_ROOT .'/core/lib/files.lib.php';
6582
+        include_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';
6583
+
6584
+        $sortfield='position_name';
6585
+        $sortorder='asc';
6586
+
6587
+        $dir = $sdir . '/';
6588
+        $pdir = '/';
6589
+        if ($modulepart == 'ticket')
6590
+        {
6591
+            $dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6592
+            $pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6593
+        }
6594
+        else
6595
+        {
6596
+            $dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6597
+            $pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6598
+        }
6599
+
6600
+        // For backward compatibility
6601
+        if ($modulepart == 'product' && ! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
6602
+        {
6603
+            $dir = $sdir . '/'. get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6604
+            $pdir = '/' . get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6605
+        }
6606
+
6607
+        // Defined relative dir to DOL_DATA_ROOT
6608
+        $relativedir = '';
6609
+        if ($dir)
6610
+        {
6611
+            $relativedir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir);
6612
+            $relativedir = preg_replace('/^[\\/]/','',$relativedir);
6613
+            $relativedir = preg_replace('/[\\/]$/','',$relativedir);
6614
+        }
6615
+
6616
+        $dirthumb = $dir.'thumbs/';
6617
+        $pdirthumb = $pdir.'thumbs/';
6618
+
6619
+        $return ='<!-- Photo -->'."\n";
6620
+        $nbphoto=0;
6621
+
6622
+        $filearray=dol_dir_list($dir,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6623
+
6624
+        /*if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))    // For backward compatiblity, we scan also old dirs
6625
+		 {
6626
+		 $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6627
+		 $filearray=array_merge($filearray, $filearrayold);
6628
+		 }*/
6629
+
6630
+        completeFileArrayWithDatabaseInfo($filearray, $relativedir);
6631
+
6632
+        if (count($filearray))
6633
+        {
6634
+            if ($sortfield && $sortorder)
6635
+            {
6636
+                $filearray=dol_sort_array($filearray, $sortfield, $sortorder);
6637
+            }
6638
+
6639
+            foreach($filearray as $key => $val)
6640
+            {
6641
+                $photo='';
6642
+                $file = $val['name'];
6643
+
6644
+                //if (! utf8_check($file)) $file=utf8_encode($file);	// To be sure file is stored in UTF8 in memory
6645
+
6646
+                //if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
6647
+                if (image_format_supported($file) >= 0)
6648
+                {
6649
+                    $nbphoto++;
6650
+                    $photo = $file;
6651
+                    $viewfilename = $file;
6652
+
6653
+                    if ($size == 1 || $size == 'small') {   // Format vignette
6654
+
6655
+                        // Find name of thumb file
6656
+                        $photo_vignette=basename(getImageFileNameForSize($dir.$file, '_small'));
6657
+                        if (! dol_is_file($dirthumb.$photo_vignette)) $photo_vignette='';
6658
+
6659
+                        // Get filesize of original file
6660
+                        $imgarray=dol_getImageSize($dir.$photo);
6661
+
6662
+                        if ($nbbyrow > 0)
6663
+                        {
6664
+                            if ($nbphoto == 1) $return.= '<table width="100%" valign="top" align="center" border="0" cellpadding="2" cellspacing="2">';
6665
+
6666
+                            if ($nbphoto % $nbbyrow == 1) $return.= '<tr align=center valign=middle border=1>';
6667
+                            $return.= '<td width="'.ceil(100/$nbbyrow).'%" class="photo">';
6668
+                        }
6669
+                        else if ($nbbyrow < 0) $return .= '<div class="inline-block">';
6670
+
6671
+                        $return.= "\n";
6672
+
6673
+                        $relativefile=preg_replace('/^\//', '', $pdir.$photo);
6674
+                        if (empty($nolink))
6675
+                        {
6676
+                            $urladvanced=getAdvancedPreviewUrl($modulepart, $relativefile, 0, 'entity='.$this->entity);
6677
+                            if ($urladvanced) $return.='<a href="'.$urladvanced.'">';
6678
+                            else $return.= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" class="aphoto" target="_blank">';
6679
+                        }
6680
+
6681
+                        // Show image (width height=$maxHeight)
6682
+                        // Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
6683
+                        $alt=$langs->transnoentitiesnoconv('File').': '.$relativefile;
6684
+                        $alt.=' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height'];
6685
+                        if ($notitle) $alt='';
6686
+
6687
+                        if ($usesharelink)
6688
+                        {
6689
+                            if ($val['share'])
6690
+                            {
6691
+                                if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6692
+                                {
6693
+                                    $return.= '<!-- Show original file (thumb not yet available with shared links) -->';
6694
+                                    $return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6695
+                                }
6696
+                                else {
6697
+                                    $return.= '<!-- Show original file -->';
6698
+                                    $return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6699
+                                }
6700
+                            }
6701
+                            else
6702
+                            {
6703
+                                $return.= '<!-- Show nophoto file (because file is not shared) -->';
6704
+                                $return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/public/theme/common/nophoto.png" title="'.dol_escape_htmltag($alt).'">';
6705
+                            }
6706
+                        }
6707
+                        else
6708
+                        {
6709
+                            if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6710
+                            {
6711
+                                $return.= '<!-- Show thumb -->';
6712
+                                $return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdirthumb.$photo_vignette).'" title="'.dol_escape_htmltag($alt).'">';
6713
+                            }
6714
+                            else {
6715
+                                $return.= '<!-- Show original file -->';
6716
+                                $return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" title="'.dol_escape_htmltag($alt).'">';
6717
+                            }
6718
+                        }
6719
+
6720
+                        if (empty($nolink)) $return.= '</a>';
6721
+                        $return.="\n";
6722
+
6723
+                        if ($showfilename) $return.= '<br>'.$viewfilename;
6724
+                        if ($showaction)
6725
+                        {
6726
+                            $return.= '<br>';
6727
+                            // On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites
6728
+                            if ($photo_vignette && (image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight))
6729
+                            {
6730
+                                $return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=addthumb&amp;file='.urlencode($pdir.$viewfilename).'">'.img_picto($langs->trans('GenerateThumb'),'refresh').'&nbsp;&nbsp;</a>';
6731
+                            }
6732
+                            // Special cas for product
6733
+                            if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6734
+                            {
6735
+                                // Link to resize
6736
+                                $return.= '<a href="'.DOL_URL_ROOT.'/core/photos_resize.php?modulepart='.urlencode('produit|service').'&id='.$this->id.'&amp;file='.urlencode($pdir.$viewfilename).'" title="'.dol_escape_htmltag($langs->trans("Resize")).'">'.img_picto($langs->trans("Resize"), 'resize', '').'</a> &nbsp; ';
6737
+
6738
+                                // Link to delete
6739
+                                $return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6740
+                                $return.= img_delete().'</a>';
6741
+                            }
6742
+                        }
6743
+                        $return.= "\n";
6744
+
6745
+                        if ($nbbyrow > 0)
6746
+                        {
6747
+                            $return.= '</td>';
6748
+                            if (($nbphoto % $nbbyrow) == 0) $return.= '</tr>';
6749
+                        }
6750
+                        else if ($nbbyrow < 0) $return.='</div>';
6751
+                    }
6752
+
6753
+                    if (empty($size)) {     // Format origine
6754
+                        $return.= '<img class="photo photowithmargin" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'">';
6755
+
6756
+                        if ($showfilename) $return.= '<br>'.$viewfilename;
6757
+                        if ($showaction)
6758
+                        {
6759
+                            // Special case for product
6760
+                            if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6761
+                            {
6762
+                                // Link to resize
6763
+                                $return.= '<a href="'.DOL_URL_ROOT.'/core/photos_resize.php?modulepart='.urlencode('produit|service').'&id='.$this->id.'&amp;file='.urlencode($pdir.$viewfilename).'" title="'.dol_escape_htmltag($langs->trans("Resize")).'">'.img_picto($langs->trans("Resize"), 'resize', '').'</a> &nbsp; ';
6764
+
6765
+                                // Link to delete
6766
+                                $return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6767
+                                $return.= img_delete().'</a>';
6768
+                            }
6769
+                        }
6770
+                    }
6771
+
6772
+                    // On continue ou on arrete de boucler ?
6773
+                    if ($nbmax && $nbphoto >= $nbmax) break;
6774
+                }
6775
+            }
6776
+
6777
+            if ($size==1 || $size=='small')
6778
+            {
6779
+                if ($nbbyrow > 0)
6780
+                {
6781
+                    // Ferme tableau
6782
+                    while ($nbphoto % $nbbyrow)
6783
+                    {
6784
+                        $return.= '<td width="'.ceil(100/$nbbyrow).'%">&nbsp;</td>';
6785
+                        $nbphoto++;
6786
+                    }
6787
+
6788
+                    if ($nbphoto) $return.= '</table>';
6789
+                }
6790
+            }
6791
+        }
6792
+
6793
+        $this->nbphoto = $nbphoto;
6794
+
6795
+        return $return;
6796
+    }
6797
+
6798
+
6799
+    /**
6800
+     * Function test if type is array
6801
+     *
6802
+     * @param   array   $info   content informations of field
6803
+     * @return                  bool
6804
+     */
6805
+    protected function isArray($info)
6806
+    {
6807
+        if(is_array($info))
6808
+        {
6809
+            if(isset($info['type']) && $info['type']=='array') return true;
6810
+            else return false;
6811
+        }
6812
+        else return false;
6813
+    }
6814
+
6815
+    /**
6816
+     * Function test if type is null
6817
+     *
6818
+     * @param   array   $info   content informations of field
6819
+     * @return                  bool
6820
+     */
6821
+    protected function isNull($info)
6822
+    {
6823
+        if(is_array($info))
6824
+        {
6825
+            if(isset($info['type']) && $info['type']=='null') return true;
6826
+            else return false;
6827
+        }
6828
+        else return false;
6829
+    }
6830
+
6831
+    /**
6832
+     * Function test if type is date
6833
+     *
6834
+     * @param   array   $info   content informations of field
6835
+     * @return                  bool
6836
+     */
6837
+    public function isDate($info)
6838
+    {
6839
+        if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true;
6840
+        else return false;
6841
+    }
6842
+
6843
+    /**
6844
+     * Function test if type is integer
6845
+     *
6846
+     * @param   array   $info   content informations of field
6847
+     * @return                  bool
6848
+     */
6849
+    public function isInt($info)
6850
+    {
6851
+        if(is_array($info))
6852
+        {
6853
+            if(isset($info['type']) && ($info['type']=='int' || preg_match('/^integer/i',$info['type']) ) ) return true;
6854
+            else return false;
6855
+        }
6856
+        else return false;
6857
+    }
6858
+
6859
+    /**
6860
+     * Function test if type is float
6861
+     *
6862
+     * @param   array   $info   content informations of field
6863
+     * @return                  bool
6864
+     */
6865
+    public function isFloat($info)
6866
+    {
6867
+        if(is_array($info))
6868
+        {
6869
+            if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true;
6870
+            else return false;
6871
+        }
6872
+        else return false;
6873
+    }
6874
+
6875
+    /**
6876
+     * Function test if type is text
6877
+     *
6878
+     * @param   array   $info   content informations of field
6879
+     * @return                  bool
6880
+     */
6881
+    public function isText($info)
6882
+    {
6883
+        if(is_array($info))
6884
+        {
6885
+            if(isset($info['type']) && $info['type']=='text') return true;
6886
+            else return false;
6887
+        }
6888
+        else return false;
6889
+    }
6890
+
6891
+    /**
6892
+     * Function test if is indexed
6893
+     *
6894
+     * @param   array   $info   content informations of field
6895
+     * @return                  bool
6896
+     */
6897
+    protected function isIndex($info)
6898
+    {
6899
+        if(is_array($info))
6900
+        {
6901
+            if(isset($info['index']) && $info['index']==true) return true;
6902
+            else return false;
6903
+        }
6904
+        else return false;
6905
+    }
6906
+
6907
+    /**
6908
+     * Function to prepare the values to insert.
6909
+     * Note $this->${field} are set by the page that make the createCommon or the updateCommon.
6910
+     *
6911
+     * @return array
6912
+     */
6913
+    protected function setSaveQuery()
6914
+    {
6915
+        global $conf;
6916
+
6917
+        $queryarray=array();
6918
+        foreach ($this->fields as $field=>$info)	// Loop on definition of fields
6919
+        {
6920
+            // Depending on field type ('datetime', ...)
6921
+            if($this->isDate($info))
6922
+            {
6923
+                if(empty($this->{$field}))
6924
+                {
6925
+                    $queryarray[$field] = null;
6926
+                }
6927
+                else
6928
+                {
6929
+                    $queryarray[$field] = $this->db->idate($this->{$field});
6930
+                }
6931
+            }
6932
+            else if($this->isArray($info))
6933
+            {
6934
+                if(! empty($this->{$field})) {
6935
+                    if(! is_array($this->{$field})) {
6936
+                        $this->{$field} = array($this->{$field});
6937
+                    }
6938
+                    $queryarray[$field] = serialize($this->{$field});
6939
+                } else {
6940
+                    $queryarray[$field] = null;
6941
+                }
6942
+            }
6943
+            else if($this->isInt($info))
6944
+            {
6945
+                if ($field == 'entity' && is_null($this->{$field})) $queryarray[$field]=$conf->entity;
6946
+                else
6947
+                {
6948
+                    $queryarray[$field] = (int) price2num($this->{$field});
6949
+                    if (empty($queryarray[$field])) $queryarray[$field]=0;		// May be reset to null later if property 'notnull' is -1 for this field.
6950
+                }
6951
+            }
6952
+            else if($this->isFloat($info))
6953
+            {
6954
+                $queryarray[$field] = (double) price2num($this->{$field});
6955
+                if (empty($queryarray[$field])) $queryarray[$field]=0;
6956
+            }
6957
+            else
6958
+            {
6959
+                $queryarray[$field] = $this->{$field};
6960
+            }
6961
+
6962
+            if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]);
6963
+            if (! empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) $queryarray[$field] = null;
6964
+        }
6965
+
6966
+        return $queryarray;
6967
+    }
6968
+
6969
+    /**
6970
+     * Function to load data from a SQL pointer into properties of current object $this
6971
+     *
6972
+     * @param   stdClass    $obj    Contain data of object from database
6973
+     * @return void
6974
+     */
6975
+    protected function setVarsFromFetchObj(&$obj)
6976
+    {
6977
+        foreach ($this->fields as $field => $info)
6978
+        {
6979
+            if($this->isDate($info))
6980
+            {
6981
+                if(empty($obj->{$field}) || $obj->{$field} === '0000-00-00 00:00:00' || $obj->{$field} === '1000-01-01 00:00:00') $this->{$field} = 0;
6982
+                else $this->{$field} = strtotime($obj->{$field});
6983
+            }
6984
+            elseif($this->isArray($info))
6985
+            {
6986
+                if(! empty($obj->{$field})) {
6987
+                    $this->{$field} = @unserialize($obj->{$field});
6988
+                    // Hack for data not in UTF8
6989
+                    if($this->{$field } === false) @unserialize(utf8_decode($obj->{$field}));
6990
+                } else {
6991
+                    $this->{$field} = array();
6992
+                }
6993
+            }
6994
+            elseif($this->isInt($info))
6995
+            {
6996
+                if ($field == 'rowid') $this->id = (int) $obj->{$field};
6997
+                else $this->{$field} = (int) $obj->{$field};
6998
+            }
6999
+            elseif($this->isFloat($info))
7000
+            {
7001
+                $this->{$field} = (double) $obj->{$field};
7002
+            }
7003
+            elseif($this->isNull($info))
7004
+            {
7005
+                $val = $obj->{$field};
7006
+                // zero is not null
7007
+                $this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val);
7008
+            }
7009
+            else
7010
+            {
7011
+                $this->{$field} = $obj->{$field};
7012
+            }
7013
+        }
7014
+
7015
+        // If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
7016
+        if (! isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id;
7017
+    }
7018
+
7019
+    /**
7020
+     * Function to concat keys of fields
7021
+     *
7022
+     * @return string
7023
+     */
7024
+    protected function getFieldList()
7025
+    {
7026
+        $keys = array_keys($this->fields);
7027
+        return implode(',', $keys);
7028
+    }
7029
+
7030
+    /**
7031
+     * Add quote to field value if necessary
7032
+     *
7033
+     * @param 	string|int	$value			Value to protect
7034
+     * @param	array		$fieldsentry	Properties of field
7035
+     * @return 	string
7036
+     */
7037
+    protected function quote($value, $fieldsentry)
7038
+    {
7039
+        if (is_null($value)) return 'NULL';
7040
+        else if (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value");
7041
+        else return "'".$this->db->escape($value)."'";
7042
+    }
7043
+
7044
+
7045
+    /**
7046
+     * Create object into database
7047
+     *
7048
+     * @param  User $user      User that creates
7049
+     * @param  bool $notrigger false=launch triggers after, true=disable triggers
7050
+     * @return int             <0 if KO, Id of created object if OK
7051
+     */
7052
+    public function createCommon(User $user, $notrigger = false)
7053
+    {
7054
+        global $langs;
6070 7055
 
6071
-				$obj = $this->db->fetch_object($resql);
7056
+        $error = 0;
6072 7057
 
6073
-				// Several field into label (eq table:code|libelle:rowid)
6074
-				$fields_label = explode('|',$InfoFieldList[1]);
7058
+        $now=dol_now();
6075 7059
 
6076
-				if(is_array($fields_label) && count($fields_label)>1)
6077
-				{
6078
-					foreach ($fields_label as $field_toshow)
6079
-					{
6080
-						$translabel='';
6081
-						if (!empty($obj->$field_toshow)) {
6082
-							$translabel=$langs->trans($obj->$field_toshow);
6083
-						}
6084
-						if ($translabel!=$field_toshow) {
6085
-							$value.=dol_trunc($translabel,18).' ';
6086
-						}else {
6087
-							$value.=$obj->$field_toshow.' ';
6088
-						}
6089
-					}
6090
-				}
6091
-				else
6092
-				{
6093
-					$translabel='';
6094
-					if (!empty($obj->{$InfoFieldList[1]})) {
6095
-						$translabel=$langs->trans($obj->{$InfoFieldList[1]});
6096
-					}
6097
-					if ($translabel!=$obj->{$InfoFieldList[1]}) {
6098
-						$value=dol_trunc($translabel,18);
6099
-					}else {
6100
-						$value=$obj->{$InfoFieldList[1]};
6101
-					}
6102
-				}
6103
-			}
6104
-			else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
6105
-		}
6106
-		elseif ($type == 'radio')
6107
-		{
6108
-			$value=$param['options'][$value];
6109
-		}
6110
-		elseif ($type == 'checkbox')
6111
-		{
6112
-			$value_arr=explode(',',$value);
6113
-			$value='';
6114
-			if (is_array($value_arr) && count($value_arr)>0)
6115
-			{
6116
-				foreach ($value_arr as $keyval=>$valueval) {
6117
-					$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$param['options'][$valueval].'</li>';
6118
-				}
6119
-				$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6120
-			}
6121
-		}
6122
-		elseif ($type == 'chkbxlst')
6123
-		{
6124
-			$value_arr = explode(',', $value);
6125
-
6126
-			$param_list = array_keys($param['options']);
6127
-			$InfoFieldList = explode(":", $param_list[0]);
6128
-
6129
-			$selectkey = "rowid";
6130
-			$keyList = 'rowid';
6131
-
6132
-			if (count($InfoFieldList) >= 3) {
6133
-				$selectkey = $InfoFieldList[2];
6134
-				$keyList = $InfoFieldList[2] . ' as rowid';
6135
-			}
6136
-
6137
-			$fields_label = explode('|', $InfoFieldList[1]);
6138
-			if (is_array($fields_label)) {
6139
-				$keyList .= ', ';
6140
-				$keyList .= implode(', ', $fields_label);
6141
-			}
6142
-
6143
-			$sql = 'SELECT ' . $keyList;
6144
-			$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
6145
-			if (strpos($InfoFieldList[4], 'extra') !== false) {
6146
-				$sql .= ' as main';
6147
-			}
6148
-			// $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6149
-			// $sql.= ' AND entity = '.$conf->entity;
6150
-
6151
-			dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
6152
-			$resql = $this->db->query($sql);
6153
-			if ($resql) {
6154
-				$value = ''; // value was used, so now we reste it to use it to build final output
6155
-				$toprint=array();
6156
-				while ( $obj = $this->db->fetch_object($resql) ) {
6157
-
6158
-					// Several field into label (eq table:code|libelle:rowid)
6159
-					$fields_label = explode('|', $InfoFieldList[1]);
6160
-					if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
6161
-						if (is_array($fields_label) && count($fields_label) > 1) {
6162
-							foreach ( $fields_label as $field_toshow ) {
6163
-								$translabel = '';
6164
-								if (! empty($obj->$field_toshow)) {
6165
-									$translabel = $langs->trans($obj->$field_toshow);
6166
-								}
6167
-								if ($translabel != $field_toshow) {
6168
-									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6169
-								} else {
6170
-									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
6171
-								}
6172
-							}
6173
-						} else {
6174
-							$translabel = '';
6175
-							if (! empty($obj->{$InfoFieldList[1]})) {
6176
-								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
6177
-							}
6178
-							if ($translabel != $obj->{$InfoFieldList[1]}) {
6179
-								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6180
-							} else {
6181
-								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
6182
-							}
6183
-						}
6184
-					}
6185
-				}
6186
-				$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6187
-			} else {
6188
-				dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
6189
-			}
6190
-		}
6191
-		elseif ($type == 'link')
6192
-		{
6193
-			$out='';
6194
-
6195
-			// only if something to display (perf)
6196
-			if ($value)
6197
-			{
6198
-				$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
7060
+        $fieldvalues = $this->setSaveQuery();
7061
+        if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now);
7062
+        if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id;
7063
+        unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
6199 7064
 
6200
-				$InfoFieldList = explode(":", $param_list[0]);
6201
-				$classname=$InfoFieldList[0];
6202
-				$classpath=$InfoFieldList[1];
6203
-				$getnomurlparam=(empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
6204
-				if (! empty($classpath))
6205
-				{
6206
-					dol_include_once($InfoFieldList[1]);
6207
-					if ($classname && class_exists($classname))
6208
-					{
6209
-						$object = new $classname($this->db);
6210
-						$object->fetch($value);
6211
-						$value=$object->getNomUrl($getnomurlparam);
6212
-					}
6213
-				}
6214
-				else
6215
-				{
6216
-					dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6217
-					return 'Error bad setup of extrafield';
6218
-				}
6219
-			}
6220
-			else $value='';
6221
-		}
6222
-		elseif ($type == 'text' || $type == 'html')
6223
-		{
6224
-			$value=dol_htmlentitiesbr($value);
6225
-		}
6226
-		elseif ($type == 'password')
6227
-		{
6228
-			$value=preg_replace('/./i','*',$value);
6229
-		}
6230
-		elseif ($type == 'array')
6231
-		{
6232
-			$value = implode('<br>', $value);
6233
-		}
6234
-
6235
-		//print $type.'-'.$size;
6236
-		$out=$value;
6237
-
6238
-		return $out;
6239
-	}
6240
-
6241
-
6242
-	/**
6243
-	 * Function to show lines of extrafields with output datas
6244
-	 *
6245
-	 * @param 	Extrafields $extrafields    Extrafield Object
6246
-	 * @param 	string      $mode           Show output (view) or input (edit) for extrafield
6247
-	 * @param 	array       $params         Optional parameters. Example: array('style'=>'class="oddeven"', 'colspan'=>$colspan)
6248
-	 * @param 	string      $keysuffix      Suffix string to add after name and id of field (can be used to avoid duplicate names)
6249
-	 * @param 	string      $keyprefix      Prefix string to add before name and id of field (can be used to avoid duplicate names)
6250
-	 * @param	string		$onetrtd		All fields in same tr td
6251
-	 * @return 	string
6252
-	 */
6253
-	function showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='', $onetrtd=0)
6254
-	{
6255
-		global $db, $conf, $langs, $action, $form;
6256
-
6257
-		if (! is_object($form)) $form=new Form($db);
6258
-
6259
-		$out = '';
6260
-
6261
-		if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label']) > 0)
6262
-		{
6263
-			$out .= "\n";
6264
-			$out .= '<!-- showOptionalsInput --> ';
6265
-			$out .= "\n";
6266
-
6267
-			$e = 0;
6268
-			foreach($extrafields->attributes[$this->table_element]['label'] as $key=>$label)
6269
-			{
6270
-				// Show only the key field in params
6271
-				if (is_array($params) && array_key_exists('onlykey',$params) && $key != $params['onlykey']) continue;
7065
+        $keys=array();
7066
+        $values = array();
7067
+        foreach ($fieldvalues as $k => $v) {
7068
+            $keys[$k] = $k;
7069
+            $value = $this->fields[$k];
7070
+            $values[$k] = $this->quote($v, $value);
7071
+        }
6272 7072
 
6273
-				$enabled = 1;
6274
-				if ($enabled && isset($extrafields->attributes[$this->table_element]['list'][$key]))
6275
-				{
6276
-					$enabled = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1);
6277
-				}
7073
+        // Clean and check mandatory
7074
+        foreach($keys as $key)
7075
+        {
7076
+            // If field is an implicit foreign key field
7077
+            if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';
7078
+            if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';
6278 7079
 
6279
-				$perms = 1;
6280
-				if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key]))
6281
-				{
6282
-					$perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1);
6283
-				}
7080
+            //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7081
+            if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && ! isset($values[$key]) && is_null($val['default']))
7082
+            {
7083
+                $error++;
7084
+                $this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7085
+            }
6284 7086
 
6285
-				if (($mode == 'create' || $mode == 'edit') && abs($enabled) != 1 && abs($enabled) != 3) continue;	// <> -1 and <> 1 and <> 3 = not visible on forms, only on list
6286
-				if (empty($perms)) continue;
7087
+            // If field is an implicit foreign key field
7088
+            if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key]='null';
7089
+            if (! empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key]='null';
7090
+        }
6287 7091
 
6288
-				// Load language if required
6289
-				if (! empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
7092
+        if ($error) return -1;
6290 7093
 
6291
-				$colspan='3';
6292
-				if (is_array($params) && count($params)>0) {
6293
-					if (array_key_exists('colspan',$params)) {
6294
-						$colspan=$params['colspan'];
6295
-					}
6296
-				}
7094
+        $this->db->begin();
6297 7095
 
6298
-				switch($mode) {
6299
-					case "view":
6300
-						$value=$this->array_options["options_".$key.$keysuffix];
6301
-						break;
6302
-					case "edit":
6303
-						$getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, 'none');				// GETPOST can get value from GET, POST or setup of default values.
6304
-						// GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
6305
-						if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix))
6306
-						{
6307
-							if (is_array($getposttemp)) {
6308
-								// $getposttemp is an array but following code expects a comma separated string
6309
-								$value = implode(",", $getposttemp);
6310
-							} else {
6311
-								$value = $getposttemp;
6312
-							}
6313
-						} else {
6314
-							$value = $this->array_options["options_" . $key];			// No GET, no POST, no default value, so we take value of object.
6315
-						}
6316
-						//var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
6317
-						break;
6318
-				}
7096
+        if (! $error)
7097
+        {
7098
+            $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
7099
+            $sql.= ' ('.implode( ", ", $keys ).')';
7100
+            $sql.= ' VALUES ('.implode( ", ", $values ).')';
7101
+
7102
+            $res = $this->db->query($sql);
7103
+            if ($res===false) {
7104
+                $error++;
7105
+                $this->errors[] = $this->db->lasterror();
7106
+            }
7107
+        }
6319 7108
 
6320
-				if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate')
6321
-				{
6322
-					$out .= $extrafields->showSeparator($key, $this);
6323
-				}
6324
-				else
6325
-				{
6326
-					$csstyle='';
6327
-					$class=(!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
6328
-					if (is_array($params) && count($params)>0) {
6329
-						if (array_key_exists('style',$params)) {
6330
-							$csstyle=$params['style'];
6331
-						}
6332
-					}
7109
+        if (! $error)
7110
+        {
7111
+            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
7112
+        }
6333 7113
 
6334
-					// add html5 elements
6335
-					$domData  = ' data-element="extrafield"';
6336
-					$domData .= ' data-targetelement="'.$this->element.'"';
6337
-					$domData .= ' data-targetid="'.$this->id.'"';
7114
+        // Create extrafields
7115
+        if (! $error)
7116
+        {
7117
+            $result=$this->insertExtraFields();
7118
+            if ($result < 0) $error++;
7119
+        }
6338 7120
 
6339
-					$html_id = !empty($this->id) ? 'extrarow-'.$this->element.'_'.$key.'_'.$this->id : '';
7121
+        // Triggers
7122
+        if (! $error && ! $notrigger)
7123
+        {
7124
+            // Call triggers
7125
+            $result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE',$user);
7126
+            if ($result < 0) { $error++; }
7127
+            // End call triggers
7128
+        }
6340 7129
 
6341
-					$out .= '<tr id="'.$html_id.'" '.$csstyle.' class="'.$class.$this->element.'_extras_'.$key.'" '.$domData.' >';
7130
+        // Commit or rollback
7131
+        if ($error) {
7132
+            $this->db->rollback();
7133
+            return -1;
7134
+        } else {
7135
+            $this->db->commit();
7136
+            return $this->id;
7137
+        }
7138
+    }
6342 7139
 
6343
-					if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0)
6344
-					{
6345
-						if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) { $colspan='0'; }
6346
-					}
6347 7140
 
6348
-					if ($action == 'selectlines') { $colspan++; }
7141
+    /**
7142
+     * Load object in memory from the database
7143
+     *
7144
+     * @param	int    $id				Id object
7145
+     * @param	string $ref				Ref
7146
+     * @param	string	$morewhere		More SQL filters (' AND ...')
7147
+     * @return 	int         			<0 if KO, 0 if not found, >0 if OK
7148
+     */
7149
+    public function fetchCommon($id, $ref = null, $morewhere = '')
7150
+    {
7151
+        if (empty($id) && empty($ref) && empty($morewhere)) return -1;
6349 7152
 
6350
-					// Convert date into timestamp format (value in memory must be a timestamp)
6351
-					if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('date','datetime')))
6352
-					{
6353
-						$datenotinstring = $this->array_options['options_' . $key];
6354
-						if (! is_numeric($this->array_options['options_' . $key]))	// For backward compatibility
6355
-						{
6356
-							$datenotinstring = $this->db->jdate($datenotinstring);
6357
-						}
6358
-						$value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?dol_mktime(GETPOST($keyprefix.'options_'.$key.$keysuffix."hour", 'int', 3), GETPOST($keyprefix.'options_'.$key.$keysuffix."min",'int',3), 0, GETPOST($keyprefix.'options_'.$key.$keysuffix."month",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."day",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."year",'int',3)):$datenotinstring;
6359
-					}
6360
-					// Convert float submited string into real php numeric (value in memory must be a php numeric)
6361
-					if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('price','double')))
6362
-					{
6363
-						$value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?price2num(GETPOST($keyprefix.'options_'.$key.$keysuffix, 'alpha', 3)):$this->array_options['options_'.$key];
6364
-					}
6365
-
6366
-					$labeltoshow = $langs->trans($label);
6367
-
6368
-					$out .= '<td class="titlefield';
6369
-					if (GETPOST('action','none') == 'create') $out.='create';
6370
-					if ($mode != 'view' && ! empty($extrafields->attributes[$this->table_element]['required'][$key])) $out .= ' fieldrequired';
6371
-					$out .= '">';
6372
-					if (! empty($extrafields->attributes[$object->table_element]['help'][$key])) $out .= $form->textwithpicto($labeltoshow, $extrafields->attributes[$object->table_element]['help'][$key]);
6373
-					else $out .= $labeltoshow;
6374
-					$out .= '</td>';
6375
-
6376
-					$html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : '';
6377
-					$out .='<td id="'.$html_id.'" class="'.$this->element.'_extras_'.$key.'" '.($colspan?' colspan="'.$colspan.'"':'').'>';
6378
-
6379
-					switch($mode) {
6380
-						case "view":
6381
-							$out .= $extrafields->showOutputField($key, $value);
6382
-							break;
6383
-						case "edit":
6384
-							$out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id);
6385
-							break;
6386
-					}
6387
-
6388
-					$out .= '</td>';
6389
-
6390
-					if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) $out .= '</tr>';
6391
-					else $out .= '</tr>';
6392
-					$e++;
6393
-				}
6394
-			}
6395
-			$out .= "\n";
6396
-			// Add code to manage list depending on others
6397
-			if (! empty($conf->use_javascript_ajax)) {
6398
-				$out .= '
6399
-				<script type="text/javascript">
6400
-				    jQuery(document).ready(function() {
6401
-				    	function showOptions(child_list, parent_list)
6402
-				    	{
6403
-				    		var val = $("select[name=\"options_"+parent_list+"\"]").val();
6404
-				    		var parentVal = parent_list + ":" + val;
6405
-							if(val > 0) {
6406
-					    		$("select[name=\""+child_list+"\"] option[parent]").hide();
6407
-					    		$("select[name=\""+child_list+"\"] option[parent=\""+parentVal+"\"]").show();
6408
-							} else {
6409
-								$("select[name=\""+child_list+"\"] option").show();
6410
-							}
6411
-				    	}
6412
-						function setListDependencies() {
6413
-					    	jQuery("select option[parent]").parent().each(function() {
6414
-					    		var child_list = $(this).attr("name");
6415
-								var parent = $(this).find("option[parent]:first").attr("parent");
6416
-								var infos = parent.split(":");
6417
-								var parent_list = infos[0];
6418
-								$("select[name=\""+parent_list+"\"]").change(function() {
6419
-									showOptions(child_list, parent_list);
6420
-								});
6421
-					    	});
6422
-						}
7153
+        $sql = 'SELECT '.$this->getFieldList();
7154
+        $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
6423 7155
 
6424
-						setListDependencies();
6425
-				    });
6426
-				</script>'."\n";
6427
-				$out .= '<!-- /showOptionalsInput --> '."\n";
6428
-			}
6429
-		}
6430
-		return $out;
6431
-	}
6432
-
6433
-
6434
-	/**
6435
-	 * Returns the rights used for this class
6436
-	 * @return stdClass
6437
-	 */
6438
-	public function getRights()
6439
-	{
6440
-		global $user;
6441
-
6442
-		$element = $this->element;
6443
-		if ($element == 'facturerec') $element='facture';
6444
-
6445
-		return $user->rights->{$element};
6446
-	}
6447
-
6448
-	/**
6449
-	 * Function used to replace a thirdparty id with another one.
6450
-	 * This function is meant to be called from replaceThirdparty with the appropiate tables
6451
-	 * Column name fk_soc MUST be used to identify thirdparties
6452
-	 *
6453
-	 * @param  DoliDB 	   $db 			  Database handler
6454
-	 * @param  int 		   $origin_id     Old thirdparty id (the thirdparty to delete)
6455
-	 * @param  int 		   $dest_id       New thirdparty id (the thirdparty that will received element of the other)
6456
-	 * @param  string[]    $tables        Tables that need to be changed
6457
-	 * @param  int         $ignoreerrors  Ignore errors. Return true even if errors. We need this when replacement can fails like for categories (categorie of old thirdparty may already exists on new one)
6458
-	 * @return bool						  True if success, False if error
6459
-	 */
6460
-	public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
6461
-	{
6462
-		foreach ($tables as $table)
6463
-		{
6464
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_soc = '.$dest_id.' WHERE fk_soc = '.$origin_id;
6465
-
6466
-			if (! $db->query($sql))
6467
-			{
6468
-				if ($ignoreerrors) return true;		// TODO Not enough. If there is A-B on kept thirdarty and B-C on old one, we must get A-B-C after merge. Not A-B.
6469
-				//$this->errors = $db->lasterror();
6470
-				return false;
6471
-			}
6472
-		}
6473
-
6474
-		return true;
6475
-	}
6476
-
6477
-	/**
6478
-	 * Get buy price to use for margin calculation. This function is called when buy price is unknown.
6479
-	 *	 Set buy price = sell price if ForceBuyingPriceIfNull configured,
6480
-	 *   else if calculation MARGIN_TYPE = 'costprice' and costprice is defined, use costprice as buyprice
6481
-	 *	 else if calculation MARGIN_TYPE = 'pmp' and pmp is calculated, use pmp as buyprice
6482
-	 *	 else set min buy price as buy price
6483
-	 *
6484
-	 * @param float		$unitPrice		 Product unit price
6485
-	 * @param float		$discountPercent Line discount percent
6486
-	 * @param int		$fk_product		 Product id
6487
-	 * @return	float                    <0 if KO, buyprice if OK
6488
-	 */
6489
-	public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
6490
-	{
6491
-		global $conf;
6492
-
6493
-		$buyPrice = 0;
6494
-
6495
-		if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) // In most cases, test here is false
6496
-		{
6497
-			$buyPrice = $unitPrice * (1 - $discountPercent / 100);
6498
-		}
6499
-		else
6500
-		{
6501
-			// Get cost price for margin calculation
6502
-			if (! empty($fk_product))
6503
-			{
6504
-				if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice')
6505
-				{
6506
-					require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6507
-					$product = new Product($this->db);
6508
-					$result = $product->fetch($fk_product);
6509
-					if ($result <= 0)
6510
-					{
6511
-						$this->errors[] = 'ErrorProductIdDoesNotExists';
6512
-						return -1;
6513
-					}
6514
-					if ($product->cost_price > 0)
6515
-					{
6516
-						$buyPrice = $product->cost_price;
6517
-					}
6518
-					else if ($product->pmp > 0)
6519
-					{
6520
-						$buyPrice = $product->pmp;
6521
-					}
6522
-				}
6523
-				else if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp')
6524
-				{
6525
-					require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6526
-					$product = new Product($this->db);
6527
-					$result = $product->fetch($fk_product);
6528
-					if ($result <= 0)
6529
-					{
6530
-						$this->errors[] = 'ErrorProductIdDoesNotExists';
6531
-						return -1;
6532
-					}
6533
-					if ($product->pmp > 0)
6534
-					{
6535
-						$buyPrice = $product->pmp;
6536
-					}
6537
-				}
7156
+        if (!empty($id))  $sql.= ' WHERE rowid = '.$id;
7157
+        elseif (!empty($ref)) $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']);
7158
+        else $sql.=' WHERE 1 = 1';	// usage with empty id and empty ref is very rare
7159
+        if ($morewhere)   $sql.= $morewhere;
7160
+        $sql.=' LIMIT 1';	// This is a fetch, to be sure to get only one record
6538 7161
 
6539
-				if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1','pmp','costprice')))
6540
-				{
6541
-					require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6542
-					$productFournisseur = new ProductFournisseur($this->db);
6543
-					if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0)
6544
-					{
6545
-						$buyPrice = $productFournisseur->fourn_unitprice;
6546
-					}
6547
-					else if ($result < 0)
6548
-					{
6549
-						$this->errors[] = $productFournisseur->error;
6550
-						return -2;
6551
-					}
6552
-				}
6553
-			}
6554
-		}
6555
-		return $buyPrice;
6556
-	}
7162
+        $res = $this->db->query($sql);
7163
+        if ($res)
7164
+        {
7165
+            $obj = $this->db->fetch_object($res);
7166
+            if ($obj)
7167
+            {
7168
+                $this->setVarsFromFetchObj($obj);
7169
+                return $this->id;
7170
+            }
7171
+            else
7172
+            {
7173
+                return 0;
7174
+            }
7175
+        }
7176
+        else
7177
+        {
7178
+            $this->error = $this->db->lasterror();
7179
+            $this->errors[] = $this->error;
7180
+            return -1;
7181
+        }
7182
+    }
6557 7183
 
6558
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
6559
-	/**
6560
-	 *  Show photos of an object (nbmax maximum), into several columns
6561
-	 *
6562
-	 *  @param		string	$modulepart		'product', 'ticket', ...
6563
-	 *  @param      string	$sdir        	Directory to scan (full absolute path)
6564
-	 *  @param      int		$size        	0=original size, 1='small' use thumbnail if possible
6565
-	 *  @param      int		$nbmax       	Nombre maximum de photos (0=pas de max)
6566
-	 *  @param      int		$nbbyrow     	Number of image per line or -1 to use div. Used only if size=1.
6567
-	 * 	@param		int		$showfilename	1=Show filename
6568
-	 * 	@param		int		$showaction		1=Show icon with action links (resize, delete)
6569
-	 * 	@param		int		$maxHeight		Max height of original image when size='small' (so we can use original even if small requested). If 0, always use 'small' thumb image.
6570
-	 * 	@param		int		$maxWidth		Max width of original image when size='small'
6571
-	 *  @param      int     $nolink         Do not add a href link to view enlarged imaged into a new tab
6572
-	 *  @param      int     $notitle        Do not add title tag on image
6573
-	 *  @param		int		$usesharelink	Use the public shared link of image (if not available, the 'nophoto' image will be shown instead)
6574
-	 *  @return     string					Html code to show photo. Number of photos shown is saved in this->nbphoto
6575
-	 */
6576
-	function show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $notitle=0, $usesharelink=0)
6577
-	{
6578
-        // phpcs:enable
6579
-		global $conf,$user,$langs;
6580
-
6581
-		include_once DOL_DOCUMENT_ROOT .'/core/lib/files.lib.php';
6582
-		include_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';
6583
-
6584
-		$sortfield='position_name';
6585
-		$sortorder='asc';
6586
-
6587
-		$dir = $sdir . '/';
6588
-		$pdir = '/';
6589
-		if ($modulepart == 'ticket')
6590
-		{
6591
-			$dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6592
-			$pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6593
-		}
6594
-		else
6595
-		{
6596
-			$dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6597
-			$pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6598
-		}
6599
-
6600
-		// For backward compatibility
6601
-		if ($modulepart == 'product' && ! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
6602
-		{
6603
-			$dir = $sdir . '/'. get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6604
-			$pdir = '/' . get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6605
-		}
6606
-
6607
-		// Defined relative dir to DOL_DATA_ROOT
6608
-		$relativedir = '';
6609
-		if ($dir)
6610
-		{
6611
-			$relativedir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir);
6612
-			$relativedir = preg_replace('/^[\\/]/','',$relativedir);
6613
-			$relativedir = preg_replace('/[\\/]$/','',$relativedir);
6614
-		}
6615
-
6616
-		$dirthumb = $dir.'thumbs/';
6617
-		$pdirthumb = $pdir.'thumbs/';
6618
-
6619
-		$return ='<!-- Photo -->'."\n";
6620
-		$nbphoto=0;
6621
-
6622
-		$filearray=dol_dir_list($dir,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6623
-
6624
-		/*if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))    // For backward compatiblity, we scan also old dirs
6625
-		 {
6626
-		 $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6627
-		 $filearray=array_merge($filearray, $filearrayold);
6628
-		 }*/
7184
+    /**
7185
+     * Update object into database
7186
+     *
7187
+     * @param  User $user      	User that modifies
7188
+     * @param  bool $notrigger 	false=launch triggers after, true=disable triggers
7189
+     * @return int             	<0 if KO, >0 if OK
7190
+     */
7191
+    public function updateCommon(User $user, $notrigger = false)
7192
+    {
7193
+        global $conf, $langs;
6629 7194
 
6630
-		completeFileArrayWithDatabaseInfo($filearray, $relativedir);
7195
+        $error = 0;
6631 7196
 
6632
-		if (count($filearray))
6633
-		{
6634
-			if ($sortfield && $sortorder)
6635
-			{
6636
-				$filearray=dol_sort_array($filearray, $sortfield, $sortorder);
6637
-			}
7197
+        $now=dol_now();
6638 7198
 
6639
-			foreach($filearray as $key => $val)
6640
-			{
6641
-				$photo='';
6642
-				$file = $val['name'];
7199
+        $fieldvalues = $this->setSaveQuery();
7200
+        if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification']=$this->db->idate($now);
7201
+        if (array_key_exists('fk_user_modif', $fieldvalues) && ! ($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif']=$user->id;
7202
+        unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
6643 7203
 
6644
-				//if (! utf8_check($file)) $file=utf8_encode($file);	// To be sure file is stored in UTF8 in memory
7204
+        $keys=array();
7205
+        $values = array();
7206
+        foreach ($fieldvalues as $k => $v) {
7207
+            $keys[$k] = $k;
7208
+            $value = $this->fields[$k];
7209
+            $values[$k] = $this->quote($v, $value);
7210
+            $tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
7211
+        }
6645 7212
 
6646
-				//if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
6647
-				if (image_format_supported($file) >= 0)
6648
-				{
6649
-					$nbphoto++;
6650
-					$photo = $file;
6651
-					$viewfilename = $file;
7213
+        // Clean and check mandatory
7214
+        foreach($keys as $key)
7215
+        {
7216
+            if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';		// This is an implicit foreign key field
7217
+            if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';					// This is an explicit foreign key field
7218
+
7219
+            //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7220
+            /*
7221
+			if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
7222
+			{
7223
+				$error++;
7224
+				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7225
+			}*/
7226
+        }
6652 7227
 
6653
-					if ($size == 1 || $size == 'small') {   // Format vignette
7228
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ;
6654 7229
 
6655
-						// Find name of thumb file
6656
-						$photo_vignette=basename(getImageFileNameForSize($dir.$file, '_small'));
6657
-						if (! dol_is_file($dirthumb.$photo_vignette)) $photo_vignette='';
7230
+        $this->db->begin();
7231
+        if (! $error)
7232
+        {
7233
+            $res = $this->db->query($sql);
7234
+            if ($res===false)
7235
+            {
7236
+                $error++;
7237
+                $this->errors[] = $this->db->lasterror();
7238
+            }
7239
+        }
6658 7240
 
6659
-						// Get filesize of original file
6660
-						$imgarray=dol_getImageSize($dir.$photo);
7241
+        // Update extrafield
7242
+        if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0)
7243
+        {
7244
+            $result=$this->insertExtraFields();
7245
+            if ($result < 0)
7246
+            {
7247
+                $error++;
7248
+            }
7249
+        }
6661 7250
 
6662
-						if ($nbbyrow > 0)
6663
-						{
6664
-							if ($nbphoto == 1) $return.= '<table width="100%" valign="top" align="center" border="0" cellpadding="2" cellspacing="2">';
7251
+        // Triggers
7252
+        if (! $error && ! $notrigger)
7253
+        {
7254
+            // Call triggers
7255
+            $result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user);
7256
+            if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail
7257
+            // End call triggers
7258
+        }
6665 7259
 
6666
-							if ($nbphoto % $nbbyrow == 1) $return.= '<tr align=center valign=middle border=1>';
6667
-							$return.= '<td width="'.ceil(100/$nbbyrow).'%" class="photo">';
6668
-						}
6669
-						else if ($nbbyrow < 0) $return .= '<div class="inline-block">';
7260
+        // Commit or rollback
7261
+        if ($error) {
7262
+            $this->db->rollback();
7263
+            return -1;
7264
+        } else {
7265
+            $this->db->commit();
7266
+            return $this->id;
7267
+        }
7268
+    }
6670 7269
 
6671
-						$return.= "\n";
7270
+    /**
7271
+     * Delete object in database
7272
+     *
7273
+     * @param 	User 	$user       			User that deletes
7274
+     * @param 	bool 	$notrigger  			false=launch triggers after, true=disable triggers
7275
+     * @param	int		$forcechilddeletion		0=no, 1=Force deletion of children
7276
+     * @return 	int             				<=0 if KO, >0 if OK
7277
+     */
7278
+    public function deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
7279
+    {
7280
+        $error=0;
6672 7281
 
6673
-						$relativefile=preg_replace('/^\//', '', $pdir.$photo);
6674
-						if (empty($nolink))
6675
-						{
6676
-							$urladvanced=getAdvancedPreviewUrl($modulepart, $relativefile, 0, 'entity='.$this->entity);
6677
-							if ($urladvanced) $return.='<a href="'.$urladvanced.'">';
6678
-							else $return.= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" class="aphoto" target="_blank">';
6679
-						}
7282
+        $this->db->begin();
6680 7283
 
6681
-						// Show image (width height=$maxHeight)
6682
-						// Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
6683
-						$alt=$langs->transnoentitiesnoconv('File').': '.$relativefile;
6684
-						$alt.=' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height'];
6685
-						if ($notitle) $alt='';
6686
-
6687
-						if ($usesharelink)
6688
-						{
6689
-							if ($val['share'])
6690
-							{
6691
-								if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6692
-								{
6693
-									$return.= '<!-- Show original file (thumb not yet available with shared links) -->';
6694
-									$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6695
-								}
6696
-								else {
6697
-									$return.= '<!-- Show original file -->';
6698
-									$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6699
-								}
6700
-							}
6701
-							else
6702
-							{
6703
-								$return.= '<!-- Show nophoto file (because file is not shared) -->';
6704
-								$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/public/theme/common/nophoto.png" title="'.dol_escape_htmltag($alt).'">';
6705
-							}
6706
-						}
6707
-						else
6708
-						{
6709
-							if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6710
-							{
6711
-								$return.= '<!-- Show thumb -->';
6712
-								$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdirthumb.$photo_vignette).'" title="'.dol_escape_htmltag($alt).'">';
6713
-							}
6714
-							else {
6715
-								$return.= '<!-- Show original file -->';
6716
-								$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" title="'.dol_escape_htmltag($alt).'">';
6717
-							}
6718
-						}
7284
+        if ($forcechilddeletion)
7285
+        {
7286
+            foreach($this->childtables as $table)
7287
+            {
7288
+                $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
7289
+                $resql = $this->db->query($sql);
7290
+                if (! $resql)
7291
+                {
7292
+                    $this->error=$this->db->lasterror();
7293
+                    $this->errors[]=$this->error;
7294
+                    $this->db->rollback();
7295
+                    return -1;
7296
+                }
7297
+            }
7298
+        }
7299
+        elseif (! empty($this->fk_element) && ! empty($this->childtables))	// If object has childs linked with a foreign key field, we check all child tables.
7300
+        {
7301
+            $objectisused = $this->isObjectUsed($this->id);
7302
+            if (! empty($objectisused))
7303
+            {
7304
+                dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
7305
+                $this->error='ErrorRecordHasChildren';
7306
+                $this->errors[]=$this->error;
7307
+                $this->db->rollback();
7308
+                return 0;
7309
+            }
7310
+        }
6719 7311
 
6720
-						if (empty($nolink)) $return.= '</a>';
6721
-						$return.="\n";
6722
-
6723
-						if ($showfilename) $return.= '<br>'.$viewfilename;
6724
-						if ($showaction)
6725
-						{
6726
-							$return.= '<br>';
6727
-							// On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites
6728
-							if ($photo_vignette && (image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight))
6729
-							{
6730
-								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=addthumb&amp;file='.urlencode($pdir.$viewfilename).'">'.img_picto($langs->trans('GenerateThumb'),'refresh').'&nbsp;&nbsp;</a>';
6731
-							}
6732
-							// Special cas for product
6733
-							if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6734
-							{
6735
-								// Link to resize
6736
-								$return.= '<a href="'.DOL_URL_ROOT.'/core/photos_resize.php?modulepart='.urlencode('produit|service').'&id='.$this->id.'&amp;file='.urlencode($pdir.$viewfilename).'" title="'.dol_escape_htmltag($langs->trans("Resize")).'">'.img_picto($langs->trans("Resize"), 'resize', '').'</a> &nbsp; ';
6737
-
6738
-								// Link to delete
6739
-								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6740
-								$return.= img_delete().'</a>';
6741
-							}
6742
-						}
6743
-						$return.= "\n";
7312
+        if (! $error) {
7313
+            if (! $notrigger) {
7314
+                // Call triggers
7315
+                $result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
7316
+                if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
7317
+                // End call triggers
7318
+            }
7319
+        }
6744 7320
 
6745
-						if ($nbbyrow > 0)
6746
-						{
6747
-							$return.= '</td>';
6748
-							if (($nbphoto % $nbbyrow) == 0) $return.= '</tr>';
6749
-						}
6750
-						else if ($nbbyrow < 0) $return.='</div>';
6751
-					}
6752
-
6753
-					if (empty($size)) {     // Format origine
6754
-						$return.= '<img class="photo photowithmargin" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'">';
6755
-
6756
-						if ($showfilename) $return.= '<br>'.$viewfilename;
6757
-						if ($showaction)
6758
-						{
6759
-							// Special case for product
6760
-							if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6761
-							{
6762
-								// Link to resize
6763
-								$return.= '<a href="'.DOL_URL_ROOT.'/core/photos_resize.php?modulepart='.urlencode('produit|service').'&id='.$this->id.'&amp;file='.urlencode($pdir.$viewfilename).'" title="'.dol_escape_htmltag($langs->trans("Resize")).'">'.img_picto($langs->trans("Resize"), 'resize', '').'</a> &nbsp; ';
6764
-
6765
-								// Link to delete
6766
-								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6767
-								$return.= img_delete().'</a>';
6768
-							}
6769
-						}
6770
-					}
7321
+        if (! $error && ! empty($this->isextrafieldmanaged))
7322
+        {
7323
+            $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element."_extrafields";
7324
+            $sql.= " WHERE fk_object=" . $this->id;
6771 7325
 
6772
-					// On continue ou on arrete de boucler ?
6773
-					if ($nbmax && $nbphoto >= $nbmax) break;
6774
-				}
6775
-			}
7326
+            $resql = $this->db->query($sql);
7327
+            if (! $resql)
7328
+            {
7329
+                $this->errors[] = $this->db->lasterror();
7330
+                $error++;
7331
+            }
7332
+        }
6776 7333
 
6777
-			if ($size==1 || $size=='small')
6778
-			{
6779
-				if ($nbbyrow > 0)
6780
-				{
6781
-					// Ferme tableau
6782
-					while ($nbphoto % $nbbyrow)
6783
-					{
6784
-						$return.= '<td width="'.ceil(100/$nbbyrow).'%">&nbsp;</td>';
6785
-						$nbphoto++;
6786
-					}
6787
-
6788
-					if ($nbphoto) $return.= '</table>';
6789
-				}
6790
-			}
6791
-		}
6792
-
6793
-		$this->nbphoto = $nbphoto;
6794
-
6795
-		return $return;
6796
-	}
6797
-
6798
-
6799
-	/**
6800
-	 * Function test if type is array
6801
-	 *
6802
-	 * @param   array   $info   content informations of field
6803
-	 * @return                  bool
6804
-	 */
6805
-	protected function isArray($info)
6806
-	{
6807
-		if(is_array($info))
6808
-		{
6809
-			if(isset($info['type']) && $info['type']=='array') return true;
6810
-			else return false;
6811
-		}
6812
-		else return false;
6813
-	}
6814
-
6815
-	/**
6816
-	 * Function test if type is null
6817
-	 *
6818
-	 * @param   array   $info   content informations of field
6819
-	 * @return                  bool
6820
-	 */
6821
-	protected function isNull($info)
6822
-	{
6823
-		if(is_array($info))
6824
-		{
6825
-			if(isset($info['type']) && $info['type']=='null') return true;
6826
-			else return false;
6827
-		}
6828
-		else return false;
6829
-	}
6830
-
6831
-	/**
6832
-	 * Function test if type is date
6833
-	 *
6834
-	 * @param   array   $info   content informations of field
6835
-	 * @return                  bool
6836
-	 */
6837
-	public function isDate($info)
6838
-	{
6839
-		if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true;
6840
-		else return false;
6841
-	}
6842
-
6843
-	/**
6844
-	 * Function test if type is integer
6845
-	 *
6846
-	 * @param   array   $info   content informations of field
6847
-	 * @return                  bool
6848
-	 */
6849
-	public function isInt($info)
6850
-	{
6851
-		if(is_array($info))
6852
-		{
6853
-			if(isset($info['type']) && ($info['type']=='int' || preg_match('/^integer/i',$info['type']) ) ) return true;
6854
-			else return false;
6855
-		}
6856
-		else return false;
6857
-	}
6858
-
6859
-	/**
6860
-	 * Function test if type is float
6861
-	 *
6862
-	 * @param   array   $info   content informations of field
6863
-	 * @return                  bool
6864
-	 */
6865
-	public function isFloat($info)
6866
-	{
6867
-		if(is_array($info))
6868
-		{
6869
-			if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true;
6870
-			else return false;
6871
-		}
6872
-		else return false;
6873
-	}
6874
-
6875
-	/**
6876
-	 * Function test if type is text
6877
-	 *
6878
-	 * @param   array   $info   content informations of field
6879
-	 * @return                  bool
6880
-	 */
6881
-	public function isText($info)
6882
-	{
6883
-		if(is_array($info))
6884
-		{
6885
-			if(isset($info['type']) && $info['type']=='text') return true;
6886
-			else return false;
6887
-		}
6888
-		else return false;
6889
-	}
6890
-
6891
-	/**
6892
-	 * Function test if is indexed
6893
-	 *
6894
-	 * @param   array   $info   content informations of field
6895
-	 * @return                  bool
6896
-	 */
6897
-	protected function isIndex($info)
6898
-	{
6899
-		if(is_array($info))
6900
-		{
6901
-			if(isset($info['index']) && $info['index']==true) return true;
6902
-			else return false;
6903
-		}
6904
-		else return false;
6905
-	}
6906
-
6907
-	/**
6908
-	 * Function to prepare the values to insert.
6909
-	 * Note $this->${field} are set by the page that make the createCommon or the updateCommon.
6910
-	 *
6911
-	 * @return array
6912
-	 */
6913
-	protected function setSaveQuery()
6914
-	{
6915
-		global $conf;
6916
-
6917
-		$queryarray=array();
6918
-		foreach ($this->fields as $field=>$info)	// Loop on definition of fields
6919
-		{
6920
-			// Depending on field type ('datetime', ...)
6921
-			if($this->isDate($info))
6922
-			{
6923
-				if(empty($this->{$field}))
6924
-				{
6925
-					$queryarray[$field] = null;
6926
-				}
6927
-				else
6928
-				{
6929
-					$queryarray[$field] = $this->db->idate($this->{$field});
6930
-				}
6931
-			}
6932
-			else if($this->isArray($info))
6933
-			{
6934
-				if(! empty($this->{$field})) {
6935
-					if(! is_array($this->{$field})) {
6936
-						$this->{$field} = array($this->{$field});
6937
-					}
6938
-					$queryarray[$field] = serialize($this->{$field});
6939
-				} else {
6940
-					$queryarray[$field] = null;
6941
-				}
6942
-			}
6943
-			else if($this->isInt($info))
6944
-			{
6945
-				if ($field == 'entity' && is_null($this->{$field})) $queryarray[$field]=$conf->entity;
6946
-				else
6947
-				{
6948
-					$queryarray[$field] = (int) price2num($this->{$field});
6949
-					if (empty($queryarray[$field])) $queryarray[$field]=0;		// May be reset to null later if property 'notnull' is -1 for this field.
6950
-				}
6951
-			}
6952
-			else if($this->isFloat($info))
6953
-			{
6954
-				$queryarray[$field] = (double) price2num($this->{$field});
6955
-				if (empty($queryarray[$field])) $queryarray[$field]=0;
6956
-			}
6957
-			else
6958
-			{
6959
-				$queryarray[$field] = $this->{$field};
6960
-			}
7334
+        if (! $error)
7335
+        {
7336
+            $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
6961 7337
 
6962
-			if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]);
6963
-			if (! empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) $queryarray[$field] = null;
6964
-		}
7338
+            $res = $this->db->query($sql);
7339
+            if($res===false) {
7340
+                $error++;
7341
+                $this->errors[] = $this->db->lasterror();
7342
+            }
7343
+        }
6965 7344
 
6966
-		return $queryarray;
6967
-	}
7345
+        // Commit or rollback
7346
+        if ($error) {
7347
+            $this->db->rollback();
7348
+            return -1;
7349
+        } else {
7350
+            $this->db->commit();
7351
+            return 1;
7352
+        }
7353
+    }
6968 7354
 
6969
-	/**
6970
-	 * Function to load data from a SQL pointer into properties of current object $this
6971
-	 *
6972
-	 * @param   stdClass    $obj    Contain data of object from database
7355
+    /**
7356
+     * Initialise object with example values
7357
+     * Id must be 0 if object instance is a specimen
7358
+     *
6973 7359
      * @return void
6974
-	 */
6975
-	protected function setVarsFromFetchObj(&$obj)
6976
-	{
6977
-		foreach ($this->fields as $field => $info)
6978
-		{
6979
-			if($this->isDate($info))
6980
-			{
6981
-				if(empty($obj->{$field}) || $obj->{$field} === '0000-00-00 00:00:00' || $obj->{$field} === '1000-01-01 00:00:00') $this->{$field} = 0;
6982
-				else $this->{$field} = strtotime($obj->{$field});
6983
-			}
6984
-			elseif($this->isArray($info))
6985
-			{
6986
-				if(! empty($obj->{$field})) {
6987
-					$this->{$field} = @unserialize($obj->{$field});
6988
-					// Hack for data not in UTF8
6989
-					if($this->{$field } === false) @unserialize(utf8_decode($obj->{$field}));
6990
-				} else {
6991
-					$this->{$field} = array();
6992
-				}
6993
-			}
6994
-			elseif($this->isInt($info))
6995
-			{
6996
-				if ($field == 'rowid') $this->id = (int) $obj->{$field};
6997
-				else $this->{$field} = (int) $obj->{$field};
6998
-			}
6999
-			elseif($this->isFloat($info))
7000
-			{
7001
-				$this->{$field} = (double) $obj->{$field};
7002
-			}
7003
-			elseif($this->isNull($info))
7004
-			{
7005
-				$val = $obj->{$field};
7006
-				// zero is not null
7007
-				$this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val);
7008
-			}
7009
-			else
7010
-			{
7011
-				$this->{$field} = $obj->{$field};
7012
-			}
7013
-		}
7014
-
7015
-		// If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
7016
-		if (! isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id;
7017
-	}
7018
-
7019
-	/**
7020
-	 * Function to concat keys of fields
7021
-	 *
7022
-	 * @return string
7023
-	 */
7024
-	protected function getFieldList()
7025
-	{
7026
-		$keys = array_keys($this->fields);
7027
-		return implode(',', $keys);
7028
-	}
7029
-
7030
-	/**
7031
-	 * Add quote to field value if necessary
7032
-	 *
7033
-	 * @param 	string|int	$value			Value to protect
7034
-	 * @param	array		$fieldsentry	Properties of field
7035
-	 * @return 	string
7036
-	 */
7037
-    protected function quote($value, $fieldsentry)
7360
+     */
7361
+    public function initAsSpecimenCommon()
7038 7362
     {
7039
-		if (is_null($value)) return 'NULL';
7040
-		else if (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value");
7041
-		else return "'".$this->db->escape($value)."'";
7042
-	}
7043
-
7044
-
7045
-	/**
7046
-	 * Create object into database
7047
-	 *
7048
-	 * @param  User $user      User that creates
7049
-	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
7050
-	 * @return int             <0 if KO, Id of created object if OK
7051
-	 */
7052
-	public function createCommon(User $user, $notrigger = false)
7053
-	{
7054
-		global $langs;
7055
-
7056
-		$error = 0;
7057
-
7058
-		$now=dol_now();
7059
-
7060
-		$fieldvalues = $this->setSaveQuery();
7061
-		if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now);
7062
-		if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id;
7063
-		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
7064
-
7065
-		$keys=array();
7066
-		$values = array();
7067
-		foreach ($fieldvalues as $k => $v) {
7068
-			$keys[$k] = $k;
7069
-			$value = $this->fields[$k];
7070
-			$values[$k] = $this->quote($v, $value);
7071
-		}
7072
-
7073
-		// Clean and check mandatory
7074
-		foreach($keys as $key)
7075
-		{
7076
-			// If field is an implicit foreign key field
7077
-			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';
7078
-			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';
7079
-
7080
-			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7081
-			if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && ! isset($values[$key]) && is_null($val['default']))
7082
-			{
7083
-				$error++;
7084
-				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7085
-			}
7086
-
7087
-			// If field is an implicit foreign key field
7088
-			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key]='null';
7089
-			if (! empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key]='null';
7090
-		}
7091
-
7092
-		if ($error) return -1;
7093
-
7094
-		$this->db->begin();
7363
+        $this->id = 0;
7095 7364
 
7096
-		if (! $error)
7097
-		{
7098
-			$sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
7099
-			$sql.= ' ('.implode( ", ", $keys ).')';
7100
-			$sql.= ' VALUES ('.implode( ", ", $values ).')';
7365
+        // TODO...
7366
+    }
7101 7367
 
7102
-			$res = $this->db->query($sql);
7103
-			if ($res===false) {
7104
-				$error++;
7105
-				$this->errors[] = $this->db->lasterror();
7106
-			}
7107
-		}
7108
-
7109
-		if (! $error)
7110
-		{
7111
-			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
7112
-		}
7113
-
7114
-		// Create extrafields
7115
-		if (! $error)
7116
-		{
7117
-			$result=$this->insertExtraFields();
7118
-			if ($result < 0) $error++;
7119
-		}
7120
-
7121
-		// Triggers
7122
-		if (! $error && ! $notrigger)
7123
-		{
7124
-			// Call triggers
7125
-			$result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE',$user);
7126
-			if ($result < 0) { $error++; }
7127
-			// End call triggers
7128
-		}
7129
-
7130
-		// Commit or rollback
7131
-		if ($error) {
7132
-			$this->db->rollback();
7133
-			return -1;
7134
-		} else {
7135
-			$this->db->commit();
7136
-			return $this->id;
7137
-		}
7138
-	}
7139
-
7140
-
7141
-	/**
7142
-	 * Load object in memory from the database
7143
-	 *
7144
-	 * @param	int    $id				Id object
7145
-	 * @param	string $ref				Ref
7146
-	 * @param	string	$morewhere		More SQL filters (' AND ...')
7147
-	 * @return 	int         			<0 if KO, 0 if not found, >0 if OK
7148
-	 */
7149
-	public function fetchCommon($id, $ref = null, $morewhere = '')
7150
-	{
7151
-		if (empty($id) && empty($ref) && empty($morewhere)) return -1;
7152
-
7153
-		$sql = 'SELECT '.$this->getFieldList();
7154
-		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
7155
-
7156
-		if (!empty($id))  $sql.= ' WHERE rowid = '.$id;
7157
-		elseif (!empty($ref)) $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']);
7158
-		else $sql.=' WHERE 1 = 1';	// usage with empty id and empty ref is very rare
7159
-		if ($morewhere)   $sql.= $morewhere;
7160
-		$sql.=' LIMIT 1';	// This is a fetch, to be sure to get only one record
7161
-
7162
-		$res = $this->db->query($sql);
7163
-		if ($res)
7164
-		{
7165
-			$obj = $this->db->fetch_object($res);
7166
-			if ($obj)
7167
-			{
7168
-				$this->setVarsFromFetchObj($obj);
7169
-				return $this->id;
7170
-			}
7171
-			else
7172
-			{
7173
-				return 0;
7174
-			}
7175
-		}
7176
-		else
7177
-		{
7178
-			$this->error = $this->db->lasterror();
7179
-			$this->errors[] = $this->error;
7180
-			return -1;
7181
-		}
7182
-	}
7183
-
7184
-	/**
7185
-	 * Update object into database
7186
-	 *
7187
-	 * @param  User $user      	User that modifies
7188
-	 * @param  bool $notrigger 	false=launch triggers after, true=disable triggers
7189
-	 * @return int             	<0 if KO, >0 if OK
7190
-	 */
7191
-	public function updateCommon(User $user, $notrigger = false)
7192
-	{
7193
-		global $conf, $langs;
7194
-
7195
-		$error = 0;
7196
-
7197
-		$now=dol_now();
7198
-
7199
-		$fieldvalues = $this->setSaveQuery();
7200
-		if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification']=$this->db->idate($now);
7201
-		if (array_key_exists('fk_user_modif', $fieldvalues) && ! ($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif']=$user->id;
7202
-		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
7203
-
7204
-		$keys=array();
7205
-		$values = array();
7206
-		foreach ($fieldvalues as $k => $v) {
7207
-			$keys[$k] = $k;
7208
-			$value = $this->fields[$k];
7209
-			$values[$k] = $this->quote($v, $value);
7210
-			$tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
7211
-		}
7212
-
7213
-		// Clean and check mandatory
7214
-		foreach($keys as $key)
7215
-		{
7216
-			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';		// This is an implicit foreign key field
7217
-			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';					// This is an explicit foreign key field
7218
-
7219
-			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7220
-			/*
7221
-			if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
7222
-			{
7223
-				$error++;
7224
-				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7225
-			}*/
7226
-		}
7227 7368
 
7228
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ;
7369
+    /* Part for comments */
7229 7370
 
7230
-		$this->db->begin();
7231
-		if (! $error)
7232
-		{
7233
-			$res = $this->db->query($sql);
7234
-			if ($res===false)
7235
-			{
7236
-				$error++;
7237
-				$this->errors[] = $this->db->lasterror();
7238
-			}
7239
-		}
7240
-
7241
-		// Update extrafield
7242
-		if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0)
7243
-		{
7244
-			$result=$this->insertExtraFields();
7245
-			if ($result < 0)
7246
-			{
7247
-				$error++;
7248
-			}
7249
-		}
7250
-
7251
-		// Triggers
7252
-		if (! $error && ! $notrigger)
7253
-		{
7254
-			// Call triggers
7255
-			$result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user);
7256
-			if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail
7257
-			// End call triggers
7258
-		}
7259
-
7260
-		// Commit or rollback
7261
-		if ($error) {
7262
-			$this->db->rollback();
7263
-			return -1;
7264
-		} else {
7265
-			$this->db->commit();
7266
-			return $this->id;
7267
-		}
7268
-	}
7269
-
7270
-	/**
7271
-	 * Delete object in database
7272
-	 *
7273
-	 * @param 	User 	$user       			User that deletes
7274
-	 * @param 	bool 	$notrigger  			false=launch triggers after, true=disable triggers
7275
-	 * @param	int		$forcechilddeletion		0=no, 1=Force deletion of children
7276
-	 * @return 	int             				<=0 if KO, >0 if OK
7277
-	 */
7278
-	public function deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
7279
-	{
7280
-		$error=0;
7281
-
7282
-		$this->db->begin();
7283
-
7284
-		if ($forcechilddeletion)
7285
-		{
7286
-			foreach($this->childtables as $table)
7287
-			{
7288
-				$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
7289
-				$resql = $this->db->query($sql);
7290
-				if (! $resql)
7291
-				{
7292
-					$this->error=$this->db->lasterror();
7293
-					$this->errors[]=$this->error;
7294
-					$this->db->rollback();
7295
-					return -1;
7296
-				}
7297
-			}
7298
-		}
7299
-		elseif (! empty($this->fk_element) && ! empty($this->childtables))	// If object has childs linked with a foreign key field, we check all child tables.
7300
-		{
7301
-			$objectisused = $this->isObjectUsed($this->id);
7302
-			if (! empty($objectisused))
7303
-			{
7304
-				dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
7305
-				$this->error='ErrorRecordHasChildren';
7306
-				$this->errors[]=$this->error;
7307
-				$this->db->rollback();
7308
-				return 0;
7309
-			}
7310
-		}
7311
-
7312
-		if (! $error) {
7313
-			if (! $notrigger) {
7314
-				// Call triggers
7315
-				$result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
7316
-				if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
7317
-				// End call triggers
7318
-			}
7319
-		}
7320
-
7321
-		if (! $error && ! empty($this->isextrafieldmanaged))
7322
-		{
7323
-			$sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element."_extrafields";
7324
-			$sql.= " WHERE fk_object=" . $this->id;
7325
-
7326
-			$resql = $this->db->query($sql);
7327
-			if (! $resql)
7328
-			{
7329
-				$this->errors[] = $this->db->lasterror();
7330
-				$error++;
7331
-			}
7332
-		}
7371
+    /**
7372
+     * Load comments linked with current task
7373
+     *	@return boolean	1 if ok
7374
+     */
7375
+    public function fetchComments()
7376
+    {
7377
+        require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
7333 7378
 
7334
-		if (! $error)
7335
-		{
7336
-			$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
7379
+        $comment = new Comment($this->db);
7380
+        $result=$comment->fetchAllFor($this->element, $this->id);
7381
+        if ($result<0) {
7382
+            $this->errors=array_merge($this->errors, $comment->errors);
7383
+            return -1;
7384
+        } else {
7385
+            $this->comments = $comment->comments;
7386
+        }
7387
+        return count($this->comments);
7388
+    }
7337 7389
 
7338
-			$res = $this->db->query($sql);
7339
-			if($res===false) {
7340
-				$error++;
7341
-				$this->errors[] = $this->db->lasterror();
7342
-			}
7343
-		}
7344
-
7345
-		// Commit or rollback
7346
-		if ($error) {
7347
-			$this->db->rollback();
7348
-			return -1;
7349
-		} else {
7350
-			$this->db->commit();
7351
-			return 1;
7352
-		}
7353
-	}
7354
-
7355
-	/**
7356
-	 * Initialise object with example values
7357
-	 * Id must be 0 if object instance is a specimen
7358
-	 *
7359
-	 * @return void
7360
-	 */
7361
-	public function initAsSpecimenCommon()
7362
-	{
7363
-		$this->id = 0;
7364
-
7365
-		// TODO...
7366
-	}
7367
-
7368
-
7369
-	/* Part for comments */
7370
-
7371
-	/**
7372
-	 * Load comments linked with current task
7373
-	 *	@return boolean	1 if ok
7374
-	 */
7375
-	public function fetchComments()
7376
-	{
7377
-		require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
7378
-
7379
-		$comment = new Comment($this->db);
7380
-		$result=$comment->fetchAllFor($this->element, $this->id);
7381
-		if ($result<0) {
7382
-			$this->errors=array_merge($this->errors, $comment->errors);
7383
-			return -1;
7384
-		} else {
7385
-			$this->comments = $comment->comments;
7386
-		}
7387
-		return count($this->comments);
7388
-	}
7389
-
7390
-	/**
7391
-	 * Return nb comments already posted
7392
-	 *
7393
-	 * @return int
7394
-	 */
7395
-	public function getNbComments()
7396
-	{
7397
-		return count($this->comments);
7398
-	}
7390
+    /**
7391
+     * Return nb comments already posted
7392
+     *
7393
+     * @return int
7394
+     */
7395
+    public function getNbComments()
7396
+    {
7397
+        return count($this->comments);
7398
+    }
7399 7399
 
7400 7400
     /**
7401 7401
      * Trim object parameters
Please login to merge, or discard this patch.