dolibarr 25.0.0-alpha
card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
5 * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
6 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
7 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
8 * Copyright (C) 2010-2023 Juanjo Menent <jmenent@2byte.es>
9 * Copyright (C) 2010-2022 Philippe Grand <philippe.grand@atoo-net.com>
10 * Copyright (C) 2012-2023 Christophe Battarel <christophe.battarel@altairis.fr>
11 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
12 * Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
13 * Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
14 * Copyright (C) 2016 Marcos García <marcosgdf@gmail.com>
15 * Copyright (C) 2018-2026 Frédéric France <frederic.france@free.fr>
16 * Copyright (C) 2020 Nicolas ZABOURI <info@inovea-conseil.com>
17 * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
18 * Copyright (C) 2023 Lenin Rivas <lenin.rivas777@gmail.com>
19 * Copyright (C) 2023 William Mead <william.mead@manchenumerique.fr>
20 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
21 * Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
22 * Copyright (C) 2025 Benjamin Falière <benjamin@faliere.com>
23 * Copyright (C) 2025 Anthony Berton <anthony.berton@bb2a.fr>
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 3 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program. If not, see <https://www.gnu.org/licenses/>.
37 */
38
39
46// Load Dolibarr environment
47require '../../main.inc.php';
57require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
58require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
59require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php';
60require_once DOL_DOCUMENT_ROOT . '/core/class/html.formpropal.class.php';
61require_once DOL_DOCUMENT_ROOT . '/core/class/html.formmargin.class.php';
62require_once DOL_DOCUMENT_ROOT . '/comm/propal/class/propal.class.php';
63require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
64require_once DOL_DOCUMENT_ROOT . '/core/modules/propale/modules_propale.php';
65require_once DOL_DOCUMENT_ROOT . '/core/lib/propal.lib.php';
66require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php';
67require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
68require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
69if (isModEnabled('project')) {
70 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
71 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
72}
73
74if (isModEnabled('variants')) {
75 require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductCombination.class.php';
76}
77
78
79// Load translation files required by the page
80$langs->loadLangs(array('companies', 'propal', 'compta', 'bills', 'orders', 'products', 'sendings', 'other'));
81if (isModEnabled('incoterm')) {
82 $langs->load('incoterm');
83}
84if (isModEnabled('margin')) {
85 $langs->load('margins');
86}
87
88$error = 0;
89$outlangs = null;
90$array_options = array();
91
92$id = GETPOSTINT('id');
93$ref = GETPOST('ref', 'alpha');
94$socid = GETPOSTINT('socid');
95$action = GETPOST('action', 'aZ09');
96$cancel = GETPOST('cancel', 'alpha');
97$origin = GETPOST('origin', 'alpha');
98$originid = GETPOSTINT('originid');
99$renewal = GETPOST('renewal'); // for contract renewal
100$confirm = GETPOST('confirm', 'alpha');
101$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page
102$lineid = GETPOSTINT('lineid');
103$contactid = GETPOSTINT('contactid');
104$projectid = GETPOSTINT('projectid');
105$rank = (GETPOSTINT('rank') > 0) ? GETPOSTINT('rank') : -1;
106
107// PDF
108$hidedetails = (GETPOSTINT('hidedetails') ? GETPOSTINT('hidedetails') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
109$hidedesc = (GETPOSTINT('hidedesc') ? GETPOSTINT('hidedesc') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
110$hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
111
112$object = new Propal($db);
113
114// fetch optionals attributes and labels
115$extrafields->fetch_name_optionals_label($object->table_element);
116
117// Load object
118if ($id > 0 || !empty($ref)) {
119 $ret = $object->fetch($id, $ref);
120 if ($ret > 0) {
121 $ret = $object->fetch_thirdparty();
122 if ($ret > 0 && isset($object->fk_project)) {
123 $ret = $object->fetchProject();
124 }
125 }
126 if ($ret <= 0) {
127 setEventMessages($object->error, $object->errors, 'errors');
128 $action = '';
129 }
130}
131
132// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
133$hookmanager->initHooks(array('propalcard', 'globalcard'));
134
135$usercanread = $user->hasRight("propal", "lire");
136$usercancreate = $user->hasRight("propal", "creer");
137$usercandelete = $user->hasRight("propal", "supprimer");
138
139$usercanclose = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'close')));
140$usercanvalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'validate')));
141$usercansend = (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'send')));
142
143$usermustrespectpricemin = ((getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('produit', 'ignore_price_min_advance')) || !getDolGlobalString('MAIN_USE_ADVANCED_PERMS'));
144$usercancreateorder = ($user->hasRight('commande', 'creer') == 1);
145$usercancreateinvoice = ($user->hasRight('facture', 'creer') == 1);
146$usercancreatecontract = ($user->hasRight('contrat', 'creer') == 1);
147$usercancreateintervention = ($user->hasRight('ficheinter', 'creer') == 1);
148$usercancreatepurchaseorder = ($user->hasRight('fournisseur', 'commande', 'creer') || $user->hasRight('supplier_order', 'creer'));
149$usercanreopen = ((!getDolGlobalBool('MAIN_USE_ADVANCED_PERMS') && $usercanclose) || (getDolGlobalBool('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'reopen')));
150if (getDolGlobalBool('PROPAL_DISALLOW_REOPEN')) {
151 $usercanreopen = false;
152}
153
154$permissiontoadd = $usercancreate;
155$permissionnote = $usercancreate; // Used by the include of actions_setnotes.inc.php
156$permissiondellink = $usercancreate; // Used by the include of actions_dellink.inc.php
157$permissiontoedit = $usercancreate; // Used by the include of actions_lineupdown.inc.php
158$permissiontoeditextra = $permissiontoadd;
159if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
160 // For action 'update_extras', is there a specific permission set for the attribute to update
161 $permissiontoeditextra = dol_eval((string) $extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
162}
163
164$price_base_type = null;
165$shipping_method_id = null;
166$warehouse_id = -1;
167
168// Security check
169if (!empty($user->socid)) {
170 $socid = $user->socid;
171}
172restrictedArea($user, 'propal', $object->id);
173
174
175/*
176 * Actions
177 */
178
179$parameters = array('socid' => $socid);
180$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
181if ($reshook < 0) {
182 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
183}
184if (empty($reshook)) {
185 $backurlforlist = dolBuildUrl(DOL_URL_ROOT . '/comm/propal/list.php');
186
187 if (empty($backtopage) || ($cancel && empty($id))) {
188 if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
189 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
190 $backtopage = $backurlforlist;
191 } else {
192 $backtopage = dolBuildUrl(DOL_URL_ROOT . '/comm/propal/card.php', ['id' => ((!empty($id) && $id > 0) ? $id : '__ID__')]);
193 }
194 }
195 }
196
197 if ($cancel) {
198 if (!empty($backtopageforcancel)) {
199 header("Location: " . $backtopageforcancel);
200 exit;
201 } elseif (!empty($backtopage)) {
202 header("Location: " . $backtopage);
203 exit;
204 }
205 $action = '';
206 }
207
208 include DOL_DOCUMENT_ROOT . '/core/actions_setnotes.inc.php'; // Must be include, not includ_once
209
210 include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once'
211
212 include DOL_DOCUMENT_ROOT . '/core/actions_lineupdown.inc.php'; // Must be 'include', not 'include_once'
213
214 // Action clone object
215 if ($action == 'confirm_clone' && $confirm == 'yes' && $usercancreate) {
216 if (!($socid > 0)) {
217 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('IdThirdParty')), null, 'errors');
218 } else {
219 if ($object->id > 0) {
220 // We clone object to avoid to denaturate loaded object when setting some properties for clone or if createFromClone modifies the object.
221 $objectutil = dol_clone($object, 1);
222 '@phan-var-force Propal $objectutil';
223
224 if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY')) {
225 //Get difference between old and new delivery date and change lines according to difference
226 $date_delivery = dol_mktime(
227 12,
228 0,
229 0,
230 GETPOSTINT('date_deliverymonth'),
231 GETPOSTINT('date_deliveryday'),
232 GETPOSTINT('date_deliveryyear')
233 );
234 $date_delivery_old = $objectutil->delivery_date;
235 if (!empty($date_delivery_old) && !empty($date_delivery)) {
236 //Attempt to get the date without possible hour rounding errors
237 $old_date_delivery = dol_mktime(
238 12,
239 0,
240 0,
241 (int) dol_print_date($date_delivery_old, '%m'),
242 (int) dol_print_date($date_delivery_old, '%d'),
243 (int) dol_print_date($date_delivery_old, '%Y')
244 );
245 //Calculate the difference and apply if necessary
246 $difference = $date_delivery - $old_date_delivery;
247 if ($difference != 0) {
248 $objectutil->delivery_date = $date_delivery;
249 foreach ($objectutil->lines as $line) {
250 if (isset($line->date_start)) {
251 $line->date_start += $difference;
252 }
253 if (isset($line->date_end)) {
254 $line->date_end += $difference;
255 }
256 }
257 }
258 }
259 }
260
261 $result = $objectutil->createFromClone($user, $socid, (GETPOSTISSET('entity') ? GETPOSTINT('entity') : null), (GETPOST('update_prices') == 'on'), (GETPOST('update_desc') == 'on'));
262 if ($result > 0) {
263 $warningMsgLineList = array();
264 // check all product lines are to sell otherwise add a warning message for each product line is not to sell
265 foreach ($objectutil->lines as $line) {
266 if (!is_object($line->product)) {
267 $line->fetch_product();
268 }
269 if (is_object($line->product) && $line->product->id > 0) {
270 if (empty($line->product->status)) {
271 $warningMsgLineList[$line->id] = $langs->trans('WarningLineProductNotToSell', $line->product->ref);
272 }
273 }
274 }
275 if (!empty($warningMsgLineList)) {
276 setEventMessages('', $warningMsgLineList, 'warnings');
277 }
278
279 header("Location: " . $_SERVER['PHP_SELF'] . '?id=' . $result);
280 exit();
281 } else {
282 if (count($objectutil->errors) > 0) {
283 setEventMessages($objectutil->error, $objectutil->errors, 'errors');
284 }
285 $action = '';
286 }
287 }
288 }
289 } elseif ($action == 'confirm_cancel' && $confirm == 'yes' && $usercanclose) {
290 // Cancel proposal
291 $result = $object->setCancel($user);
292 if ($result > 0) {
293 header('Location: ' . dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]));
294 exit();
295 } else {
296 $langs->load("errors");
297 setEventMessages($object->error, $object->errors, 'errors');
298 }
299 } elseif ($action == 'confirm_delete' && $confirm == 'yes' && $usercandelete) {
300 // Delete proposal
301 $result = $object->delete($user);
302 if ($result > 0) {
303 header('Location: ' . dolBuildUrl(DOL_URL_ROOT . '/comm/propal/list.php', ['restore_lastsearch_values' => 1]));
304 exit();
305 } else {
306 $langs->load("errors");
307 setEventMessages($object->error, $object->errors, 'errors');
308 }
309 } elseif ($action == 'confirm_deleteline' && $confirm == 'yes' && $usercancreate) {
310 // Remove line
311 $result = $object->deleteLine($lineid);
312 // reorder lines
313 if ($result > 0) {
314 $object->line_order(true);
315 } else {
316 $langs->load("errors");
317 setEventMessages($object->error, $object->errors, 'errors');
318 }
319
320 $ret = $object->fetch($id); // Reload to get new records
321 if ($ret > 0) {
322 $object->fetch_thirdparty();
323 }
324
325 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
326 // Define output language
327 $outputlangs = $langs;
328 if (getDolGlobalInt('MAIN_MULTILANGS')) {
329 $outputlangs = new Translate("", $conf);
330 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
331 $outputlangs->setDefaultLang($newlang);
332 }
333 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
334 }
335 } elseif ($action == 'confirm_delete_subtotalline' && $confirm == 'yes' && $usercancreate) {
336 // Delete line
337 $object->fetch($id);
338 $object->fetch_thirdparty();
339
340 $result = $object->deleteSubtotalLine($langs, GETPOSTINT('lineid'), (bool) GETPOST('deletecorrespondingsubtotalline'));
341 if ($result > 0) {
342 // reorder lines
343 $object->line_order(true);
344 // Define output language
345 $outputlangs = $langs;
346 $newlang = '';
347 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id')) {
348 $newlang = GETPOST('lang_id');
349 }
350 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
351 $newlang = $object->thirdparty->default_lang;
352 }
353 if (!empty($newlang)) {
354 $outputlangs = new Translate("", $conf);
355 $outputlangs->setDefaultLang($newlang);
356 $outputlangs->load('products');
357 }
358 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
359 $ret = $object->fetch($id); // Reload to get new records
360 $result = $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
361 }
362 if ($result >= 0) {
363 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id);
364 exit();
365 }
366 } else {
367 setEventMessages($object->error, $object->errors, 'errors');
368 $action = '';
369 }
370 } elseif ($action == 'confirm_validate' && $confirm == 'yes' && $usercanvalidate) {
371 // Validation
372 $idwarehouse = GETPOSTINT('idwarehouse');
373 $result = $object->valid($user);
374 if ($result > 0 && getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
375 $result = $object->closeProposal($user, $object::STATUS_SIGNED);
376 }
377
378 $ret = $object->fetch($id); // Reload to get new records
379
380 if ($result >= 0) {
381 $ret = $object->fetch($id); // Reload to get new records
382 if ($ret > 0) {
383 $object->fetch_thirdparty();
384 }
385 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
386 $outputlangs = $langs;
387 $newlang = '';
388 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
389 $newlang = GETPOST('lang_id', 'aZ09');
390 }
391 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
392 $newlang = $object->thirdparty->default_lang;
393 }
394 if (!empty($newlang)) {
395 $outputlangs = new Translate("", $conf);
396 $outputlangs->setDefaultLang($newlang);
397 }
398 $model = $object->model_pdf;
399
400 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
401 }
402 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
403 exit();
404 } else {
405 $langs->load("errors");
406 if (count($object->errors) > 0) {
407 setEventMessages($object->error, $object->errors, 'errors');
408 } else {
409 setEventMessages($langs->trans($object->error), null, 'errors');
410 }
411 }
412 } elseif ($action == 'setdate' && $usercancreate) {
413 $datep = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
414
415 if (empty($datep)) {
416 $error++;
417 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
418 }
419
420 if (!$error) {
421 $result = $object->set_date($user, $datep);
422 if ($result > 0 && !empty($object->duree_validite) && !empty($object->fin_validite)) {
423 $datev = $datep + ($object->duree_validite * 24 * 3600);
424 $result = $object->set_echeance($user, $datev, 1);
425 }
426 if ($result < 0) {
427 dol_print_error($db, $object->error);
428 } elseif (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
429 $outputlangs = $langs;
430 $newlang = '';
431 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
432 $newlang = GETPOST('lang_id', 'aZ09');
433 }
434 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
435 $newlang = $object->thirdparty->default_lang;
436 }
437 if (!empty($newlang)) {
438 $outputlangs = new Translate("", $conf);
439 $outputlangs->setDefaultLang($newlang);
440 }
441 $model = $object->model_pdf;
442 $ret = $object->fetch($id); // Reload to get new records
443 if ($ret > 0) {
444 $object->fetch_thirdparty();
445 }
446
447 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
448 }
449 }
450 } elseif ($action == 'setecheance' && $usercancreate) {
451 $result = $object->set_echeance($user, dol_mktime(12, 0, 0, GETPOSTINT('echmonth'), GETPOSTINT('echday'), GETPOSTINT('echyear')));
452 if ($result >= 0) {
453 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
454 $outputlangs = $langs;
455 $newlang = '';
456 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
457 $newlang = GETPOST('lang_id', 'aZ09');
458 }
459 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
460 $newlang = $object->thirdparty->default_lang;
461 }
462 if (!empty($newlang)) {
463 $outputlangs = new Translate("", $conf);
464 $outputlangs->setDefaultLang($newlang);
465 }
466 $model = $object->model_pdf;
467 $ret = $object->fetch($id); // Reload to get new records
468 if ($ret > 0) {
469 $object->fetch_thirdparty();
470 }
471
472 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
473 }
474 } else {
475 setEventMessages($object->error, $object->errors, 'errors');
476 }
477 } elseif ($action == 'setdate_livraison' && $usercancreate) {
478 $result = $object->setDeliveryDate($user, dol_mktime(12, 0, 0, GETPOSTINT('date_livraisonmonth'), GETPOSTINT('date_livraisonday'), GETPOSTINT('date_livraisonyear')));
479 if ($result < 0) {
480 setEventMessages($object->error, $object->errors, 'errors');
481 }
482 } elseif ($action == 'setref_client' && $usercancreate) {
483 // Positionne ref client
484 $result = $object->set_ref_client($user, GETPOST('ref_client'));
485 if ($result < 0) {
486 setEventMessages($object->error, $object->errors, 'errors');
487 }
488 } elseif ($action == 'set_incoterms' && isModEnabled('incoterm') && $usercancreate) {
489 // Set incoterm
490 $result = $object->setIncoterms(GETPOSTINT('incoterm_id'), GETPOST('location_incoterms'));
491 if ($result < 0) {
492 setEventMessages($object->error, $object->errors, 'errors');
493 }
494 } elseif ($action == 'settags' && isModEnabled('category') && $usercancreate) { // Set tags
495 $result = $object->setCategories(GETPOST('categories', 'array'));
496 if ($result < 0) {
497 setEventMessages($object->error, $object->errors, 'errors');
498 }
499 } elseif ($action == 'add' && $usercancreate) {
500 // Create proposal
501 $object->socid = $socid;
502 $object->fetch_thirdparty();
503
504 $datep = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
505 $date_delivery = dol_mktime(12, 0, 0, GETPOSTINT('date_livraisonmonth'), GETPOSTINT('date_livraisonday'), GETPOSTINT('date_livraisonyear'));
506 $duration = GETPOSTINT('duree_validite');
507
508 if (empty($datep)) {
509 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("DatePropal")), null, 'errors');
510 $action = 'create';
511 $error++;
512 }
513 if (empty($duration)) {
514 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ValidityDuration")), null, 'errors');
515 $action = 'create';
516 $error++;
517 }
518
519 if ($socid < 1) {
520 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Customer")), null, 'errors');
521
522 $action = 'create';
523 $error++;
524 }
525
526 if (!$error) {
527 $db->begin();
528
529 // If we select proposal to clone during creation (when option PROPAL_CLONE_ON_CREATE_PAGE is on)
530 if (GETPOST('createmode') == 'copy' && GETPOST('copie_propal')) {
531 if ($object->fetch(GETPOSTINT('copie_propal')) > 0) {
532 $object->ref = GETPOST('ref');
533 $object->datep = $datep;
534 $object->date = $datep;
535 $object->delivery_date = $date_delivery;
536 $object->availability_id = GETPOSTINT('availability_id');
537 $object->demand_reason_id = GETPOSTINT('demand_reason_id');
538 $object->fk_delivery_address = GETPOSTINT('fk_address');
539 $object->shipping_method_id = GETPOSTINT('shipping_method_id');
540 $object->warehouse_id = GETPOSTINT('warehouse_id');
541 $object->duree_validite = $duration;
542 $object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
543 $object->deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
544 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
545 $object->fk_account = GETPOSTINT('fk_account');
546 $object->socid = GETPOSTINT('socid');
547 $object->contact_id = GETPOSTINT('contactid');
548 $object->fk_project = GETPOSTINT('projectid');
549 $object->model_pdf = GETPOST('model', 'alphanohtml');
550 $object->author = $user; // deprecated
551 $object->user_author_id = $user->id;
552 $object->note_private = GETPOST('note_private', 'restricthtml');
553 $object->note_public = GETPOST('note_public', 'restricthtml');
556 $object->fk_incoterms = GETPOSTINT('incoterm_id');
557 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
558 } else {
559 setEventMessages($langs->trans("ErrorFailedToCopyProposal", GETPOST('copie_propal')), null, 'errors');
560 }
561 } else {
562 $object->ref = GETPOST('ref');
563 $object->ref_customer = GETPOST('ref_client');
564 $object->ref_client = $object->ref_customer;
565 $object->datep = $datep;
566 $object->date = $datep;
567 $object->delivery_date = $date_delivery;
568 $object->availability_id = GETPOSTINT('availability_id');
569 $object->demand_reason_id = GETPOSTINT('demand_reason_id');
570 $object->fk_delivery_address = GETPOSTINT('fk_address');
571 $object->shipping_method_id = GETPOSTINT('shipping_method_id');
572 $object->warehouse_id = GETPOSTINT('warehouse_id');
573 $object->duree_validite = price2num(GETPOST('duree_validite', 'alpha'));
574 $object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
575 $object->deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
576 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
577 $object->fk_account = GETPOSTINT('fk_account');
578 $object->contact_id = GETPOSTINT('contactid');
579 $object->fk_project = GETPOSTINT('projectid');
580 $object->model_pdf = GETPOST('model');
581 $object->author = $user; // deprecated
582 $object->user_author_id = $user->id;
583 $object->note_private = GETPOST('note_private', 'restricthtml');
584 $object->note_public = GETPOST('note_public', 'restricthtml');
585 $object->fk_incoterms = GETPOSTINT('incoterm_id');
586 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
587
588 $object->origin = GETPOST('origin');
589 $object->origin_id = GETPOSTINT('originid');
590
591 // Multicurrency
592 if (isModEnabled("multicurrency")) {
593 $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
594 }
595
596 // Fill array 'array_options' with data from add form
597 $ret = $extrafields->setOptionalsFromPost(null, $object);
598 if ($ret < 0) {
599 $error++;
600 $action = 'create';
601 }
602 }
603
604 if (!$error) {
605 if ($origin && $originid) {
606 // Parse element/subelement (ex: project_task)
607 $element = $subelement = $origin;
608 $regs = array();
609 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
610 $element = $regs[1];
611 $subelement = $regs[2];
612 }
613
614 // For compatibility
615 if ($element == 'order') {
616 $element = $subelement = 'commande';
617 }
618 if ($element == 'propal') {
619 $element = 'comm/propal';
620 $subelement = 'propal';
621 }
622 if ($element == 'contract') {
623 $element = $subelement = 'contrat';
624 }
625 if ($element == 'inter') {
626 $element = $subelement = 'fichinter';
627 }
628 if ($element == 'shipping') {
629 $element = $subelement = 'expedition';
630 }
631
632 // If this is a renewal proposal for a contract, we might choose to systematically create a new contract,
633 if (($origin != 'contrat' || $renewal != 'true') && !getDolGlobalInt('CONTRACT_NEW_CONTRACT_ON_RENEWAL')) {
634 $object->origin = $origin;
635 $object->origin_id = $originid;
636
637 // Possibility to add external linked objects with hooks
638 $object->linked_objects[$object->origin] = $object->origin_id;
639 }
640 if (GETPOSTISARRAY('other_linked_objects')) {
641 $object->linked_objects = array_merge($object->linked_objects, GETPOST('other_linked_objects', 'array:int'));
642 }
643
644 $id = $object->create($user);
645 if ($id > 0) {
646 dol_include_once('/' . $element . '/class/' . $subelement . '.class.php');
647
648 $classname = ucfirst($subelement);
649 $srcobject = new $classname($db);
650 '@phan-var-force Commande|Propal|Contrat|Fichinter|Expedition $srcobject'; // Can be other class, but CommonObject is too generic
653 dol_syslog("Try to find source object origin=" . $object->origin . " originid=" . $object->origin_id . " to add lines");
654 $result = $srcobject->fetch($object->origin_id);
655
656 if ($result > 0) {
657 $lines = $srcobject->lines;
658 if (empty($lines) && method_exists($srcobject, 'fetch_lines')) {
659 $srcobject->fetch_lines();
660 $lines = $srcobject->lines;
661 }
662
663 $fk_parent_line = 0;
664 $num = count($lines);
665 for ($i = 0; $i < $num; $i++) {
666 $label = (!empty($lines[$i]->label) ? $lines[$i]->label : '');
667 $desc = (!empty($lines[$i]->desc) ? $lines[$i]->desc : '');
668
669 // Positive line
670 $product_type = ($lines[$i]->product_type ? (int) $lines[$i]->product_type : 0);
671
672 // Date start
673 $date_start = false;
674 if ($lines[$i]->date_debut_prevue) {
675 $date_start = $lines[$i]->date_debut_prevue;
676 }
677 if ($lines[$i]->date_debut_reel) {
678 $date_start = $lines[$i]->date_debut_reel;
679 }
680 if ($lines[$i]->date_start) {
681 $date_start = $lines[$i]->date_start;
682 }
683
684 // Date end
685 $date_end = false;
686 if ($lines[$i]->date_fin_prevue) {
687 $date_end = $lines[$i]->date_fin_prevue;
688 }
689 if ($lines[$i]->date_fin_reel) {
690 $date_end = $lines[$i]->date_fin_reel;
691 }
692 if ($lines[$i]->date_end) {
693 $date_end = $lines[$i]->date_end;
694 }
695
696 // For a contract renewal, we report duration, starting after the end of contract
697 if ($origin == 'contrat' && $renewal == 'true') {
698 if ($lines[$i]->date_start && $lines[$i]->date_end) {
699 $duration = $lines[$i]->date_end - $lines[$i]->date_start;
700 $date_start = $lines[$i]->date_end + 86400;
701 $date_end = $date_start + $duration;
702 }
703 }
704
705 // Reset fk_parent_line for no child products and special product
706 if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
707 $fk_parent_line = 0;
708 }
709
710 // Extrafields
711 if (method_exists($lines[$i], 'fetch_optionals')) {
712 $lines[$i]->fetch_optionals();
713 $array_options = $lines[$i]->array_options;
714 }
715
716 $tva_tx = $lines[$i]->tva_tx;
717 if (!empty($lines[$i]->vat_src_code) && !preg_match('/\‍(/', $tva_tx)) {
718 $tva_tx .= ' (' . $lines[$i]->vat_src_code . ')';
719 }
720
721 // Preserve the TTC entry mode of the source line: a line entered including tax must
722 // stay in TTC so its total is computed from the typed value, without rounding drift.
723 $line_price_base_type = $lines[$i]->getPriceBaseType();
724 $result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $line_price_base_type, (float) $lines[$i]->subprice_ttc, $lines[$i]->info_bits, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $date_start, $date_end, $array_options, $lines[$i]->fk_unit);
725
726 if ($result > 0) {
727 $lineid = $result;
728 } else {
729 $lineid = 0;
730 $error++;
731 break;
732 }
733
734 // Defined the new fk_parent_line
735 if ($result > 0 && $lines[$i]->product_type == 9) {
736 $fk_parent_line = $result;
737 }
738 }
739
740 // Hooks
741 $parameters = array('objFrom' => $srcobject);
742 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been
743 // modified by hook
744 if ($reshook < 0) {
745 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
746 $error++;
747 }
748 } else {
749 setEventMessages($srcobject->error, $srcobject->errors, 'errors');
750 $error++;
751 }
752 } else {
753 setEventMessages($object->error, $object->errors, 'errors');
754 $error++;
755 }
756 } else {
757 // Standard creation
758 $id = $object->create($user);
759 }
760
761 if ($id > 0) {
762 // Insert default contacts if defined
763 if (GETPOST('contactid') > 0) {
764 $result = $object->add_contact(GETPOSTINT('contactid'), 'CUSTOMER', 'external');
765 if ($result < 0) {
766 $error++;
767 setEventMessages($langs->trans("ErrorFailedToAddContact"), null, 'errors');
768 }
769 }
770
771 if (getDolGlobalString('PROPOSAL_AUTO_ADD_AUTHOR_AS_CONTACT')) {
772 $result = $object->add_contact($user->id, 'SALESREPFOLL', 'internal');
773 if ($result < 0) {
774 $error++;
775 setEventMessages($langs->trans("ErrorFailedToAddUserAsContact"), null, 'errors');
776 }
777 }
778 if (isModEnabled('category')) {
779 $categories = GETPOST('categories', 'array');
780 if (method_exists($object, 'setCategories')) {
781 $object->setCategories($categories);
782 }
783 }
784
785 if (!$error) {
786 $db->commit();
787
788 // Define output language
789 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
790 $outputlangs = $langs;
791 $newlang = '';
792 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
793 $newlang = GETPOST('lang_id', 'aZ09');
794 }
795 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
796 $newlang = $object->thirdparty->default_lang;
797 }
798 if (!empty($newlang)) {
799 $outputlangs = new Translate("", $conf);
800 $outputlangs->setDefaultLang($newlang);
801 }
802 $model = $object->model_pdf;
803
804 $ret = $object->fetch($id); // Reload to get new records
805 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
806 if ($result < 0) {
807 dol_print_error($db, $object->error, $object->errors);
808 }
809 }
810
811 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id);
812 exit();
813 } else {
814 $db->rollback();
815 $action = 'create';
816 }
817 } else {
818 setEventMessages($object->error, $object->errors, 'errors');
819 $db->rollback();
820 $action = 'create';
821 }
822 }
823 }
824 } elseif ($action == 'classifybilled' && $usercanclose) {
825 // Classify billed
826 $db->begin();
827
828 $result = $object->classifyBilled($user, 0, '');
829 if ($result < 0) {
830 setEventMessages($object->error, $object->errors, 'errors');
831 $error++;
832 }
833
834 if (!$error) {
835 $db->commit();
836 } else {
837 $db->rollback();
838 }
839 } elseif ($action == 'confirm_closeas' && $usercanclose && !GETPOST('cancel', 'alpha')) {
840 // Close proposal
841 if (!(GETPOSTINT('statut') > 0)) {
842 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CloseAs")), null, 'errors');
843 $action = 'closeas';
844 } elseif (GETPOSTINT('statut') == $object::STATUS_SIGNED || GETPOSTINT('statut') == $object::STATUS_NOTSIGNED) {
845 $locationTarget = '';
846 // prevent browser refresh from closing proposal several times
847 if ($object->status == $object::STATUS_VALIDATED || (getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE') && $object->status == $object::STATUS_DRAFT)) {
848 $db->begin();
849
850 $oldstatus = $object->status;
851
852 $result = $object->closeProposal($user, GETPOSTINT('statut'), GETPOST('note_private'));
853
854 if ($result < 0) {
855 setEventMessages($object->error, $object->errors, 'errors');
856 $error++;
857 } else {
858 // Needed if object linked modified by trigger (because linked objects can't be fetched two times : linkedObjectsFullLoaded)
859 $locationTarget = DOL_URL_ROOT . '/comm/propal/card.php?id=' . $object->id;
860 }
861
862 $deposit = null;
863
864 $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
865
866 if (
867 !$error && GETPOSTINT('statut') == $object::STATUS_SIGNED && GETPOST('generate_deposit') == 'on'
868 && !empty($deposit_percent_from_payment_terms) && isModEnabled('invoice') && $user->hasRight('facture', 'creer')
869 ) {
870 require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
871
872 $date = dol_mktime(0, 0, 0, GETPOSTINT('datefmonth'), GETPOSTINT('datefday'), GETPOSTINT('datefyear'));
873 $forceFields = array();
874
875 if (GETPOSTISSET('date_pointoftax')) {
876 $forceFields['date_pointoftax'] = dol_mktime(0, 0, 0, GETPOSTINT('date_pointoftaxmonth'), GETPOSTINT('date_pointoftaxday'), GETPOSTINT('date_pointoftaxyear'));
877 }
878
879 $deposit = Facture::createDepositFromOrigin($object, $date, GETPOSTINT('cond_reglement_id'), $user, 0, GETPOSTINT('validate_generated_deposit') == 'on', $forceFields);
880
881 if ($deposit) {
882 setEventMessage('DepositGenerated');
883 $locationTarget = DOL_URL_ROOT . '/compta/facture/card.php?id=' . $deposit->id;
884 } else {
885 $error++;
886 setEventMessages("Failed to create down payment - " . $object->error, $object->errors, 'errors');
887 }
888 }
889
890 if (!$error) {
891 $db->commit();
892
893 if ($deposit && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
894 $ret = $deposit->fetch($deposit->id); // Reload to get new records
895 $outputlangs = $langs;
896
897 if (getDolGlobalInt('MAIN_MULTILANGS')) {
898 $outputlangs = new Translate('', $conf);
899 $outputlangs->setDefaultLang($deposit->thirdparty->default_lang);
900 $outputlangs->load('products');
901 }
902
903 $result = $deposit->generateDocument($deposit->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
904
905 if ($result < 0) {
906 setEventMessages($deposit->error, $deposit->errors, 'errors');
907 }
908 }
909
910 if ($locationTarget) {
911 header('Location: ' . $locationTarget);
912 exit;
913 }
914 } else {
915 $object->status = $oldstatus;
916 $object->statut = $oldstatus; // deprecated
917
918 $db->rollback();
919 $action = '';
920 }
921 }
922 }
923 } elseif ($action == 'confirm_reopen' && $usercanreopen && !GETPOST('cancel', 'alpha')) {
924 // Reopen proposal
925 // prevent browser refresh from reopening proposal several times
927 $db->begin();
928
929 $newstatus = (getDolGlobalInt('PROPAL_SKIP_ACCEPT_REFUSE') ? Propal::STATUS_DRAFT : Propal::STATUS_VALIDATED);
930 $result = $object->reopen($user, $newstatus);
931 if ($result < 0) {
932 setEventMessages($object->error, $object->errors, 'errors');
933 $error++;
934 } else {
935 $object->statut = $newstatus; // deprecated
936 $object->status = $newstatus;
937 }
938
939 if (!$error) {
940 $db->commit();
941 } else {
942 $db->rollback();
943 }
944 }
945 } elseif ($action == 'import_lines_from_object' && $usercancreate && $object->status == Propal::STATUS_DRAFT) {
946 // add lines from objectlinked
947 $fromElement = GETPOST('fromelement');
948 $fromElementid = GETPOST('fromelementid');
949 $importLines = GETPOST('line_checkbox');
950
951 if (!empty($importLines) && is_array($importLines) && !empty($fromElement) && ctype_alpha($fromElement) && !empty($fromElementid)) {
952 if ($fromElement == 'commande') {
953 dol_include_once('/' . $fromElement . '/class/' . $fromElement . '.class.php');
954 $lineClassName = 'OrderLine';
955 } elseif ($fromElement == 'propal') {
956 dol_include_once('/comm/' . $fromElement . '/class/' . $fromElement . '.class.php');
957 $lineClassName = 'PropaleLigne';
958 } elseif ($fromElement == 'facture') {
959 dol_include_once('/compta/' . $fromElement . '/class/' . $fromElement . '.class.php');
960 $lineClassName = 'FactureLigne';
961 } else {
962 $lineClassName = null;
963 }
964 $nextRang = count($object->lines) + 1;
965 $importCount = 0;
966 $error = 0;
967 foreach ($importLines as $lineId) {
968 $lineId = intval($lineId);
969 $originLine = new $lineClassName($db);
970 if (intval($fromElementid) > 0 && $originLine->fetch($lineId) > 0) {
971 $originLine->fetch_optionals();
972 $desc = $originLine->desc;
973 $pu_ht = $originLine->subprice;
974 $qty = $originLine->qty;
975 $txtva = $originLine->tva_tx;
976 $txlocaltax1 = $originLine->localtax1_tx;
977 $txlocaltax2 = $originLine->localtax2_tx;
978 $fk_product = $originLine->fk_product;
979 $remise_percent = $originLine->remise_percent;
980 $date_start = $originLine->date_start;
981 $date_end = $originLine->date_end;
982 $fk_code_ventilation = 0;
983 $info_bits = $originLine->info_bits;
984 $fk_remise_except = $originLine->fk_remise_except;
985 $price_base_type = 'HT';
986 $pu_ttc = 0;
987 $type = $originLine->product_type;
988 $rang = $nextRang++;
989 $special_code = $originLine->special_code;
990 $origin = $originLine->element;
991 $origin_id = $originLine->id;
992 $fk_parent_line = 0;
993 $fk_fournprice = $originLine->fk_fournprice;
994 $pa_ht = $originLine->pa_ht;
995 $label = $originLine->label;
996 $array_options = $originLine->array_options;
997 $situation_percent = 100;
998 $fk_prev_id = '';
999 $fk_unit = $originLine->fk_unit;
1000 $pu_ht_devise = $originLine->multicurrency_subprice;
1001
1002 $res = $object->addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1, $txlocaltax2, $fk_product, $remise_percent, $price_base_type, $pu_ttc, $info_bits, $type, $rang, $special_code, $fk_parent_line, $fk_fournprice, $pa_ht, $label, $date_start, $date_end, $array_options, $fk_unit, $origin, $origin_id, $pu_ht_devise, $fk_remise_except);
1003
1004 if ($res > 0) {
1005 $importCount++;
1006 } else {
1007 $error++;
1008 }
1009 } else {
1010 $error++;
1011 }
1012 }
1013
1014 if ($error) {
1015 setEventMessages($langs->trans('ErrorsOnXLines', $error), null, 'errors');
1016 }
1017 }
1018 } elseif ($action == 'addline' && GETPOST('updateallvatlinesblock', 'alpha') && GETPOST('vatforblocklines', 'alpha') !== '' && $usercancreate) {
1019 $tx_tva = GETPOST('vatforblocklines') ? GETPOST('vatforblocklines') : 0;
1020 $result = $object->updateSubtotalLineBlockLines($langs, $object->getRangOfLine($lineid), 'tva', $tx_tva);
1021 if ($result < 0) {
1022 setEventMessages($object->error, $object->errors, 'errors');
1023 }
1024 } elseif ($action == 'addline' && GETPOST('updatealldiscountlinesblock', 'alpha') && GETPOST('discountforblocklines', 'alpha') !== '' && $usercancreate) {
1025 $discount = GETPOST('discountforblocklines') ? GETPOST('discountforblocklines') : 0;
1026 $result = $object->updateSubtotalLineBlockLines($langs, $object->getRangOfLine($lineid), 'discount', $discount);
1027 if ($result < 0) {
1028 setEventMessages($object->error, $object->errors, 'errors');
1029 }
1030 }
1031
1032 include DOL_DOCUMENT_ROOT . '/core/actions_printing.inc.php';
1033
1034 // Actions to send emails
1035 $actiontypecode = 'AC_EMAIL';
1036 $triggersendname = 'PROPAL_SENTBYMAIL';
1037 $autocopy = 'MAIN_MAIL_AUTOCOPY_PROPOSAL_TO';
1038 $trackid = 'pro' . $object->id;
1039 include DOL_DOCUMENT_ROOT . '/core/actions_sendmails.inc.php';
1040
1041
1042 // Go back to draft
1043 if ($action == 'modif' && $usercancreate) {
1044 $result = $object->setDraft($user);
1045 if ($result < 0) {
1046 setEventMessages($object->error, $object->errors, 'errors');
1047 }
1048
1049 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1050 // Define output language
1051 $outputlangs = $langs;
1052 if (getDolGlobalInt('MAIN_MULTILANGS')) {
1053 $outputlangs = new Translate("", $conf);
1054 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
1055 $outputlangs->setDefaultLang($newlang);
1056 }
1057 $ret = $object->fetch($id); // Reload to get new records
1058 if ($ret > 0) {
1059 $object->fetch_thirdparty();
1060 }
1061 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1062 }
1063 } elseif ($action == "setabsolutediscount" && $usercancreate) {
1064 if (GETPOSTINT("remise_id")) {
1065 if ($object->id > 0) {
1066 $result = $object->insert_discount(GETPOSTINT("remise_id"));
1067 if ($result < 0) {
1068 setEventMessages($object->error, $object->errors, 'errors');
1069 }
1070 }
1071 }
1072 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'aZ09') && (GETPOST('alldate_start', 'alpha') || GETPOST('alldate_end', 'alpha')) && $usercancreate) {
1073 // Define date start and date end for all line
1074 $alldate_start = dol_mktime(GETPOSTINT('alldate_starthour'), GETPOSTINT('alldate_startmin'), 0, GETPOSTINT('alldate_startmonth'), GETPOSTINT('alldate_startday'), GETPOSTINT('alldate_startyear'));
1075 $alldate_end = dol_mktime(GETPOSTINT('alldate_endhour'), GETPOSTINT('alldate_endmin'), 0, GETPOSTINT('alldate_endmonth'), GETPOSTINT('alldate_endday'), GETPOSTINT('alldate_endyear'));
1076 foreach ($object->lines as $key => $line) {
1077 if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
1078 continue;
1079 }
1080 if ($line->product_type == 1) { // only service line
1081 // Preserve the original entry mode of the line so the total is not drifted by rounding.
1082 $line_price_base_type = $line->getPriceBaseType();
1083 $line_pu = ($line_price_base_type === 'TTC') ? (float) $line->subprice_ttc : (float) $line->subprice;
1084 $result = $object->updateline($line->id, $line_pu, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, $line_price_base_type, $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $alldate_start, $alldate_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
1085 $object->lines[$key] = $object->line;
1086 }
1087 }
1088 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '' && $usercancreate) {
1089 // Define a vat_rate for all lines
1090 $vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0);
1091 $vat_rate = str_replace('*', '', $vat_rate);
1092 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
1093 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
1094 foreach ($object->lines as $key => $line) {
1095 if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
1096 continue;
1097 }
1098 // Preserve the original entry mode of the line so the total is not drifted by rounding.
1099 $line_price_base_type = $line->getPriceBaseType();
1100 $line_pu = ($line_price_base_type === 'TTC') ? (float) $line->subprice_ttc : (float) $line->subprice;
1101 $result = $object->updateline($line->id, $line_pu, $line->qty, $line->remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $line->desc, $line_price_base_type, $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
1102 $object->lines[$key] = $object->line;
1103 }
1104 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('remiseforalllines', 'alpha') !== '' && $usercancreate) {
1105 // Define a discount for all lines
1106 $remise_percent = (GETPOST('remiseforalllines') ? GETPOST('remiseforalllines') : 0);
1107 $remise_percent = str_replace('*', '', $remise_percent);
1108 foreach ($object->lines as $key => $line) {
1109 if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
1110 continue;
1111 }
1112 $tvatx = $line->tva_tx;
1113 if (!empty($line->vat_src_code)) {
1114 $tvatx .= ' (' . $line->vat_src_code . ')';
1115 }
1116 // Preserve the original entry mode of the line so the total is not drifted by rounding.
1117 $line_price_base_type = $line->getPriceBaseType();
1118 $line_pu = ($line_price_base_type === 'TTC') ? (float) $line->subprice_ttc : (float) $line->subprice;
1119 $result = $object->updateline($line->id, $line_pu, $line->qty, (float) $remise_percent, $tvatx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, $line_price_base_type, $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
1120 $object->lines[$key] = $object->line;
1121 }
1122 } elseif ($action == 'addline' && GETPOST('submitforallmargins', 'alpha') && GETPOST('marginforalllines', 'alpha') !== '' && $usercancreate) {
1123 // Define margin
1124 $margin_rate = (GETPOST('marginforalllines', 'alpha') ? GETPOST('marginforalllines', 'alpha') : 0);
1125 foreach ($object->lines as $key => $line) {
1126 if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
1127 continue;
1128 }
1129 $subprice = price2num($line->pa_ht * (1 + $margin_rate / 100), 'MU');
1130 $prod = new Product($db);
1131 $prod->fetch($line->fk_product);
1132 if ($prod->price_min > $subprice) {
1133 $price_subprice = price($subprice, 0, $outlangs, 1, -1, -1, 'auto');
1134 $price_price_min = price($prod->price_min, 0, $outlangs, 1, -1, -1, 'auto');
1135 setEventMessages($prod->ref . ' - ' . $prod->label . ' (' . $price_subprice . ' < ' . $price_price_min . ' ' . strtolower($langs->trans("MinPrice")) . ')' . "\n", null, 'warnings');
1136 }
1137 // Manage $line->subprice and $line->multicurrency_subprice
1138 if ($line->subprice <> 0) {
1139 $multicurrency_subprice = (float) $subprice * $line->multicurrency_subprice / $line->subprice;
1140 } else {
1141 $multicurrency_subprice = 0;
1142 }
1143 // Update DB
1144 $result = $object->updateline($line->id, (float) $subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $multicurrency_subprice);
1145 $object->lines[$key] = $object->line;
1146 // Update $object with new margin info
1147 // $line->price = $subprice;
1148 // $line->marge_tx = $margin_rate;
1149 // $line->marque_tx = $margin_rate * $line->pa_ht / (float) $subprice;
1150 // $line->total_ht = $line->qty * (float) $subprice;
1151 // $line->total_tva = $line->tva_tx * $line->qty * (float) $subprice;
1152 // $line->total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $subprice;
1153 // // Manage $line->subprice and $line->multicurrency_subprice
1154 // $line->multicurrency_total_ht = $line->qty * (float) $subprice * $line->multicurrency_subprice / $line->subprice;
1155 // $line->multicurrency_total_tva = $line->tva_tx * $line->qty * (float) $subprice * $line->multicurrency_subprice / $line->subprice;
1156 // $line->multicurrency_total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $subprice * $line->multicurrency_subprice / $line->subprice;
1157 // // Used previous $line->subprice and $line->multicurrency_subprice above, now they can be set to their new values
1158 // $line->subprice = (float) $subprice;
1159 // $line->multicurrency_subprice = $multicurrency_subprice;
1160 }
1161 } elseif ($action == 'confirm_addtextline' && $usercancreate) {
1162 // Handling adding a new text line for subtotals module
1163
1164 $langs->load('subtotals');
1165
1166 $desc = GETPOST('subtotaltextcontent', 'restricthtml');
1167
1168 // Insert line
1169 $result = $object->addSubtotalLine($langs, $desc, 0, array());
1170
1171 if ($result >= 0) {
1172 if ($result == 0) {
1173 setEventMessages($object->error, $object->errors, 'warnings');
1174 }
1175 $ret = $object->fetch($object->id); // Reload to get new records
1176 $object->fetch_thirdparty();
1177
1178 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1179 // Define output language
1180 $outputlangs = $langs;
1181 $newlang = GETPOST('lang_id', 'alpha');
1182 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1183 $newlang = $object->thirdparty->default_lang;
1184 }
1185 if (!empty($newlang)) {
1186 $outputlangs = new Translate("", $conf);
1187 $outputlangs->setDefaultLang($newlang);
1188 }
1189
1190 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1191 }
1192 } else {
1193 setEventMessages($object->error, $object->errors, 'errors');
1194 }
1195 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id);
1196 exit();
1197 } elseif ($action == 'confirm_addtitleline' && $usercancreate) {
1198 // Handling adding a new title line for subtotals module
1199
1200 $langs->load('subtotals');
1201
1202 $desc = GETPOST('subtotallinedesc', 'alphanohtml');
1203 $depth = GETPOSTINT('subtotallinelevel') ?? 1;
1204
1205 $subtotal_options = array();
1206
1207 foreach (Propal::$TITLE_OPTIONS as $option) {
1208 $value = GETPOST($option, 'alphanohtml');
1209 if ($value) {
1210 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
1211 }
1212 }
1213
1214 // Insert line
1215 $result = $object->addSubtotalLine($langs, $desc, (int) $depth, $subtotal_options);
1216
1217 if ($result >= 0) {
1218 if ($result == 0) {
1219 setEventMessages($object->error, $object->errors, 'warnings');
1220 }
1221 $ret = $object->fetch($object->id); // Reload to get new records
1222 $object->fetch_thirdparty();
1223
1224 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1225 // Define output language
1226 $outputlangs = $langs;
1227 $newlang = GETPOST('lang_id', 'alpha');
1228 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1229 $newlang = $object->thirdparty->default_lang;
1230 }
1231 if (!empty($newlang)) {
1232 $outputlangs = new Translate("", $conf);
1233 $outputlangs->setDefaultLang($newlang);
1234 }
1235
1236 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1237 }
1238 } else {
1239 setEventMessages($object->error, $object->errors, 'errors');
1240 }
1241 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id);
1242 exit();
1243 } elseif ($action == 'confirm_addsubtotalline' && $usercancreate) {
1244 // Handling adding a new subtotal line for subtotals module
1245
1246 $langs->load('subtotals');
1247
1248 $choosen_line = GETPOST('subtotaltitleline', 'alphanohtml');
1249 foreach ($object->lines as $line) {
1250 if ($line->desc == $choosen_line && $line->special_code == SUBTOTALS_SPECIAL_CODE) {
1251 $desc = $line->desc;
1252 $depth = -$line->qty;
1253 }
1254 }
1255
1256 $subtotal_options = array();
1257
1258 foreach (Propal::$SUBTOTAL_OPTIONS as $option) {
1259 $value = GETPOST($option, 'alphanohtml');
1260 if ($value) {
1261 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
1262 }
1263 }
1264
1265 // Insert line
1266 if (isset($desc) && isset($depth)) {
1267 $result = $object->addSubtotalLine($langs, $desc, (int) $depth, $subtotal_options);
1268 } else {
1269 $result = -1;
1270 $object->errors[] = $langs->trans("CorrespondingTitleNotFound");
1271 }
1272
1273 if ($result >= 0) {
1274 $ret = $object->fetch($object->id); // Reload to get new records
1275 $object->fetch_thirdparty();
1276
1277 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1278 // Define output language
1279 $outputlangs = $langs;
1280 $newlang = GETPOST('lang_id', 'alpha');
1281 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1282 $newlang = $object->thirdparty->default_lang;
1283 }
1284 if (!empty($newlang)) {
1285 $outputlangs = new Translate("", $conf);
1286 $outputlangs->setDefaultLang($newlang);
1287 }
1288
1289 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1290 }
1291 } else {
1292 setEventMessages($object->error, $object->errors, 'errors');
1293 }
1294 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id);
1295 exit();
1296 } elseif ($action == 'addline' && !GETPOST('submitforalllines', 'alpha') && !GETPOST('submitforallmargins', 'alpha') && !GETPOST('markforalllines', 'alpha') && $usercancreate) {
1297 // Add line
1298 // Set if we used free entry or predefined product
1299 $predef = '';
1300 $line_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
1301
1302 $price_ht = '';
1303 $price_ht_devise = '';
1304 $price_ttc = '';
1305 $price_ttc_devise = '';
1306
1307 // TODO Implement if (getDolGlobalInt('MAIN_UNIT_PRICE_WITH_TAX_IS_FOR_ALL_TAXES'))
1308
1309 if (GETPOST('price_ht') !== '') {
1310 $price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
1311 }
1312 if (GETPOST('multicurrency_price_ht') !== '') {
1313 $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
1314 }
1315 if (GETPOST('price_ttc') !== '') {
1316 $price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2);
1317 }
1318 if (GETPOST('multicurrency_price_ttc') !== '') {
1319 $price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2);
1320 }
1321
1322 $prod_entry_mode = GETPOST('prod_entry_mode', 'aZ09');
1323 if ($prod_entry_mode == 'free') {
1324 $idprod = 0;
1325 } else {
1326 $idprod = GETPOSTINT('idprod');
1327
1328 if (getDolGlobalString('MAIN_DISABLE_FREE_LINES') && $idprod <= 0) {
1329 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
1330 $error++;
1331 }
1332 }
1333
1334 $tva_tx = GETPOST('tva_tx', 'alpha');
1335
1336 $qty = price2num(GETPOST('qty' . $predef, 'alpha'), 'MS', 2);
1337 $remise_percent = (GETPOSTISSET('remise_percent' . $predef) ? price2num(GETPOST('remise_percent' . $predef, 'alpha'), '', 2) : 0);
1338 if (empty($remise_percent)) {
1339 $remise_percent = 0;
1340 }
1341
1342 // Extrafields
1343 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1344 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
1345 // Unset extrafield
1346 if (is_array($extralabelsline)) {
1347 // Get extra fields
1348 foreach ($extralabelsline as $key => $value) {
1349 unset($_POST["options_" . $key]);
1350 }
1351 }
1352
1353 $price_to_test_sign = ($price_ht ? $price_ht : $price_ttc);
1354
1355 if ((empty($idprod) || $idprod < 0) && ($price_to_test_sign < 0) && ($qty < 0)) {
1356 $langs->load("errors");
1357 setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
1358 $error++;
1359 }
1360 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
1361 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1362 $error++;
1363 }
1364
1365 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && $price_ht === '' && $price_ht_devise === '' && $price_ttc === '' && $price_ttc_devise === '') { // Unit price can be 0 but not ''. Also price can be negative for proposal.
1366 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
1367 $error++;
1368 }
1369 if ($qty < 0 && !getDolGlobalString('PROPAL_ENABLE_NEGATIVE_QTY')) {
1370 setEventMessages($langs->trans('FieldCannotBeNegative', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
1371 $error++;
1372 }
1373 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && empty($line_desc)) {
1374 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), null, 'errors');
1375 $error++;
1376 }
1377
1378 if (!$error && isModEnabled('variants') && $prod_entry_mode != 'free') {
1379 if ($combinations = GETPOST('combinations', 'array:alphanohtml')) {
1380 //Check if there is a product with the given combination
1381 $prodcomb = new ProductCombination($db);
1382
1383 if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
1384 $idprod = $res->fk_product_child;
1385 } else {
1386 setEventMessages($langs->trans('ErrorProductCombinationNotFound'), null, 'errors');
1387 $error++;
1388 }
1389 }
1390 }
1391
1392 if (!$error && (!empty($line_desc) || (!empty($idprod) && $idprod > 0))) {
1393 $pu_ht = 0;
1394 $pu_ttc = 0;
1395 $pu_ht_devise = 0;
1396 $pu_ttc_devise = 0;
1397 $price_min = 0;
1398 $price_min_ttc = 0;
1399 $tva_npr = 0;
1400 $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
1401
1402 $db->begin();
1403
1404 // $tva_tx can be 'x.x (XXX)'
1405
1406 // Ecrase $pu par celui du produit
1407 // Ecrase $desc par celui du produit
1408 // Replaces $fk_unit with the product unit
1409 if (!empty($idprod) && $idprod > 0) {
1410 $prod = new Product($db);
1411 $prod->fetch($idprod);
1412
1413 $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
1414
1415 // Update if prices fields are defined
1416 /*$tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id);
1417 $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id);
1418 if (empty($tva_tx)) {
1419 $tva_npr = 0;
1420 }*/
1421
1422 // Price unique per product
1423 $pu_ht = $prod->price;
1424 $pu_ttc = $prod->price_ttc;
1425 $price_min = $prod->price_min;
1426 $price_min_ttc = $prod->price_min_ttc;
1427 $price_base_type = $prod->price_base_type;
1428
1429 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1430 // If price per customer
1431 require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
1432 $prodcustprice = new ProductCustomerPrice($db);
1433 $filter = array('t.fk_product' => (string) $prod->id, 't.fk_soc' => (string) $object->thirdparty->id);
1434
1435 // If a price per customer exist
1436 $pricebycustomerexist = false;
1437 $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
1438 if ($result >= 0) {
1439 // If there is some prices specific to the customer
1440 if (count($prodcustprice->lines) > 0) {
1441 $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
1442 foreach ($prodcustprice->lines as $k => $custprice_line) {
1443 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
1444 $pricebycustomerexist = true;
1445 $pu_ht = price($custprice_line->price);
1446 $pu_ttc = price($custprice_line->price_ttc);
1447 $price_min = price($custprice_line->price_min);
1448 $price_min_ttc = price($custprice_line->price_min_ttc);
1449 $price_base_type = $custprice_line->price_base_type;
1450 /*$tva_tx = ($custprice_line->default_vat_code ? $custprice_line->tva_tx.' ('.$custprice_line->default_vat_code.' )' : $custprice_line->tva_tx);
1451 if ($custprice_line->default_vat_code && !preg_match('/\‍(.*\‍)/', $tva_tx)) {
1452 $tva_tx .= ' ('.$custprice_line->default_vat_code.')';
1453 }
1454 $tva_npr = $custprice_line->recuperableonly;
1455 if (empty($tva_tx)) {
1456 $tva_npr = 0;
1457 }*/
1458 break;
1459 }
1460 }
1461 }
1462 } else {
1463 setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
1464 }
1465
1466 if (!$pricebycustomerexist && !empty($object->thirdparty->price_level)) { // If price per segment
1467 $pu_ht = $prod->multiprices[$object->thirdparty->price_level];
1468 $pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
1469 $price_min = $prod->multiprices_min[$object->thirdparty->price_level];
1470 $price_min_ttc = $prod->multiprices_min_ttc[$object->thirdparty->price_level];
1471 $price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level];
1472 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
1473 if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) {
1474 $tva_tx = $prod->multiprices_tva_tx[$object->thirdparty->price_level];
1475 }
1476 if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) {
1477 $tva_npr = $prod->multiprices_recuperableonly[$object->thirdparty->price_level];
1478 }
1479 }
1480 }
1481 } elseif (getDolGlobalString('PRODUIT_MULTIPRICES') && !empty($object->thirdparty->price_level)) { // If price per segment
1482 $pu_ht = $prod->multiprices[$object->thirdparty->price_level];
1483 $pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
1484 $price_min = $prod->multiprices_min[$object->thirdparty->price_level];
1485 $price_min_ttc = $prod->multiprices_min_ttc[$object->thirdparty->price_level];
1486 $price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level];
1487 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
1488 if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) {
1489 $tva_tx = $prod->multiprices_tva_tx[$object->thirdparty->price_level];
1490 }
1491 if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) {
1492 $tva_npr = $prod->multiprices_recuperableonly[$object->thirdparty->price_level];
1493 }
1494 }
1495 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
1496 // If price per customer
1497 require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
1498
1499 $prodcustprice = new ProductCustomerPrice($db);
1500
1501 $filter = array('t.fk_product' => (string) $prod->id, 't.fk_soc' => (string) $object->thirdparty->id);
1502
1503 $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
1504 if ($result >= 0) {
1505 // If there is some prices specific to the customer
1506 if (count($prodcustprice->lines) > 0) {
1507 $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
1508 foreach ($prodcustprice->lines as $k => $custprice_line) {
1509 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
1510 $pu_ht = price($custprice_line->price);
1511 $pu_ttc = price($custprice_line->price_ttc);
1512 $price_min = price($custprice_line->price_min);
1513 $price_min_ttc = price($custprice_line->price_min_ttc);
1514 $price_base_type = $custprice_line->price_base_type;
1515 /*$tva_tx = ($custprice_line->default_vat_code ? $custprice_line->tva_tx.' ('.$custprice_line->default_vat_code.' )' : $custprice_line->tva_tx);
1516 if ($custprice_line->default_vat_code && !preg_match('/\‍(.*\‍)/', $tva_tx)) {
1517 $tva_tx .= ' ('.$custprice_line->default_vat_code.')';
1518 }
1519 $tva_npr = $custprice_line->recuperableonly;
1520 if (empty($tva_tx)) {
1521 $tva_npr = 0;
1522 }*/
1523 break;
1524 }
1525 }
1526 }
1527 } else {
1528 setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
1529 }
1530 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY')) {
1531 // If price per quantity
1532 if ($prod->prices_by_qty[0]) { // yes, this product has some prices per quantity
1533 // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
1534 $pqp = GETPOSTINT('pbq');
1535
1536 // Search price into product_price_by_qty from $prod->id
1537 foreach ($prod->prices_by_qty_list[0] as $priceforthequantityarray) {
1538 if ($priceforthequantityarray['rowid'] != $pqp) {
1539 continue;
1540 }
1541 // We found the price
1542 if ($priceforthequantityarray['price_base_type'] == 'HT') {
1543 $pu_ht = $priceforthequantityarray['unitprice'];
1544 } else {
1545 $pu_ttc = $priceforthequantityarray['unitprice'];
1546 }
1547 // Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
1548 break;
1549 }
1550 }
1551 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
1552 // If price per quantity and customer
1553 if ($prod->prices_by_qty[$object->thirdparty->price_level]) { // yes, this product has some prices per quantity
1554 // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
1555 $pqp = GETPOSTINT('pbq');
1556
1557 // Search price into product_price_by_qty from $prod->id
1558 foreach ($prod->prices_by_qty_list[$object->thirdparty->price_level] as $priceforthequantityarray) {
1559 if ($priceforthequantityarray['rowid'] != $pqp) {
1560 continue;
1561 }
1562 // We found the price
1563 if ($priceforthequantityarray['price_base_type'] == 'HT') {
1564 $pu_ht = $priceforthequantityarray['unitprice'];
1565 } else {
1566 $pu_ttc = $priceforthequantityarray['unitprice'];
1567 }
1568 // Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
1569 break;
1570 }
1571 }
1572 }
1573
1574 $tmpvat = (float) price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
1575 $tmpprodvat = (float) price2num(preg_replace('/\s*\‍(.*\‍)/', '', (string) $prod->tva_tx));
1576
1577 // Set unit price to use.
1578 // Force price_base_type to match what the user actually entered, so the total is computed
1579 // from the typed value and not from the converted/rounded value (avoids 0.01 rounding drift).
1580 if (!empty($price_ht) || (string) $price_ht === '0') {
1581 $pu_ht = (float) price2num($price_ht, 'MU');
1582 $pu_ttc = (float) price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
1583 $price_base_type = 'HT';
1584 } elseif (!empty($price_ht_devise) || (string) $price_ht_devise === '0') {
1585 $pu_ht_devise = price2num($price_ht_devise, 'MU');
1586 $pu_ttc_devise = (float) price2num((float) $pu_ht_devise * (1 + ((float) $tmpvat / 100)), 'MU');
1587 $pu_ht = '';
1588 $pu_ttc = '';
1589 $price_base_type = 'HT';
1590 } elseif (!empty($price_ttc) || (string) $price_ttc === '0') {
1591 $pu_ttc = (float) price2num($price_ttc, 'MU');
1592 $pu_ht = (float) price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
1593 $price_base_type = 'TTC';
1594 } elseif (!empty($price_ttc_devise) || (string) $price_ttc_devise === '0') {
1595 $pu_ttc_devise = (float) price2num($price_ttc_devise, 'MU');
1596 $pu_ht_devise = (float) price2num((float) $pu_ttc_devise / (1 + ((float) $tmpvat / 100)), 'MU');
1597 $pu_ht = '';
1598 $pu_ttc = '';
1599 $price_base_type = 'TTC';
1600 } elseif ($tmpvat != $tmpprodvat) {
1601 // Is this still used ?
1602 if ($price_base_type != 'HT') {
1603 $pu_ht = (float) price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
1604 } else {
1605 $pu_ttc = (float) price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
1606 }
1607 }
1608
1609 $desc = '';
1610
1611 // Define output language
1612 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1613 $outputlangs = $langs;
1614 $newlang = '';
1615 if (/* empty($newlang) && */GETPOST('lang_id', 'aZ09')) {
1616 $newlang = GETPOST('lang_id', 'aZ09');
1617 }
1618 if (empty($newlang)) {
1619 $newlang = $object->thirdparty->default_lang;
1620 }
1621 if (!empty($newlang)) {
1622 $outputlangs = new Translate("", $conf);
1623 $outputlangs->setDefaultLang($newlang);
1624 }
1625
1626 $desc = (!empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description;
1627 } else {
1628 $desc = $prod->description;
1629 }
1630
1631 if (getDolGlobalInt('PRODUIT_AUTOFILL_DESC') == 0) {
1632 // 'DoNotAutofillButAutoConcat'
1633 $desc = dol_concatdesc($desc, $line_desc, false, getDolGlobalString('MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION') ? true : false);
1634 } else {
1635 //'AutoFillFormFieldBeforeSubmit' or 'DoNotUseDescriptionOfProdut' => User has already done the modification they want
1636 $desc = $line_desc;
1637 }
1638
1639 // Add custom code and origin country into description
1640 if (!getDolGlobalString('MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE') && (!empty($prod->customcode) || !empty($prod->country_code))) {
1641 $tmptxt = '(';
1642 // Define output language
1643 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1644 $outputlangs = $langs;
1645 $newlang = '';
1646 if (/* empty($newlang) && */GETPOST('lang_id', 'alpha')) {
1647 $newlang = GETPOST('lang_id', 'alpha');
1648 }
1649 if (empty($newlang)) {
1650 $newlang = $object->thirdparty->default_lang;
1651 }
1652 if (!empty($newlang)) {
1653 $outputlangs = new Translate("", $conf);
1654 $outputlangs->setDefaultLang($newlang);
1655 $outputlangs->load('products');
1656 }
1657 if (!empty($prod->customcode)) {
1658 $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomsCode") . ': ' . $prod->customcode;
1659 }
1660 if (!empty($prod->customcode) && !empty($prod->country_code)) {
1661 $tmptxt .= ' - ';
1662 }
1663 if (!empty($prod->country_code)) {
1664 $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin") . ': ' . getCountry($prod->country_code, '', $db, $outputlangs, 0);
1665 }
1666 } else {
1667 if (!empty($prod->customcode)) {
1668 $tmptxt .= $langs->transnoentitiesnoconv("CustomsCode") . ': ' . $prod->customcode;
1669 }
1670 if (!empty($prod->customcode) && !empty($prod->country_code)) {
1671 $tmptxt .= ' - ';
1672 }
1673 if (!empty($prod->country_code)) {
1674 $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin") . ': ' . getCountry($prod->country_code, '', $db, $langs, 0);
1675 }
1676 }
1677 $tmptxt .= ')';
1678 $desc = dol_concatdesc($desc, $tmptxt);
1679 }
1680
1681 $type = $prod->type;
1682 $fk_unit = $prod->fk_unit;
1683 } else {
1684 $pu_ht = price2num($price_ht, 'MU');
1685 $pu_ttc = price2num($price_ttc, 'MU');
1686 $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
1687 $tva_tx = str_replace('*', '', $tva_tx);
1688 if (empty($tva_tx)) {
1689 $tva_npr = 0;
1690 }
1691 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1692 $desc = $line_desc;
1693 $type = GETPOST('type');
1694 $fk_unit = GETPOST('units', 'alpha');
1695 $pu_ht_devise = price2num($price_ht_devise, 'MU');
1696 $pu_ttc_devise = price2num($price_ttc_devise, 'MU');
1697
1698 if ($pu_ttc && !$pu_ht) {
1699 $price_base_type = 'TTC';
1700 }
1701 }
1702
1703 $info_bits = 0;
1704 if ($tva_npr) {
1705 $info_bits |= 0x01;
1706 }
1707
1708 // Local Taxes
1709 $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
1710 $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
1711
1712 // Margin
1713 $fournprice = (int) (GETPOST('fournprice' . $predef) ? GETPOST('fournprice' . $predef) : ''); // This can be id of supplier price, or 'pmpprice' or 'costprice', or 'inputprice', we force to keep ID only
1714 $buyingprice = price2num((GETPOST('buying_price' . $predef) != '' ? GETPOST('buying_price' . $predef) : ''), '', 2); // If buying_price is '0', we must keep this value
1715
1716 $date_start = dol_mktime(GETPOSTINT('date_start' . $predef . 'hour'), GETPOSTINT('date_start' . $predef . 'min'), GETPOSTINT('date_start' . $predef . 'sec'), GETPOSTINT('date_start' . $predef . 'month'), GETPOSTINT('date_start' . $predef . 'day'), GETPOSTINT('date_start' . $predef . 'year'));
1717 $date_end = dol_mktime(GETPOSTINT('date_end' . $predef . 'hour'), GETPOSTINT('date_end' . $predef . 'min'), GETPOSTINT('date_end' . $predef . 'sec'), GETPOSTINT('date_end' . $predef . 'month'), GETPOSTINT('date_end' . $predef . 'day'), GETPOSTINT('date_end' . $predef . 'year'));
1718
1719 // Prepare a price equivalent for minimum price check
1720 $pu_equivalent = $pu_ht;
1721 $pu_equivalent_ttc = $pu_ttc;
1722 $currency_tx = $object->multicurrency_tx;
1723
1724 // Check if we have a foreign currency
1725 // If so, we update the pu_equiv as the equivalent price in base currency
1726 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
1727 $pu_equivalent = (float) $pu_ht_devise / (float) $currency_tx;
1728 }
1729 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
1730 $pu_equivalent_ttc = (float) $pu_ttc_devise / (float) $currency_tx;
1731 }
1732
1733 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1734 /*
1735 if ($pu_equivalent) {
1736 $tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
1737 $pu_equivalent_ttc = ...
1738 } else {
1739 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $tva_tx, -1, -1, 0, 'TTC', $info_bits, $type);
1740 $pu_equivalent_ht = ...
1741 }
1742 */
1743
1744 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1745 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1746
1747 //$desc = dol_htmlcleanlastbr($desc);
1748
1749 // Check price is not lower than minimum
1750 if ($usermustrespectpricemin) {
1751 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
1752 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1753 setEventMessages($mesg, null, 'errors');
1754 $error++;
1755 } elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - $remise_percent / 100)) < (float) price2num($price_min_ttc)) && $price_base_type == 'TTC') {
1756 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1757 setEventMessages($mesg, null, 'errors');
1758 $error++;
1759 }
1760 }
1761
1762 if (!$error) {
1763 // Insert line
1764 $result = $object->addline($desc, $pu_ht, (float) $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $price_base_type, $pu_ttc, $info_bits, $type, min($rank, count($object->lines) + 1), 0, GETPOSTINT('fk_parent_line'), (int) $fournprice, $buyingprice, $label, $date_start, $date_end, $array_options, $fk_unit, '', 0, (float) $pu_ht_devise);
1765
1766 if ($result > 0) {
1767 $db->commit();
1768
1769 $ret = $object->fetch($object->id); // Reload to get new records
1770 if ($ret > 0) {
1771 $object->fetch_thirdparty();
1772 }
1773
1774 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1775 // Define output language
1776 $outputlangs = $langs;
1777 $newlang = GETPOST('lang_id', 'alpha');
1778 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1779 $newlang = $object->thirdparty->default_lang;
1780 }
1781 if (!empty($newlang)) {
1782 $outputlangs = new Translate("", $conf);
1783 $outputlangs->setDefaultLang($newlang);
1784 }
1785 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1786 }
1787
1788 unset($_POST['prod_entry_mode']);
1789
1790 unset($_POST['qty']);
1791 unset($_POST['type']);
1792 unset($_POST['remise_percent']);
1793 unset($_POST['price_ht']);
1794 unset($_POST['multicurrency_price_ht']);
1795 unset($_POST['price_ttc']);
1796 unset($_POST['tva_tx']);
1797 unset($_POST['product_ref']);
1798 unset($_POST['product_label']);
1799 unset($_POST['product_desc']);
1800 unset($_POST['fournprice']);
1801 unset($_POST['buying_price']);
1802 unset($_POST['np_marginRate']);
1803 unset($_POST['np_markRate']);
1804 unset($_POST['dp_desc']);
1805 unset($_POST['idprod']);
1806 unset($_POST['units']);
1807
1808 unset($_POST['date_starthour']);
1809 unset($_POST['date_startmin']);
1810 unset($_POST['date_startsec']);
1811 unset($_POST['date_startday']);
1812 unset($_POST['date_startmonth']);
1813 unset($_POST['date_startyear']);
1814 unset($_POST['date_endhour']);
1815 unset($_POST['date_endmin']);
1816 unset($_POST['date_endsec']);
1817 unset($_POST['date_endday']);
1818 unset($_POST['date_endmonth']);
1819 unset($_POST['date_endyear']);
1820
1821 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id);
1822 exit();
1823 } else {
1824 $db->rollback();
1825
1826 setEventMessages($object->error, $object->errors, 'errors');
1827 }
1828 }
1829 }
1830 } elseif ($action == 'addline' && $usercancreate && (
1831 (GETPOST('submitforallmargins', 'alpha') && GETPOST('marginforalllines', 'alpha') !== '') ||
1832 (GETPOST('submitforallmark', 'alpha') && GETPOST('markforalllines', 'alpha') !== '')
1833 )) {
1834 $outlangs = $langs;
1835 // Define margin
1836 $margin_rate = GETPOSTISSET('marginforalllines') ? GETPOST('marginforalllines', 'int') : '';
1837 $mark_rate = GETPOSTISSET('markforalllines') ? GETPOST('markforalllines', 'int') : '';
1838 foreach ($object->lines as &$line) {
1839 if ($line->subprice > 0) {
1840 if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
1841 continue;
1842 }
1843 $subprice_multicurrency = $line->subprice;
1844 if (is_numeric($margin_rate) && $margin_rate > 0) {
1845 $line->subprice = (float) price2num((float) $line->pa_ht * (1 + (float) $margin_rate / 100), 'MU');
1846 } elseif (is_numeric($mark_rate) && $mark_rate > 0) {
1847 $line->subprice = (float) ($line->pa_ht / (1 - ((float) $mark_rate / 100)));
1848 } else {
1849 $line->subprice = (float) $line->pa_ht;
1850 }
1851
1852 if ($line->fk_product > 0) {
1853 $prod = new Product($db);
1854 $res = $prod->fetch($line->fk_product);
1855 if ($res > 0) {
1856 if ($prod->price_min > $line->subprice) {
1857 $price_subprice = price($line->subprice, 0, $outlangs, 1, -1, -1, 'auto');
1858 $price_price_min = price($prod->price_min, 0, $outlangs, 1, -1, -1, 'auto');
1859 setEventMessages($prod->ref . ' - ' . $prod->label . ' (' . $price_subprice . ' < ' . $price_price_min . ' ' . strtolower($langs->trans("MinPrice")) . ')' . "\n", null, 'warnings');
1860 } else {
1861 setEventMessages($prod->error, $prod->errors, 'errors');
1862 }
1863 } else {
1864 setEventMessages($prod->error, $prod->errors, 'errors');
1865 }
1866 }
1867
1868 // Manage $line->subprice and $line->multicurrency_subprice
1869 $multicurrency_subprice = (float) $line->subprice * $line->multicurrency_subprice / $subprice_multicurrency;
1870 // Update DB
1871 $result = $object->updateline($line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $multicurrency_subprice);
1872 // Update $object with new margin info
1873 if ($result > 0) {
1874 if (is_numeric($margin_rate) && empty($mark_rate)) {
1875 $line->marge_tx = $margin_rate;
1876 } elseif (is_numeric($mark_rate) && empty($margin_rate)) {
1877 $line->marque_tx = $mark_rate;
1878 }
1879 $line->total_ht = $line->qty * (float) $line->subprice;
1880 $line->total_tva = $line->tva_tx * $line->qty * (float) $line->subprice;
1881 $line->total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $line->subprice;
1882 // Manage $line->subprice and $line->multicurrency_subprice
1883 $line->multicurrency_total_ht = $line->qty * (float) $subprice_multicurrency * $line->multicurrency_subprice / $line->subprice;
1884 $line->multicurrency_total_tva = $line->tva_tx * $line->qty * (float) $subprice_multicurrency * $line->multicurrency_subprice / $line->subprice;
1885 $line->multicurrency_total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $subprice_multicurrency * $line->multicurrency_subprice / $line->subprice;
1886 // Used previous $line->subprice and $line->multicurrency_subprice above, now they can be set to their new values
1887 $line->multicurrency_subprice = $multicurrency_subprice;
1888 } else {
1889 setEventMessages($object->error, $object->errors, 'errors');
1890 }
1891 }
1892 }
1893 } elseif ($action == 'updatetitleline' && GETPOSTISSET("save") && $usercancreate && !GETPOST('cancel', 'alpha')) {
1894 // Handling updating a title line for subtotals module
1895
1896 $langs->load('subtotals');
1897
1898 $desc = GETPOST('line_desc', 'alphanohtml') ?? $langs->trans("Title");
1899 $depth = GETPOSTINT('line_depth') ?? 1;
1900
1901 $subtotal_options = array();
1902
1903 foreach (Propal::$TITLE_OPTIONS as $option) {
1904 $value = GETPOST($option, 'alphanohtml');
1905 if ($value) {
1906 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
1907 }
1908 }
1909
1910 // Update line
1911 $result = $object->updateSubtotalLine($langs, GETPOSTINT('lineid'), $desc, $depth, $subtotal_options);
1912
1913 if ($result >= 0) {
1914 if ($result == 0) {
1915 setEventMessages($object->error, $object->errors, 'warnings');
1916 }
1917 $ret = $object->fetch($object->id); // Reload to get new records
1918 $object->fetch_thirdparty();
1919
1920 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1921 // Define output language
1922 $outputlangs = $langs;
1923 $newlang = GETPOST('lang_id', 'alpha');
1924 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1925 $newlang = $object->thirdparty->default_lang;
1926 }
1927 if (!empty($newlang)) {
1928 $outputlangs = new Translate("", $conf);
1929 $outputlangs->setDefaultLang($newlang);
1930 }
1931
1932 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1933 }
1934 } else {
1935 setEventMessages($object->error, $object->errors, 'errors');
1936 }
1937 } elseif ($action == 'updatetextline' && GETPOSTISSET("save") && $usercancreate && !GETPOST('cancel', 'alpha')) {
1938 // Handling updating a text line for subtotals module
1939
1940 $langs->load('subtotals');
1941
1942 $desc = GETPOST('line_desc', 'restricthtml');
1943
1944 // Update line
1945 $result = $object->updateSubtotalLine($langs, GETPOSTINT('lineid'), $desc, 0, array());
1946
1947 if ($result >= 0) {
1948 if ($result == 0) {
1949 setEventMessages($object->error, $object->errors, 'warnings');
1950 }
1951 $ret = $object->fetch($object->id); // Reload to get new records
1952 $object->fetch_thirdparty();
1953
1954 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1955 // Define output language
1956 $outputlangs = $langs;
1957 $newlang = GETPOST('lang_id', 'alpha');
1958 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1959 $newlang = $object->thirdparty->default_lang;
1960 }
1961 if (!empty($newlang)) {
1962 $outputlangs = new Translate("", $conf);
1963 $outputlangs->setDefaultLang($newlang);
1964 }
1965
1966 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1967 }
1968 } else {
1969 setEventMessages($object->error, $object->errors, 'errors');
1970 }
1971 } elseif ($action == 'updatesubtotalline' && GETPOSTISSET("save") && $usercancreate && !GETPOST('cancel', 'alpha')) {
1972 // Handling updating a subtotal line for subtotals module
1973
1974 $langs->load('subtotals');
1975
1976 $desc = GETPOST('line_desc', 'alphanohtml');
1977 $depth = GETPOSTINT('line_depth');
1978
1979 $subtotal_options = array();
1980
1981 foreach (Propal::$SUBTOTAL_OPTIONS as $option) {
1982 $value = GETPOST($option, 'alphanohtml');
1983 if ($value) {
1984 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
1985 }
1986 }
1987
1988 // Update line
1989 $result = $object->updateSubtotalLine($langs, GETPOSTINT('lineid'), $desc, $depth, $subtotal_options);
1990
1991 if ($result > 0) {
1992 $ret = $object->fetch($object->id); // Reload to get new records
1993 $object->fetch_thirdparty();
1994
1995 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1996 // Define output language
1997 $outputlangs = $langs;
1998 $newlang = GETPOST('lang_id', 'alpha');
1999 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
2000 $newlang = $object->thirdparty->default_lang;
2001 }
2002 if (!empty($newlang)) {
2003 $outputlangs = new Translate("", $conf);
2004 $outputlangs->setDefaultLang($newlang);
2005 }
2006
2007 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
2008 }
2009 } else {
2010 setEventMessages($object->error, $object->errors, 'errors');
2011 }
2012 } elseif ($action == 'updateline' && $usercancreate && GETPOST('save')) {
2013 // Update a line
2014
2015 // Clean parameters
2016 $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml'));
2017
2018 // Define info_bits
2019 $info_bits = 0;
2020 if (preg_match('/\*/', GETPOST('tva_tx'))) {
2021 $info_bits |= 0x01;
2022 }
2023
2024 // Define vat_rate
2025 $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx', 'alpha') : 0);
2026 $vat_rate = str_replace('*', '', $vat_rate);
2027 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
2028 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
2029 $pu_ht = price2num(GETPOST('price_ht'), '', 2);
2030 $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
2031
2032 // Add buying price
2033 $fournprice = (int) (GETPOST('fournprice') ? GETPOST('fournprice') : ''); // This can be id of supplier price, or 'pmpprice' or 'costprice', or 'inputprice', we force to keep ID only
2034 $buyingprice = price2num((GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''), '', 2); // If buying_price is '0', we must keep this value
2035
2036 $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
2037 $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
2038
2039 $date_start = dol_mktime(GETPOSTINT('date_starthour'), GETPOSTINT('date_startmin'), GETPOSTINT('date_startsec'), GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
2040 $date_end = dol_mktime(GETPOSTINT('date_endhour'), GETPOSTINT('date_endmin'), GETPOSTINT('date_endsec'), GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
2041
2042 $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
2043 if (empty($remise_percent)) {
2044 $remise_percent = 0;
2045 }
2046
2047 // Prepare a price equivalent for minimum price check
2048 $pu_equivalent = $pu_ht;
2049 $pu_equivalent_ttc = $pu_ttc;
2050
2051 $currency_tx = $object->multicurrency_tx;
2052
2053 // Check if we have a foreign currency
2054 // If so, we update the pu_equiv as the equivalent price in base currency
2055 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
2056 $pu_equivalent = (float) $pu_ht_devise / (float) $currency_tx;
2057 }
2058 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
2059 $pu_equivalent_ttc = (float) $pu_ttc_devise / (float) $currency_tx;
2060 }
2061
2062 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
2063 /*
2064 if ($pu_equivalent) {
2065 $tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
2066 $pu_equivalent_ttc = ...
2067 } else {
2068 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
2069 $pu_equivalent_ht = ...
2070 }
2071 */
2072
2073 // Extrafields
2074 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
2075 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
2076 // Unset extrafield
2077 if (is_array($extralabelsline)) {
2078 // Get extra fields
2079 foreach ($extralabelsline as $key => $value) {
2080 unset($_POST["options_" . $key]);
2081 }
2082 }
2083
2084 // Define special_code for special lines
2085 $special_code = GETPOSTINT('special_code');
2086 if (!GETPOST('qty')) {
2087 $special_code = 3;
2088 }
2089
2090 // The form JS clears the other field when the user edits one of them: only the modified field is filled.
2091 // When both fields are submitted, the user did not change the price - we must preserve the original
2092 // storage mode of the line, otherwise a no-op save would shift the total by rounding.
2093 $pu = $pu_ht;
2094 $price_base_type = 'HT';
2095 if (empty($pu_ht) && !empty($pu_ttc)) {
2096 $pu = $pu_ttc;
2097 $price_base_type = 'TTC';
2098 } elseif (!empty($pu_ht) && !empty($pu_ttc)) {
2099 foreach ($object->lines as $line_obj) {
2100 if ($line_obj->id == GETPOSTINT('lineid')) {
2101 if ($line_obj->wasEnteredIncludingTax()) {
2102 $pu = $pu_ttc;
2103 $price_base_type = 'TTC';
2104 }
2105 break;
2106 }
2107 }
2108 }
2109
2110 // Check minimum price
2111 $productid = GETPOSTINT('productid');
2112 if (!empty($productid)) {
2113 $product = new Product($db);
2114 $res = $product->fetch($productid);
2115
2116 $type = $product->type;
2117
2118 $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
2119
2120 $price_min = $product->price_min;
2121 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
2122 $price_min = $product->multiprices_min[$object->thirdparty->price_level];
2123 }
2124 $price_min_ttc = $product->price_min_ttc;
2125 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
2126 $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
2127 }
2128
2129 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
2130 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
2131
2132 // Check price is not lower than minimum
2133 if ($usermustrespectpricemin) {
2134 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
2135 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2136 setEventMessages($mesg, null, 'errors');
2137 $error++;
2138 $action = 'editline';
2139 } elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min_ttc)) && $price_base_type == 'TTC') {
2140 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2141 setEventMessages($mesg, null, 'errors');
2142 $error++;
2143 $action = 'editline';
2144 }
2145 }
2146 } else {
2147 $type = GETPOST('type');
2148 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
2149
2150 // Check parameters
2151 if (GETPOST('type') < 0) {
2152 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
2153 $error++;
2154 }
2155 }
2156
2157 if (!$error) {
2158 $db->begin();
2159
2160 if (!$user->hasRight('margins', 'creer')) {
2161 foreach ($object->lines as &$line) {
2162 if ($line->id == GETPOSTINT('lineid')) {
2163 $fournprice = $line->fk_fournprice;
2164 $buyingprice = (string) $line->pa_ht; // do not convert to float here, it breaks the functioning of $pa_ht_isemptystring
2165 break;
2166 }
2167 }
2168 }
2169
2170 $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
2171
2172 $result = $object->updateline(GETPOSTINT('lineid'), (float) $pu, (float) $qty, (float) $remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $description, $price_base_type, $info_bits, $special_code, GETPOSTINT('fk_parent_line'), 0, (int) $fournprice, $buyingprice, $label, $type, $date_start, $date_end, $array_options, GETPOSTINT("units"), (float) $pu_ht_devise);
2173
2174 if ($result >= 0) {
2175 $db->commit();
2176
2177 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
2178 // Define output language
2179 $outputlangs = $langs;
2180 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2181 $outputlangs = new Translate("", $conf);
2182 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
2183 $outputlangs->setDefaultLang($newlang);
2184 }
2185 $ret = $object->fetch($id); // Reload to get new records
2186 if ($ret > 0) {
2187 $object->fetch_thirdparty();
2188 }
2189 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
2190 }
2191
2192 unset($_POST['qty']);
2193 unset($_POST['type']);
2194 unset($_POST['productid']);
2195 unset($_POST['remise_percent']);
2196 unset($_POST['price_ht']);
2197 unset($_POST['multicurrency_price_ht']);
2198 unset($_POST['price_ttc']);
2199 unset($_POST['tva_tx']);
2200 unset($_POST['product_ref']);
2201 unset($_POST['product_label']);
2202 unset($_POST['product_desc']);
2203 unset($_POST['fournprice']);
2204 unset($_POST['buying_price']);
2205
2206 unset($_POST['date_starthour']);
2207 unset($_POST['date_startmin']);
2208 unset($_POST['date_startsec']);
2209 unset($_POST['date_startday']);
2210 unset($_POST['date_startmonth']);
2211 unset($_POST['date_startyear']);
2212 unset($_POST['date_endhour']);
2213 unset($_POST['date_endmin']);
2214 unset($_POST['date_endsec']);
2215 unset($_POST['date_endday']);
2216 unset($_POST['date_endmonth']);
2217 unset($_POST['date_endyear']);
2218 } else {
2219 $db->rollback();
2220
2221 setEventMessages($object->error, $object->errors, 'errors');
2222 }
2223 }
2224 } elseif ($action == 'updateline' && $usercancreate && GETPOST('cancel', 'alpha')) {
2225 header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // To re-display card in edit mode
2226 exit();
2227 } elseif ($action == 'classin' && $usercancreate) {
2228 // Set project
2229 $object->setProject(GETPOSTINT('projectid'));
2230 } elseif ($action == 'setavailability' && $usercancreate) {
2231 // Delivery time
2232 $result = $object->set_availability($user, GETPOSTINT('availability_id'));
2233 } elseif ($action == 'setdemandreason' && $usercancreate) {
2234 // Origin of the commercial proposal
2235 $result = $object->set_demand_reason($user, GETPOSTINT('demand_reason_id'));
2236 } elseif ($action == 'setconditions' && $usercancreate) {
2237 // Terms of payment
2238 $result = $object->setPaymentTerms(GETPOSTINT('cond_reglement_id'), GETPOSTFLOAT('cond_reglement_id_deposit_percent'));
2239 } elseif ($action == 'setmode' && $usercancreate) {
2240 // Payment choice
2241 $result = $object->setPaymentMethods(GETPOSTINT('mode_reglement_id'));
2242 } elseif ($action == 'setmulticurrencycode' && $usercancreate) {
2243 // Multicurrency Code
2244 $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
2245 } elseif ($action == 'setmulticurrencyrate' && $usercancreate) {
2246 // Multicurrency rate
2247 $result = $object->setMulticurrencyRate(GETPOSTFLOAT('multicurrency_tx'), GETPOSTINT('calculation_mode'));
2248 } elseif ($action == 'setbankaccount' && $usercancreate) {
2249 // bank account
2250 $result = $object->setBankAccount(GETPOSTINT('fk_account'));
2251 } elseif ($action == 'setshippingmethod' && $usercancreate) {
2252 // shipping method
2253 $result = $object->setShippingMethod(GETPOSTINT('shipping_method_id'));
2254 } elseif ($action == 'setwarehouse' && $usercancreate) {
2255 // warehouse
2256 $result = $object->setWarehouse(GETPOSTINT('warehouse_id'));
2257 } elseif ($action == 'update_extras' && $permissiontoeditextra) {
2258 $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty
2259
2260 $attribute_name = GETPOST('attribute', 'aZ09');
2261
2262 // Fill array 'array_options' with data from update form
2263 $result = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
2264 if ($result < 0) {
2265 $error++;
2266 }
2267
2268 if (!$error) {
2269 $result = $object->updateExtraField($attribute_name, 'PROPAL_MODIFY');
2270 if ($result < 0) {
2271 setEventMessages($object->error, $object->errors, 'errors');
2272 $error++;
2273 }
2274 }
2275 if ($error) {
2276 $action = 'edit_extras';
2277 }
2278 }
2279
2280 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
2281 if ($action == 'addcontact' && $usercancreate) {
2282 $result = 0;
2283 if ($object->id > 0) {
2284 $contactid = (GETPOST('userid') ? GETPOSTINT('userid') : GETPOSTINT('contactid'));
2285 $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
2286 $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
2287 }
2288
2289 if ($result >= 0) {
2290 header("Location: " . $_SERVER['PHP_SELF'] . "?id=" . $object->id);
2291 exit();
2292 } else {
2293 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
2294 $langs->load("errors");
2295 setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
2296 } else {
2297 setEventMessages($object->error, $object->errors, 'errors');
2298 }
2299 }
2300 } elseif ($action == 'swapstatut' && $usercancreate) {
2301 // Toggle the status of a contact
2302 if ($object->fetch($id) > 0) {
2303 $result = $object->swapContactStatus(GETPOSTINT('ligne'));
2304 } else {
2306 }
2307 } elseif ($action == 'deletecontact' && $usercancreate) {
2308 // Delete a contact
2309 $object->fetch($id);
2310 $result = $object->delete_contact($lineid);
2311
2312 if ($result >= 0) {
2313 header("Location: " . $_SERVER['PHP_SELF'] . "?id=" . $object->id);
2314 exit();
2315 } else {
2317 }
2318 }
2319 }
2320
2321 // Actions to build doc
2322 $upload_dir = !empty($conf->propal->multidir_output[$object->entity ?? $conf->entity]) ? $conf->propal->multidir_output[$object->entity ?? $conf->entity] : $conf->propal->dir_output;
2323 $permissiontoadd = $usercancreate;
2324 include DOL_DOCUMENT_ROOT . '/core/actions_builddoc.inc.php';
2325}
2326
2327
2328/*
2329 * View
2330 */
2331
2332$form = new Form($db);
2333$formfile = new FormFile($db);
2334$formpropal = new FormPropal($db);
2335$formmargin = new FormMargin($db);
2336$formproject = null;
2337if (isModEnabled('project')) {
2338 $formproject = new FormProjets($db);
2339}
2340
2341$title = $object->ref . " - " . $langs->trans('Card');
2342if ($action == 'create') {
2343 $title = $langs->trans("NewPropal");
2344}
2345$help_url = 'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos|DE:Modul_Angebote';
2346
2347llxHeader('', $title, $help_url);
2348
2349$now = dol_now();
2350
2351// Add new proposal
2352if ($action == 'create') {
2353 $currency_code = getDolCurrency();
2354
2355 print load_fiche_titre($langs->trans("NewProp"), '', 'propal');
2356
2357 $soc = new Societe($db);
2358 if ($socid > 0) {
2359 $res = $soc->fetch($socid);
2360 }
2361
2362 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
2363 $deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
2364 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
2365 $fk_account = GETPOSTINT('fk_account');
2366 $datepropal = (getDolGlobalString('MAIN_DO_NOT_AUTOFILL_DATE_PROPOSAL') ? -1 : ''); // By default '' so we will autofill date. -1 means keep empty.
2367
2368 // Load objectsrc
2369 $objectsrc = null;
2370 if (!empty($origin) && !empty($originid)) {
2371 // Parse element/subelement (ex: project_task)
2372 $element = $subelement = $origin;
2373 $regs = array();
2374 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
2375 $element = $regs[1];
2376 $subelement = $regs[2];
2377 }
2378
2379 if ($element == 'project') {
2380 $projectid = $originid;
2381
2382 // Fetch project and thirdparty
2383 $project = new Project($db);
2384 $project->fetch($projectid);
2385 if ($project->socid > 0) {
2386 $soc = new Societe($db);
2387 $soc->fetch($project->socid);
2388 }
2389 } else {
2390 // For compatibility
2391 if ($element == 'order' || $element == 'commande') {
2392 $element = $subelement = 'commande';
2393 }
2394 if ($element == 'propal') {
2395 $element = 'comm/propal';
2396 $subelement = 'propal';
2397 }
2398 if ($element == 'contract') {
2399 $element = $subelement = 'contrat';
2400 }
2401 if ($element == 'shipping') {
2402 $element = $subelement = 'expedition';
2403 }
2404
2405 dol_include_once('/' . $element . '/class/' . $subelement . '.class.php');
2406
2407 $classname = ucfirst($subelement);
2408 $objectsrc = new $classname($db);
2409 '@phan-var-force Commande|Propal|Contrat|Expedition $objectsrc'; // Can be other class, but CommonObject is too generic
2411 $objectsrc->fetch($originid);
2412 if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
2413 $objectsrc->fetch_lines();
2414 }
2415 $objectsrc->fetch_thirdparty();
2416
2417 $projectid = (int) $objectsrc->fk_project;
2418 $ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : '');
2419
2420 $soc = $objectsrc->thirdparty;
2421
2422 $cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0));
2423 $mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
2424 $warehouse_id = (!empty($objectsrc->warehouse_id) ? $objectsrc->warehouse_id : (!empty($soc->warehouse_id) ? $soc->warehouse_id : -1));
2425
2426 // Replicate extrafields
2427 $objectsrc->fetch_optionals();
2428 $object->array_options = $objectsrc->array_options;
2429
2430 if (isModEnabled("multicurrency")) {
2431 if (!empty($objectsrc->multicurrency_code)) {
2432 $currency_code = $objectsrc->multicurrency_code;
2433 }
2434 if (getDolGlobalString('MULTICURRENCY_USE_ORIGIN_TX') && !empty($objectsrc->multicurrency_tx)) {
2435 $currency_tx = $objectsrc->multicurrency_tx;
2436 }
2437 }
2438 }
2439 }
2440
2441 // Load default values from thirdparty
2442 if (!empty($soc)) {
2443 $cond_reglement_id = empty($soc->cond_reglement_id) ? $cond_reglement_id : $soc->cond_reglement_id;
2444 $deposit_percent = empty($soc->deposit_percent) ? $deposit_percent : $soc->deposit_percent;
2445 $mode_reglement_id = empty($soc->mode_reglement_id) ? $mode_reglement_id : $soc->mode_reglement_id;
2446 $fk_account = empty($soc->fk_account) ? $fk_account : $soc->fk_account;
2447 $shipping_method_id = $soc->shipping_method_id;
2448 $warehouse_id = !empty($soc->fk_warehouse) ? $soc->fk_warehouse : $warehouse_id;
2449 $remise_percent = $soc->remise_percent;
2450
2451 if (isModEnabled("multicurrency") && !empty($soc->multicurrency_code)) {
2452 $currency_code = $soc->multicurrency_code;
2453 }
2454 }
2455
2456 // If form was posted (but error returned), we must reuse the value posted in priority (standard Dolibarr behaviour)
2457 if (!GETPOST('changecompany')) {
2458 if (GETPOSTISSET('cond_reglement_id')) {
2459 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
2460 }
2461 if (GETPOSTISSET('deposit_percent')) {
2462 $deposit_percent = price2num(GETPOST('deposit_percent', 'alpha'));
2463 }
2464 if (GETPOSTISSET('mode_reglement_id')) {
2465 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
2466 }
2467 if (GETPOSTISSET('fk_account')) {
2468 $fk_account = GETPOSTINT('fk_account');
2469 }
2470 if (GETPOSTISSET('shipping_method_id')) {
2471 $shipping_method_id = GETPOSTINT('shipping_method_id');
2472 }
2473 }
2474 // Warehouse default if null
2475 if ($soc->fk_warehouse > 0) {
2476 $warehouse_id = $soc->fk_warehouse;
2477 }
2478 if (isModEnabled('stock') && $warehouse_id < 0 && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
2479 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE')) {
2480 $warehouse_id = getDolGlobalString('MAIN_DEFAULT_WAREHOUSE');
2481 }
2482 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER') && !empty($user->fk_warehouse)) {
2483 $warehouse_id = $user->fk_warehouse;
2484 }
2485 }
2486
2487 print '<form name="addprop" action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
2488 print '<input type="hidden" name="token" value="' . newToken() . '">';
2489 print '<input type="hidden" name="action" value="add">';
2490 print '<input type="hidden" name="changecompany" value="0">'; // will be set to 1 by javascript so we know post is done after a company change
2491 print '<input type="hidden" name="backtopage" value="' . $backtopage . '">';
2492 if ($origin != 'project' && $originid) {
2493 print '<input type="hidden" name="origin" value="' . $origin . '">';
2494 print '<input type="hidden" name="originid" value="' . $originid . '">';
2495 if ($origin == 'contrat' && !empty($renewal)) {
2496 print '<input type="hidden" name="renewal" value="' . $renewal . '">';
2497 }
2498 } elseif ($origin == 'project' && !empty($projectid)) {
2499 print '<input type="hidden" name="projectid" value="' . $projectid . '">';
2500 }
2501
2502 print dol_get_fiche_head();
2503
2504 // Call Hook tabContentCreateProposal
2505 $parameters = array();
2506 // Note that $action and $object may be modified by hook
2507 $reshook = $hookmanager->executeHooks('tabContentCreateProposal', $parameters, $object, $action);
2508 if (empty($reshook)) {
2509 print '<table class="border centpercent">';
2510
2511 // Reference
2512 //print '<tr class="field_ref"><td class="titlefieldcreate fieldrequired">' . $langs->trans('Ref') . '</td><td class="valuefieldcreate">' . $langs->trans("Draft") . '</td></tr>';
2513
2514 // Third party
2515 print '<tr class="field_socid">';
2516
2517 print '<td class="titlefieldcreate fieldrequired">' . $langs->trans('Customer') . '</td>';
2518 $shipping_method_id = 0;
2519 $warehouse_id = 0;
2520
2521 if ($socid > 0) {
2522 print '<td class="valuefieldcreate">';
2523 print $soc->getNomUrl(1, 'customer');
2524 print '<input type="hidden" name="socid" value="' . $soc->id . '">';
2525 print '</td>';
2526 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
2527 $shipping_method_id = $soc->shipping_method_id;
2528 }
2529 } else {
2530 print '<td class="valuefieldcreate">';
2531 $filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
2532 print img_picto('', 'company', 'class="pictofixedwidth"');
2533 print $form->select_company('', 'socid', $filter, 'SelectThirdParty', 1, 0, array(), 0, 'minwidth300 maxwidth500 widthcentpercentminusxx');
2534 // reload page to retrieve customer information
2535 if (!getDolGlobalString('RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED')) {
2536 print '<script>
2537 $(document).ready(function() {
2538 $("#socid").change(function() {
2539 console.log("We have changed the company - Reload page");
2540 var socid = $(this).val();
2541 // reload page
2542 $("input[name=action]").val("create");
2543 $("input[name=changecompany]").val("1");
2544 $("form[name=addprop]").submit();
2545 });
2546 });
2547 </script>';
2548 }
2549 print ' <a href="' . DOL_URL_ROOT . '/societe/card.php?action=create&prospect=3&fournisseur=0&backtopage=' . urlencode($_SERVER["PHP_SELF"] . '?action=create') . '"><span class="fa fa-plus-circle valignmiddle paddingleft" title="' . $langs->trans("AddThirdParty") . '"></span></a>';
2550 print '</td>';
2551 }
2552 print '</tr>' . "\n";
2553
2554 // Reference of proposal on customer side
2555 if (getDolGlobalString('MAIN_ASK_CUSTOMER_REF_OF_PROPOSAL_AT_CREATION')) {
2556 print '<tr class="field_ref_client"><td class="titlefieldcreate">';
2557 print $form->textwithpicto($langs->trans('RefCustomer'), $langs->trans('RefOfOnCustomerSide', $langs->transnoentitiesnoconv("Proposal")));
2558 print '</td><td class="valuefieldcreate">';
2559 print '<input type="text" name="ref_client" value="' . (!empty($ref_client) ? $ref_client : GETPOST('ref_client')) . '"></td>';
2560 print '</tr>';
2561 }
2562
2563 if ($socid > 0) {
2564 // Contacts (ask contact only if thirdparty already defined).
2565 print '<tr class="field_contactid"><td class="titlefieldcreate">' . $langs->trans("DefaultContact") . '</td><td class="valuefieldcreate">';
2566 print img_picto('', 'contact', 'class="pictofixedwidth"');
2567 //print $form->selectcontacts($soc->id, $contactid, 'contactid', 1, '', '', 0, 'minwidth300 widthcentpercentminusx');
2568 print $form->select_contact($soc->id, $contactid, 'contactid', 1, '', '', 1, 'maxwidth300 widthcentpercentminusx', true);
2569 print '</td></tr>';
2570
2571 // Third party discounts info line
2572 print '<tr class="field_discount_info"><td class="titlefieldcreate">' . $langs->trans('Discounts') . '</td><td class="valuefieldcreate">';
2573
2574 $absolute_discount = $soc->getAvailableDiscounts();
2575
2576 $thirdparty = $soc;
2577 $discount_type = 0;
2578 $backtopage = $_SERVER["PHP_SELF"] . '?socid=' . $thirdparty->id . '&action=' . $action . '&origin=' . urlencode((string) (GETPOST('origin'))) . '&originid=' . urlencode((string) (GETPOSTINT('originid')));
2579 include DOL_DOCUMENT_ROOT . '/core/tpl/object_discounts.tpl.php';
2580 print '</td></tr>';
2581 }
2582
2583 $newdatepropal = dol_mktime(0, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'), 'tzserver');
2584 // Date
2585 print '<tr class="field_addprop"><td class="titlefieldcreate fieldrequired">' . $langs->trans('Date') . '</td><td class="valuefieldcreate">';
2586 print img_picto('', 'action', 'class="pictofixedwidth"');
2587 print $form->selectDate($newdatepropal ? $newdatepropal : $datepropal, '', 0, 0, 0, "addprop", 1, 1);
2588 print '</td></tr>';
2589
2590 // Validaty duration
2591 print '<tr class="field_duree_validitee"><td class="titlefieldcreate fieldrequired">' . $langs->trans("ValidityDuration") . '</td><td class="valuefieldcreate">' . img_picto('', 'clock', 'class="pictofixedwidth"') . '<input name="duree_validite" class="width50" value="' . (GETPOSTISSET('duree_validite') ? GETPOST('duree_validite', 'alphanohtml') : getDolGlobalString('PROPALE_VALIDITY_DURATION')) . '"> ' . $langs->trans("days") . '</td></tr>';
2592
2593 // Terms of payment
2594 print '<tr class="field_cond_reglement_id"><td class="nowrap">' . $langs->trans('PaymentConditionsShort') . '</td><td>';
2595 print img_picto('', 'payment', 'class="pictofixedwidth"');
2596 // at last resort we take the payment term id which may be filled by default values set (if not getpostisset)
2597 print $form->getSelectConditionsPaiements((int) $cond_reglement_id, 'cond_reglement_id', 1, 1, 0, '', $deposit_percent);
2598 print '</td></tr>';
2599
2600 // Mode of payment
2601 print '<tr class="field_mode_reglement_id"><td class="titlefieldcreate">' . $langs->trans('PaymentMode') . '</td><td class="valuefieldcreate">';
2602 print img_picto('', 'bank', 'class="pictofixedwidth"');
2603 print $form->select_types_paiements((string) $mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
2604 print '</td></tr>';
2605
2606 // Bank Account
2607 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
2608 print '<tr class="field_fk_account"><td class="titlefieldcreate">' . $langs->trans('BankAccount') . '</td><td class="valuefieldcreate">';
2609 print img_picto('', 'bank_account', 'class="pictofixedwidth"') . $form->select_comptes((int) $fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
2610 print '</td></tr>';
2611 }
2612
2613 // Source / Channel - What trigger creation
2614 print '<tr class="field_demand_reason_id"><td class="titlefieldcreate">' . $langs->trans('Source') . '</td><td class="valuefieldcreate">';
2615 print img_picto('', 'question', 'class="pictofixedwidth"');
2616 $form->selectInputReason((GETPOSTISSET('demand_reason_id') ? GETPOSTINT('demand_reason_id') : ''), 'demand_reason_id', "SRC_PROP", 1, 'maxwidth200 widthcentpercentminusx');
2617 print '</td></tr>';
2618
2619 // Shipping Method
2620 if (isModEnabled("shipping")) {
2621 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
2622 $shipping_method_id = $soc->shipping_method_id;
2623 }
2624 print '<tr class="field_shipping_method_id"><td class="titlefieldcreate">' . $langs->trans('SendingMethod') . '</td><td class="valuefieldcreate">';
2625 print img_picto('', 'dolly', 'class="pictofixedwidth"');
2626 $form->selectShippingMethod((string) $shipping_method_id, 'shipping_method_id', '', 1, '', 0, 'maxwidth200 widthcentpercentminusx');
2627 print '</td></tr>';
2628 }
2629
2630 $formproduct = null;
2631 // Warehouse
2632 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
2633 require_once DOL_DOCUMENT_ROOT . '/product/class/html.formproduct.class.php';
2634 $formproduct = new FormProduct($db);
2635 print '<tr class="field_warehouse_id"><td class="titlefieldcreate">' . $langs->trans('Warehouse') . '</td><td class="valuefieldcreate">';
2636 print img_picto('', 'stock', 'class="pictofixedwidth"') . $formproduct->selectWarehouses((int) $warehouse_id, 'warehouse_id', '', 1, 0, 0, '', 0, 0, array(), 'maxwidth500 widthcentpercentminusxx');
2637 print '</td></tr>';
2638 }
2639
2640 // Delivery delay
2641 print '<tr class="field_availability_id"><td class="titlefieldcreate">' . $langs->trans('AvailabilityPeriod');
2642 if (isModEnabled('order')) {
2643 print ' (' . $langs->trans('AfterOrder') . ')';
2644 }
2645 print '</td><td class="valuefieldcreate">';
2646 print img_picto('', 'clock', 'class="pictofixedwidth"');
2647 print $form->selectAvailabilityDelay((GETPOSTISSET('availability_id') ? GETPOSTINT('availability_id') : ''), 'availability_id', '', 1, 'maxwidth200 widthcentpercentminusx', 1);
2648 print '</td></tr>';
2649
2650 // Delivery date (or manufacturing)
2651 print '<tr class="field_date_livraison"><td class="titlefieldcreate">' . $langs->trans("DeliveryDate") . '</td>';
2652 print '<td class="valuefieldcreate">';
2653 print img_picto('', 'action', 'class="pictofixedwidth"');
2654 if (is_numeric(getDolGlobalString('DATE_LIVRAISON_WEEK_DELAY'))) { // If value set to 0 or a num, not empty
2655 $tmpdte = time() + (7 * getDolGlobalInt('DATE_LIVRAISON_WEEK_DELAY') * 24 * 60 * 60);
2656 $syear = date("Y", $tmpdte);
2657 $smonth = date("m", $tmpdte);
2658 $sday = date("d", $tmpdte);
2659 print $form->selectDate($syear . "-" . $smonth . "-" . $sday, 'date_livraison', 0, 0, 0, "addprop");
2660 } else {
2661 $tmp_date_delivery = GETPOST('date_delivery') ?: -1;
2662 print $form->selectDate($tmp_date_delivery, 'date_livraison', 0, 0, 0, "addprop", 1, 1);
2663 }
2664 print '</td></tr>';
2665
2666 // Project
2667 if (isModEnabled('project') && is_object($formproject)) {
2668 $langs->load("projects");
2669 print '<tr class="field_projectid">';
2670 print '<td class="titlefieldcreate">'.$langs->trans("Project").'</td><td class="valuefieldcreate">';
2671 print img_picto('', 'project', 'class="pictofixedwidth"').$formproject->select_projects((($soc->id > 0 && !getDolGlobalString('PROJECT_CAN_ALWAYS_LINK_TO_ALL_CUSTOMERS')) ? $soc->id : -1), (string) $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500 widthcentpercentminusxx');
2672 print ' <a href="'.DOL_URL_ROOT.'/projet/card.php?socid='.$soc->id.'&action=create&status=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create&socid='.$soc->id).'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddProject").'"></span></a>';
2673 print '</td>';
2674 print '</tr>';
2675 }
2676
2677 // Incoterms
2678 if (isModEnabled('incoterm')) {
2679 print '<tr class="field_incoterm_id">';
2680 print '<td class="titlefieldcreate"><label for="incoterm_id">' . $form->textwithpicto($langs->trans("IncotermLabel"), $soc->label_incoterms, 1) . '</label></td>';
2681 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2682 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
2683 print $form->select_incoterms((!empty($soc->fk_incoterms) ? $soc->fk_incoterms : ''), (!empty($soc->location_incoterms) ? $soc->location_incoterms : ''));
2684 print '</td></tr>';
2685 }
2686 if (isModEnabled('category')) {
2687 // Categories
2688 print '<tr><td>'.$langs->trans("Categories").'</td><td colspan="3">';
2689 print $form->selectCategories(Categorie::TYPE_PROPOSAL, 'categories', $object);
2690 print "</td></tr>";
2691 }
2692 // Template to use by default
2693 include_once DOL_DOCUMENT_ROOT . '/core/modules/propale/modules_propale.php';
2695 if (is_array($list) && count($list) > 0) {
2696 print '<tr class="field_model">';
2697 print '<td class="titlefieldcreate">' . $langs->trans("DefaultModel") . '</td>';
2698 print '<td class="valuefieldcreate">';
2699 print img_picto('', 'pdf', 'class="pictofixedwidth"');
2700 $preselected = getDolGlobalString('PROPALE_ADDON_PDF_ODT_DEFAULT', getDolGlobalString("PROPALE_ADDON_PDF"));
2701 print $form->selectarray('model', $list, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
2702 print "</td></tr>";
2703 }
2704
2705 // Multicurrency
2706 if (isModEnabled("multicurrency")) {
2707 print '<tr class="field_currency">';
2708 print '<td class="titlefieldcreate">' . $form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0) . '</td>';
2709 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2710 print img_picto('', 'currency', 'class="pictofixedwidth"') . $form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0, '', false, 'maxwidth200 widthcentpercentminusx');
2711 print '</td></tr>';
2712 }
2713
2714 // Public note
2715 print '<tr class="field_note_public">';
2716 print '<td class="titlefieldcreate tdtop">' . $langs->trans('NotePublic') . '</td>';
2717 print '<td class="valuefieldcreate">';
2718 $note_public = GETPOST('note_public', 'restricthtml');
2719 if (!GETPOSTISSET('note_public') && empty($note_public) && !empty($objectsrc)) {
2720 $note_public = $objectsrc->note_public;
2721 }
2722 $doleditor = new DolEditor('note_public', (string) $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
2723 print $doleditor->Create(1);
2724
2725 // Private note
2726 if (empty($user->socid)) {
2727 print '<tr class="field_note_private">';
2728 print '<td class="titlefieldcreate tdtop">' . $langs->trans('NotePrivate') . '</td>';
2729 print '<td class="valuefieldcreate">';
2730 $note_private = GETPOST('note_private', 'restricthtml');
2731 if (!GETPOSTISSET('note_private') && empty($note_private) && !empty($objectsrc)) {
2732 $note_private = $objectsrc->note_private;
2733 }
2734 $doleditor = new DolEditor('note_private', (string) $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
2735 print $doleditor->Create(1);
2736 // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
2737 print '</td></tr>';
2738 }
2739
2740 // Other attributes
2741 if (getDolGlobalInt('THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_PROPAL') && $socid > 0) {
2742 $thirdpartytopropagateextrafieldsfrom = $soc;
2743 }
2744 include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_add.tpl.php';
2745
2746 // Lines from source
2747 if (!empty($origin) && !empty($originid) && is_object($objectsrc) && !empty($classname)) {
2748 // TODO for compatibility
2749 if ($origin == 'contrat') {
2750 // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
2751 $objectsrc->update_price(1, 'auto', 1);
2752 }
2753
2754 print "\n<!-- " . $classname . " info -->";
2755 print "\n";
2756 print '<input type="hidden" name="amount" value="' . $objectsrc->total_ht . '">' . "\n";
2757 print '<input type="hidden" name="total" value="' . $objectsrc->total_ttc . '">' . "\n";
2758 print '<input type="hidden" name="tva" value="' . $objectsrc->total_tva . '">' . "\n";
2759 print '<input type="hidden" name="origin" value="' . $objectsrc->element . '">';
2760 print '<input type="hidden" name="originid" value="' . $objectsrc->id . '">';
2761
2762 $newclassname = $classname;
2763 if ($newclassname == 'Propal') {
2764 $newclassname = 'CommercialProposal';
2765 } elseif ($newclassname == 'Commande') {
2766 $newclassname = 'Order';
2767 } elseif ($newclassname == 'Expedition') {
2768 $newclassname = 'Sending';
2769 } elseif ($newclassname == 'Fichinter') {
2770 $newclassname = 'Intervention';
2771 }
2772
2773 print '<tr><td>' . $langs->trans($newclassname) . '</td><td>' . $objectsrc->getNomUrl(1) . '</td></tr>';
2774 print '<tr><td>' . $langs->trans('AmountHT') . '</td><td>' . price($objectsrc->total_ht, 0, $langs, 1, -1, -1, $conf->currency) . '</td></tr>';
2775 print '<tr><td>' . $langs->trans('AmountVAT') . '</td><td>' . price($objectsrc->total_tva, 0, $langs, 1, -1, -1, $conf->currency) . "</td></tr>";
2776 if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
2777 print '<tr><td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td><td>' . price($objectsrc->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency) . "</td></tr>";
2778 }
2779
2780 if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
2781 print '<tr><td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td><td>' . price($objectsrc->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency) . "</td></tr>";
2782 }
2783 print '<tr><td>' . $langs->trans('AmountTTC') . '</td><td>' . price($objectsrc->total_ttc, 0, $langs, 1, -1, -1, $conf->currency) . "</td></tr>";
2784
2785 if (isModEnabled("multicurrency")) {
2786 print '<tr><td>' . $langs->trans('MulticurrencyAmountHT') . '</td><td>' . price($objectsrc->multicurrency_total_ht) . '</td></tr>';
2787 print '<tr><td>' . $langs->trans('MulticurrencyAmountVAT') . '</td><td>' . price($objectsrc->multicurrency_total_tva) . "</td></tr>";
2788 print '<tr><td>' . $langs->trans('MulticurrencyAmountTTC') . '</td><td>' . price($objectsrc->multicurrency_total_ttc) . "</td></tr>";
2789 }
2790 }
2791
2792 print "</table>\n";
2793
2794
2795 /*
2796 * Combobox for copy function
2797 */
2798
2799 if (!getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2800 print '<input type="hidden" name="createmode" value="empty">';
2801 }
2802
2803 if (getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2804 print '<br><table>';
2805
2806 // For backward compatibility
2807 print '<tr>';
2808 print '<td><input type="radio" name="createmode" value="copy"></td>';
2809 print '<td>' . $langs->trans("CopyPropalFrom") . ' </td>';
2810 print '<td>';
2811 $liste_propal = array();
2812 $liste_propal[0] = '';
2813
2814 $sql = "SELECT p.rowid as id, p.ref, s.nom";
2815 $sql .= " FROM " . MAIN_DB_PREFIX . "propal p";
2816 $sql .= ", " . MAIN_DB_PREFIX . "societe s";
2817 $sql .= " WHERE s.rowid = p.fk_soc";
2818 $sql .= " AND p.entity IN (" . getEntity('propal') . ")";
2819 $sql .= " AND p.fk_statut <> 0";
2820 $sql .= " ORDER BY Id";
2821
2822 $resql = $db->query($sql);
2823 if ($resql) {
2824 $num = $db->num_rows($resql);
2825 $i = 0;
2826 while ($i < $num) {
2827 $row = $db->fetch_row($resql);
2828 $propalRefAndSocName = $row[1] . " - " . $row[2];
2829 $liste_propal[$row[0]] = $propalRefAndSocName;
2830 $i++;
2831 }
2832 print $form->selectarray("copie_propal", $liste_propal, 0);
2833 } else {
2835 }
2836 print '</td></tr>';
2837
2838 print '<tr><td class="tdtop"><input type="radio" name="createmode" value="empty" checked></td>';
2839 print '<td valign="top" colspan="2">' . $langs->trans("CreateEmptyPropal") . '</td></tr>';
2840 print '</table>';
2841 }
2842 }
2843
2844 print dol_get_fiche_end();
2845
2846 $langs->load("bills");
2847
2848 print $form->buttonsSaveCancel("CreateDraft");
2849
2850 print "</form>";
2851
2852
2853 // Show origin lines
2854 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2855 print '<br>';
2856
2857 $title = $langs->trans('ProductsAndServices');
2858 print load_fiche_titre($title);
2859
2860 print '<div class="div-table-responsive-no-min">';
2861 print '<table class="noborder centpercent">';
2862
2863 $objectsrc->printOriginLinesList();
2864
2865 print '</table>';
2866 print '</div>';
2867 }
2868} elseif ($object->id > 0) {
2869 /*
2870 * Show object in view mode
2871 */
2872 $object->fetch_thirdparty();
2873 if ($object->thirdparty) {
2874 $soc = $object->thirdparty;
2875 } else {
2876 $soc = new Societe($db);
2877 }
2878
2879 $head = propal_prepare_head($object);
2880 print dol_get_fiche_head($head, 'comm', $langs->trans('Proposal'), -1, $object->picto, 0, '', '', 0, '', 1);
2881
2882 $formconfirm = '';
2883
2884 // Clone confirmation
2885 if ($action == 'clone') {
2886 // Create an array for form
2887 $filter = '(s.client:IN:1,2,3)';
2888 $formquestion = array(
2889 // 'text' => $langs->trans("ConfirmClone"),
2890 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
2891 array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOSTINT('socid'), 'socid', $filter, '', 0, 0, array(), 0, 'maxwidth300')),
2892 array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => 0),
2893 array('type' => 'checkbox', 'name' => 'update_desc', 'label' => $langs->trans('PuttingDescUpToDate'), 'value' => 0),
2894 );
2895 if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY') && !empty($object->delivery_date)) {
2896 $formquestion[] = array('type' => 'date', 'name' => 'date_delivery', 'label' => $langs->trans("DeliveryDate"), 'value' => $object->delivery_date);
2897 }
2898 // Incomplete payment. We ask if reason = discount or other
2899 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('ToClone'), $langs->trans('ConfirmClonePropal', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 0, 600);
2900 }
2901
2902 // Subtotal line form
2903 if ($action == 'add_title_line') {
2904 $langs->load('subtotals');
2905 $type = 'title';
2906 $depth_array = $object->getPossibleLevels($langs);
2907 require dol_buildpath('/core/tpl/subtotal_create.tpl.php');
2908 } elseif ($action == 'add_subtotal_line') {
2909 $langs->load('subtotals');
2910 $type = 'subtotal';
2911 $titles = $object->getPossibleTitles();
2912 require dol_buildpath('/core/tpl/subtotal_create.tpl.php');
2913 } elseif ($action == 'add_text_line') {
2914 $langs->load('subtotals');
2915 $type = 'text';
2916 require dol_buildpath('/core/tpl/subtotal_create.tpl.php');
2917 }
2918
2919 if ($action == 'closeas') {
2920 //Form to close proposal (signed or not)
2921 $formquestion = array();
2922 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
2923 $formquestion[] = array('type' => 'select', 'name' => 'statut', 'label' => '<span class="fieldrequired">' . $langs->trans("CloseAs") . '</span>', 'values' => array($object::STATUS_SIGNED => $object->LibStatut($object::STATUS_SIGNED), $object::STATUS_NOTSIGNED => $object->LibStatut($object::STATUS_NOTSIGNED)));
2924 }
2925 $formquestion[] = array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"), 'value' => ''); // Field to complete private note (not replace)
2926
2927 if (getDolGlobalInt('PROPOSAL_SUGGEST_DOWN_PAYMENT_INVOICE_CREATION')) {
2928 // This is a hidden option:
2929 // Suggestion to create invoice during proposal signature is not enabled by default.
2930 // Such choice should be managed by the workflow module and trigger. This option generates conflicts with some setup.
2931 // It may also break step of creating an order when invoicing must be done from orders and not from proposal
2932 $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
2933
2934 if (!empty($deposit_percent_from_payment_terms) && isModEnabled('invoice') && $user->hasRight('facture', 'creer')) {
2935 require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
2936
2937 $object->fetchObjectLinked();
2938
2939 $eligibleForDepositGeneration = true;
2940
2941 if (array_key_exists('facture', $object->linkedObjects)) {
2942 foreach ($object->linkedObjects['facture'] as $invoice) {
2943 '@phan-var-force Facture $invoice';
2945 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2946 $eligibleForDepositGeneration = false;
2947 break;
2948 }
2949 }
2950 }
2951
2952 if ($eligibleForDepositGeneration && array_key_exists('commande', $object->linkedObjects)) {
2953 foreach ($object->linkedObjects['commande'] as $order) {
2954 $order->fetchObjectLinked();
2955
2956 if (array_key_exists('facture', $order->linkedObjects)) {
2957 foreach ($order->linkedObjects['facture'] as $invoice) {
2958 '@phan-var-force Facture $invoice';
2960 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2961 $eligibleForDepositGeneration = false;
2962 break 2;
2963 }
2964 }
2965 }
2966 }
2967 }
2968
2969
2970 if ($eligibleForDepositGeneration) {
2971 $formquestion[] = array(
2972 'type' => 'checkbox',
2973 'tdclass' => 'showonlyifsigned',
2974 'name' => 'generate_deposit',
2975 'morecss' => 'margintoponly marginbottomonly',
2976 'label' => $form->textwithpicto($langs->trans('GenerateDeposit', $object->deposit_percent), $langs->trans('DepositGenerationPermittedByThePaymentTermsSelected'))
2977 );
2978
2979 $formquestion[] = array(
2980 'type' => 'date',
2981 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2982 'name' => 'datef',
2983 'label' => $langs->trans('DateInvoice'),
2984 'value' => dol_now(),
2985 'datenow' => true
2986 );
2987
2988 if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
2989 $formquestion[] = array(
2990 'type' => 'date',
2991 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2992 'name' => 'date_pointoftax',
2993 'label' => $langs->trans('DatePointOfTax'),
2994 'value' => dol_now(),
2995 'datenow' => true
2996 );
2997 }
2998
2999 $paymentTermsSelect = $form->getSelectConditionsPaiements(0, 'cond_reglement_id', -1, 0, 1, 'minwidth200');
3000
3001 $formquestion[] = array(
3002 'type' => 'other',
3003 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
3004 'name' => 'cond_reglement_id',
3005 'label' => $langs->trans('PaymentTerm'),
3006 'value' => $paymentTermsSelect
3007 );
3008
3009 $formquestion[] = array(
3010 'type' => 'checkbox',
3011 'tdclass' => 'showonlyifgeneratedeposit',
3012 'name' => 'validate_generated_deposit',
3013 'morecss' => 'margintoponly marginbottomonly',
3014 'label' => $langs->trans('ValidateGeneratedDeposit')
3015 );
3016
3017 $formquestion[] = array(
3018 'type' => 'onecolumn',
3019 'value' => '
3020 <script>
3021 let signedValue = ' . $object::STATUS_SIGNED . ';
3022
3023 $(document).ready(function() {
3024 $("[name=generate_deposit]").change(function () {
3025 let $self = $(this);
3026 let $target = $(".showonlyifgeneratedeposit").parent(".tagtr");
3027
3028 if (! $self.parents(".tagtr").is(":hidden") && $self.is(":checked")) {
3029 $target.show();
3030 } else {
3031 $target.hide();
3032 }
3033
3034 return true;
3035 });
3036
3037 $("#statut").change(function() {
3038 let $target = $(".showonlyifsigned").parent(".tagtr");
3039
3040 if ($(this).val() == signedValue) {
3041 $target.show();
3042 } else {
3043 $target.hide();
3044 }
3045
3046 $("[name=generate_deposit]").trigger("change");
3047
3048 return true;
3049 });
3050
3051 $("#statut").trigger("change");
3052 });
3053 </script>
3054 '
3055 );
3056 }
3057 }
3058 }
3059
3060 if (isModEnabled('notification')) {
3061 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
3062 $notify = new Notify($db);
3063 $formquestion = array_merge($formquestion, array(
3064 array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PROPAL_CLOSE_SIGNED', $object->socid, $object)),
3065 ));
3066 }
3067
3068 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
3069 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('SetAcceptedRefused'), '', 'confirm_closeas', $formquestion, '', 1, 250);
3070 } else {
3071 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?statut=3&id=' . $object->id, $langs->trans('Close'), '', 'confirm_closeas', $formquestion, '', 1, 250);
3072 }
3073 } elseif ($action == 'cancel') {
3074 // Confirm cancel
3075 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans("CancelPropal"), $langs->trans('ConfirmCancelPropal', $object->ref), 'confirm_cancel', '', 0, 1);
3076 } elseif ($action == 'delete') {
3077 // Confirm delete
3078 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('DeleteProp'), $langs->trans('ConfirmDeleteProp', $object->ref), 'confirm_delete', '', 0, 1);
3079 } elseif ($action == 'reopen') {
3080 // Confirm reopen
3081 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenProp', $object->ref), 'confirm_reopen', '', 0, 1);
3082 } elseif ($action == 'ask_deleteline') {
3083 // Confirmation delete product/service line
3084 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 0, 1);
3085 } elseif ($action == 'ask_subtotal_deleteline') {
3086 // Confirmation of removal of a subtotal line
3087 $langs->load("subtotals");
3088 $title = "DeleteSubtotalLine";
3089 $question = "ConfirmDeleteSubtotalLine";
3090 if (GETPOST('type') == 'title') {
3091 $formconfirm = array(array('type' => 'checkbox', 'name' => 'deletecorrespondingsubtotalline', 'label' => $langs->trans("DeleteCorrespondingSubtotalLine"), 'value' => 0));
3092 $title = "DeleteTitleLine";
3093 $question = "ConfirmDeleteTitleLine";
3094 }
3095 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans($title), $langs->trans($question), 'confirm_delete_subtotalline', $formconfirm, 'no', 1);
3096 } elseif ($action == 'validate') {
3097 // Confirm validate proposal
3098 $error = 0;
3099
3100 // We verify whether the object is provisionally numbering
3101 $ref = substr($object->ref, 1, 4);
3102 if ($ref == 'PROV' || $ref == '') {
3103 $numref = $object->getNextNumRef($soc);
3104 if (empty($numref)) {
3105 $error++;
3106 setEventMessages($object->error, $object->errors, 'errors');
3107 }
3108 } else {
3109 $numref = (string) $object->ref;
3110 }
3111
3112 $text = $langs->trans('ConfirmValidateProp', $numref);
3113 if (isModEnabled('notification')) {
3114 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
3115 $notify = new Notify($db);
3116 $text .= '<br>';
3117 $text .= $notify->confirmMessage('PROPAL_VALIDATE', $object->socid, $object);
3118 }
3119
3120 // mandatoryPeriod
3121 $nbMandated = 0;
3122 foreach ($object->lines as $line) {
3123 $res = $line->fetch_product();
3124 if ($res > 0) {
3125 if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end))) {
3126 $nbMandated++;
3127 break;
3128 }
3129 }
3130 }
3131 if ($nbMandated > 0) {
3132 if (getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
3133 setEventMessages($langs->trans("mandatoryPeriodNeedTobeSetMsgValidate"), null, 'errors');
3134 $error++;
3135 } else {
3136 $text .= '<div><span class="clearboth nowraponall warning">' . img_warning() . $langs->trans("mandatoryPeriodNeedTobeSetMsgValidate") . '</span></div>';
3137 }
3138 }
3139
3140 if (!$error) {
3141 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('ValidateProp'), $text, 'confirm_validate', '', 0, 1, 240);
3142 }
3143 }
3144
3145 // Call Hook formConfirm
3146 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
3147 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3148 if (empty($reshook)) {
3149 $formconfirm .= $hookmanager->resPrint;
3150 } elseif ($reshook > 0) {
3151 $formconfirm = $hookmanager->resPrint;
3152 }
3153
3154 // Print form confirm
3155 print $formconfirm;
3156
3157
3158 // Proposal card
3159
3160 $linkback = '<a href="' . DOL_URL_ROOT . '/comm/propal/list.php?restore_lastsearch_values=1' . (!empty($socid) ? '&socid=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
3161
3162 $morehtmlref = '<div class="refidno">';
3163 // Ref customer
3164 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
3165 $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string' . (isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1);
3166 // Thirdparty
3167 $morehtmlref .= '<br>' . $soc->getNomUrl(1, 'customer');
3168 if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $soc->id > 0) {
3169 $morehtmlref .= ' (<a href="' . DOL_URL_ROOT . '/comm/propal/list.php?socid=' . ((int) $soc->id) . '">' . $langs->trans("OtherProposals") . '</a>)';
3170 }
3171 // Project
3172 if (isModEnabled('project')) {
3173 $langs->load("projects");
3174 $morehtmlref .= '<br>';
3175 if ($usercancreate) {
3176 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
3177 if ($action != 'classify') {
3178 $morehtmlref .= '<a class="editfielda" href="' . $_SERVER['PHP_SELF'] . '?action=classify&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> ';
3179 }
3180 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
3181 } else {
3182 if (!empty($object->fk_project)) {
3183 $proj = new Project($db);
3184 $proj->fetch($object->fk_project);
3185 $morehtmlref .= $proj->getNomUrl(1);
3186 if ($proj->title) {
3187 $morehtmlref .= '<span class="opacitymedium"> - ' . dol_escape_htmltag($proj->title) . '</span>';
3188 }
3189 }
3190 }
3191 }
3192 $morehtmlref .= '</div>';
3193
3194
3195 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
3196
3197 // Call Hook tabContentViewProposal
3198 $parameters = array();
3199 // Note that $action and $object may be modified by hook
3200 $reshook = $hookmanager->executeHooks('tabContentViewProposal', $parameters, $object, $action);
3201 if (empty($reshook)) {
3202 print '<div class="fichecenter">';
3203 print '<div class="fichehalfleft">';
3204 print '<div class="underbanner clearboth"></div>';
3205
3206 print '<table class="border tableforfield centpercent">';
3207
3208 // Link for thirdparty discounts
3209 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
3210 $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
3211 $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
3212 } else {
3213 $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
3214 $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
3215 }
3216
3217 print '<tr><td class="titlefieldmax45">' . $langs->trans('Discounts') . '</td><td>';
3218
3219 $absolute_discount = $soc->getAvailableDiscounts(null, $filterabsolutediscount);
3220 $absolute_creditnote = $soc->getAvailableDiscounts(null, $filtercreditnote);
3221 $absolute_discount = price2num($absolute_discount, 'MT');
3222 $absolute_creditnote = price2num($absolute_creditnote, 'MT');
3223
3224 $caneditfield = ($object->status != Propal::STATUS_SIGNED && $object->status != Propal::STATUS_BILLED);
3225
3226 $thirdparty = $soc;
3227 $discount_type = 0;
3228 $backtopage = $_SERVER["PHP_SELF"] . '?id=' . $object->id;
3229 include DOL_DOCUMENT_ROOT . '/core/tpl/object_discounts.tpl.php';
3230
3231 print '</td></tr>';
3232
3233 // Date of proposal
3234 print '<tr>';
3235 print '<td>';
3236 // print '<table class="nobordernopadding" width="100%"><tr><td>';
3237 // print $langs->trans('DatePropal');
3238 // print '</td>';
3239 // if ($action != 'editdate' && $usercancreate && $caneditfield) {
3240 // print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdate&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetDate'), 1).'</a></td>';
3241 // }
3242
3243 // print '</tr></table>';
3244 $editenable = $usercancreate && $caneditfield && $object->status == Propal::STATUS_DRAFT;
3245 print $form->editfieldkey("DatePropal", 'date', '', $object, (int) $editenable);
3246 print '</td><td class="valuefield">';
3247 if ($action == 'editdate' && $usercancreate && $caneditfield) {
3248 print '<form name="editdate" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
3249 print '<input type="hidden" name="token" value="' . newToken() . '">';
3250 print '<input type="hidden" name="action" value="setdate">';
3251 print '<input type="hidden" name="backtopage" value="' . $backtopage . '">';
3252 print $form->selectDate($object->date, 're', 0, 0, 0, "editdate");
3253 print '<input type="submit" class="button button-edit" value="' . $langs->trans('Modify') . '">';
3254 print '</form>';
3255 } else {
3256 if ($object->date) {
3257 print dol_print_date($object->date, 'day');
3258 } else {
3259 print '&nbsp;';
3260 }
3261 }
3262 print '</td>';
3263
3264 // Date end proposal
3265 print '<tr>';
3266 print '<td>';
3267 print '<table class="nobordernopadding centpercent"><tr><td>';
3268 print $langs->trans('DateEndPropal');
3269 print '</td>';
3270 if ($action != 'editecheance' && $usercancreate && $caneditfield) {
3271 print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editecheance&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetConditions'), 1) . '</a></td>';
3272 }
3273 print '</tr></table>';
3274 print '</td><td class="valuefield">';
3275 if ($action == 'editecheance' && $usercancreate && $caneditfield) {
3276 print '<form name="editecheance" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
3277 print '<input type="hidden" name="token" value="' . newToken() . '">';
3278 print '<input type="hidden" name="action" value="setecheance">';
3279 print '<input type="hidden" name="backtopage" value="' . $backtopage . '">';
3280 print $form->selectDate($object->fin_validite, 'ech', 0, 0, 0, "editecheance");
3281 print '<input type="submit" class="button button-edit" value="' . $langs->trans('Modify') . '">';
3282 print '</form>';
3283 } else {
3284 if (!empty($object->fin_validite)) {
3285 print dol_print_date($object->fin_validite, 'day');
3286 if ($object->status == Propal::STATUS_VALIDATED && $object->fin_validite < ($now - getWarningDelay('propal', 'cloture'))) {
3287 print img_warning($langs->trans("Late"));
3288 }
3289 } else {
3290 print '&nbsp;';
3291 }
3292 }
3293 print '</td>';
3294 print '</tr>';
3295
3296 // Payment term
3297 print '<tr><td>';
3298 print '<table class="nobordernopadding centpercent"><tr><td>';
3299 print $langs->trans('PaymentConditionsShort');
3300 print '</td>';
3301 if ($action != 'editconditions' && $usercancreate && $caneditfield) {
3302 print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editconditions&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetConditions'), 1) . '</a></td>';
3303 }
3304 print '</tr></table>';
3305 print '</td><td class="valuefield">';
3306 if ($action == 'editconditions' && $usercancreate && $caneditfield) {
3307 $form->form_conditions_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->cond_reglement_id, 'cond_reglement_id', 0, '', 1, $object->deposit_percent);
3308 } else {
3309 $form->form_conditions_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->cond_reglement_id, 'none', 0, '', 1, $object->deposit_percent);
3310 }
3311 print '</td>';
3312 print '</tr>';
3313
3314 // Payment mode
3315 print '<tr class="field_mode_reglement_id">';
3316 print '<td>';
3317 print '<table class="nobordernopadding centpercent"><tr><td>';
3318 print $langs->trans('PaymentMode');
3319 print '</td>';
3320 if ($action != 'editmode' && $usercancreate && $caneditfield) {
3321 print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editmode&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetMode'), 1) . '</a></td>';
3322 }
3323 print '</tr></table>';
3324 print '</td><td class="valuefieldcreate">';
3325 if ($action == 'editmode' && $usercancreate && $caneditfield) {
3326 $form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
3327 } else {
3328 $form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->mode_reglement_id, 'none');
3329 }
3330 print '</td></tr>';
3331
3332 // Delivery delay
3333 print '<tr class="fielddeliverydelay"><td>';
3334 print '<table class="nobordernopadding centpercent"><tr><td>';
3335 if (isModEnabled('order')) {
3336 print $form->textwithpicto($langs->trans('AvailabilityPeriod'), $langs->trans('AvailabilityPeriod') . ' (' . $langs->trans('AfterOrder') . ')');
3337 } else {
3338 print $langs->trans('AvailabilityPeriod');
3339 }
3340 print '</td>';
3341 if ($action != 'editavailability' && $usercancreate && $caneditfield) {
3342 print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editavailability&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetAvailability'), 1) . '</a></td>';
3343 }
3344 print '</tr></table>';
3345 print '</td><td class="valuefield">';
3346 if ($action == 'editavailability' && $usercancreate && $caneditfield) {
3347 $form->form_availability($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->availability_id, 'availability_id', $langs->trans("Delay"));
3348 } else {
3349 $form->form_availability($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->availability_id, 'none', 1);
3350 }
3351
3352 print '</td>';
3353 print '</tr>';
3354
3355 // Delivery date
3356 print '<tr><td>';
3357 print $form->editfieldkey($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, (int) ($usercancreate && $caneditfield), 'datepicker');
3358 print '</td><td class="valuefieldedit">';
3359 print $form->editfieldval($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
3360 print '</td>';
3361 print '</tr>';
3362
3363 // Shipping Method
3364 if (isModEnabled("shipping")) {
3365 print '<tr><td>';
3366 print '<table class="nobordernopadding centpercent"><tr><td>';
3367 print $langs->trans('SendingMethod');
3368 print '</td>';
3369 if ($action != 'editshippingmethod' && $usercancreate && $caneditfield) {
3370 print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editshippingmethod&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetShippingMode'), 1) . '</a></td>';
3371 }
3372 print '</tr></table>';
3373 print '</td><td class="valuefield">';
3374 if ($action == 'editshippingmethod' && $usercancreate && $caneditfield) {
3375 $form->formSelectShippingMethod($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->shipping_method_id, 'shipping_method_id', 1);
3376 } else {
3377 $form->formSelectShippingMethod($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->shipping_method_id, 'none');
3378 }
3379 print '</td>';
3380 print '</tr>';
3381 }
3382
3383 // Warehouse
3384 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
3385 $langs->load('stocks');
3386 require_once DOL_DOCUMENT_ROOT . '/product/class/html.formproduct.class.php';
3387 $formproduct = new FormProduct($db);
3388 print '<tr class="field_warehouse_id"><td>';
3389 $editenable = $usercancreate;
3390 print $form->editfieldkey("Warehouse", 'warehouse', '', $object, $editenable);
3391 print '</td><td class="valuefieldcreate">';
3392 if ($action == 'editwarehouse') {
3393 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->warehouse_id, 'warehouse_id', 1);
3394 } else {
3395 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->warehouse_id, 'none');
3396 }
3397 print '</td>';
3398 print '</tr>';
3399 }
3400
3401 // Origin of demand
3402 print '<tr><td>';
3403 print '<table class="nobordernopadding centpercent"><tr><td>';
3404 print $langs->trans('Source');
3405 print '</td>';
3406 if ($action != 'editdemandreason' && $usercancreate) {
3407 print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editdemandreason&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetDemandReason'), 1) . '</a></td>';
3408 }
3409 print '</tr></table>';
3410 print '</td><td class="valuefield">';
3411 if ($action == 'editdemandreason' && $usercancreate) {
3412 $form->formInputReason($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->demand_reason_id, 'demand_reason_id', 1);
3413 } else {
3414 $form->formInputReason($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->demand_reason_id, 'none');
3415 }
3416 print '</td>';
3417 print '</tr>';
3418
3419 if ($soc->outstanding_limit) {
3420 // Outstanding Bill
3421 print '<tr><td>';
3422 print $langs->trans('OutstandingBill');
3423 print '</td><td class="valuefield">';
3424 $arrayoutstandingbills = $soc->getOutstandingBills();
3425 print($arrayoutstandingbills['opened'] > $soc->outstanding_limit ? img_warning() : '');
3426 print price($arrayoutstandingbills['opened']) . ' / ';
3427 print price($soc->outstanding_limit, 0, $langs, 1, -1, -1, $conf->currency);
3428 print '</td>';
3429 print '</tr>';
3430 }
3431
3432 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
3433 // Bank Account
3434 print '<tr><td>';
3435 print '<table width="100%" class="nobordernopadding"><tr><td>';
3436 print $langs->trans('BankAccount');
3437 print '</td>';
3438 if ($action != 'editbankaccount' && $usercancreate) {
3439 print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editbankaccount&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetBankAccount'), 1) . '</a></td>';
3440 }
3441 print '</tr></table>';
3442 print '</td><td class="valuefield">';
3443 if ($action == 'editbankaccount') {
3444 $form->formSelectAccount($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->fk_account, 'fk_account', 1);
3445 } else {
3446 $form->formSelectAccount($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->fk_account, 'none');
3447 }
3448 print '</td>';
3449 print '</tr>';
3450 }
3451
3452 if (!getDolGlobalString('PROPOSAL_HIDE_CALCULATED_WEIGHT_VOLUME')) {
3453 $tmparray = $object->getTotalWeightVolume();
3454 $totalWeight = isset($tmparray['weight']) ? $tmparray['weight'] : 0;
3455 $totalVolume = isset($tmparray['volume']) ? $tmparray['volume'] : 0;
3456 if ($totalWeight) {
3457 print '<tr><td>' . $langs->trans("CalculatedWeight") . '</td>';
3458 print '<td class="valuefield">';
3459 print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, getDolGlobalInt('MAIN_WEIGHT_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_WEIGHT_DEFAULT_UNIT', 'no'), 1);
3460 print '</td></tr>';
3461 }
3462 if ($totalVolume) {
3463 print '<tr><td>' . $langs->trans("CalculatedVolume") . '</td>';
3464 print '<td class="valuefield">';
3465 print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'), 1);
3466 print '</td></tr>';
3467 }
3468 }
3469
3470 // Incoterms
3471 if (isModEnabled('incoterm')) {
3472 print '<tr><td>';
3473 print '<table width="100%" class="nobordernopadding"><tr><td>';
3474 print $langs->trans('IncotermLabel');
3475 print '<td><td class="right">';
3476 if ($action != 'editincoterm' && $usercancreate && $caneditfield) {
3477 print '<a class="editfielda" href="' . DOL_URL_ROOT . '/comm/propal/card.php?id=' . $object->id . '&action=editincoterm&token=' . newToken() . '">' . img_edit() . '</a>';
3478 } else {
3479 print '&nbsp;';
3480 }
3481 print '</td></tr></table>';
3482 print '</td>';
3483 print '<td class="valuefield">';
3484 if ($action == 'editincoterm' && $usercancreate && $caneditfield) {
3485 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'] . '?id=' . $object->id);
3486 } else {
3487 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
3488 }
3489 print '</td></tr>';
3490 }
3491
3492 // Categories
3493 if (isModEnabled('category')) {
3494 print '<tr><td>';
3495 print '<table class="nobordernopadding centpercent"><tr><td>';
3496 print $langs->trans("Categories");
3497 print '<td><td class="right">';
3498 if ($usercancreate) {
3499 print '<a class="editfielda" href="'.DOL_URL_ROOT.'/comm/propal/card.php?id='.$object->id.'&action=edittags&token='.newToken().'">'.img_edit().'</a>';
3500 } else {
3501 print '&nbsp;';
3502 }
3503 print '</td></tr></table>';
3504 print '</td>';
3505 print '<td>';
3506 if ($action == 'edittags') {
3507 print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
3508 print '<input type="hidden" name="action" value="settags">';
3509 print '<input type="hidden" name="token" value="'.newToken().'">';
3510 print $form->selectCategories(Categorie::TYPE_PROPOSAL, 'categories', $object);
3511 print '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">';
3512 print '</form>';
3513 } else {
3514 print $form->showCategories($object->id, Categorie::TYPE_PROPOSAL, 1);
3515 }
3516 print "</td></tr>";
3517 }
3518
3519 // Other attributes
3520 include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
3521
3522 print '</table>';
3523
3524 print '</div>';
3525 print '<div class="fichehalfright">';
3526 print '<div class="underbanner clearboth"></div>';
3527
3528 print '<table class="border tableforfield centpercent">';
3529
3530 include DOL_DOCUMENT_ROOT . '/core/tpl/object_currency_amount.tpl.php';
3531
3532 print '<tr>';
3533 print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
3534 print '<td class="nowrap amountcard right">' . price($object->total_ht, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3535 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3536 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ht, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3537 }
3538 print '</tr>';
3539
3540 print '<tr>';
3541 print '<td>' . $langs->trans('AmountVAT') . '</td>';
3542 print '<td class="nowrap amountcard right">' . price($object->total_tva, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3543 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3544 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_tva, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3545 }
3546 print '</tr>';
3547
3548 if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
3549 print '<tr>';
3550 print '<td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
3551 print '<td class="nowrap amountcard right">' . price($object->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3552 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3553 $object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
3554
3555 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax1, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3556 }
3557 print '</tr>';
3558 }
3559
3560 if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
3561 print '<tr>';
3562 print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
3563 print '<td class="nowrap amountcard right">' . price($object->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3564 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3565 $object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
3566
3567 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax2, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3568 }
3569 print '</tr>';
3570 }
3571
3572 print '<tr>';
3573 print '<td>' . $langs->trans('AmountTTC') . '</td>';
3574 print '<td class="nowrap amountcard right">' . price($object->total_ttc, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3575 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3576 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ttc, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3577 }
3578 print '</tr>';
3579
3580 print '</table>';
3581
3582 // Margin Infos
3583 if (isModEnabled('margin')) {
3584 $formmargin->displayMarginInfos($object);
3585 }
3586
3587 print '</div>';
3588 print '</div>';
3589
3590 print '<div class="clearboth"></div><br>';
3591
3592 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
3593 $blocname = 'contacts';
3594 $title = $langs->trans('ContactsAddresses');
3595 include DOL_DOCUMENT_ROOT . '/core/tpl/bloc_showhide.tpl.php';
3596 }
3597
3598 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
3599 $blocname = 'notes';
3600 $title = $langs->trans('Notes');
3601 include DOL_DOCUMENT_ROOT . '/core/tpl/bloc_showhide.tpl.php';
3602 }
3603
3604 /*
3605 * Lines
3606 */
3607
3608 // Get object lines
3609 $result = $object->getLinesArray();
3610
3611 // Add products/services form
3612 //$forceall = 1;
3613 global $inputalsopricewithtax;
3614 $inputalsopricewithtax = 1;
3615
3616 print ' <form name="addproduct" id="addproduct" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="POST">
3617 <input type="hidden" name="token" value="' . newToken() . '">
3618 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
3619 <input type="hidden" name="mode" value="">
3620 <input type="hidden" name="page_y" value="">
3621 <input type="hidden" name="backtopage" value="' . $backtopage . '">
3622 <input type="hidden" name="id" value="' . $object->id . '">
3623 ';
3624
3625 if (!empty($conf->use_javascript_ajax) && $object->status == Propal::STATUS_DRAFT) {
3626 if (isModEnabled('subtotals')) {
3627 include DOL_DOCUMENT_ROOT . '/core/tpl/subtotal_ajaxrow.tpl.php';
3628 } else {
3629 include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
3630 }
3631 }
3632
3633 print '<div class="div-table-responsive-no-min">';
3634 if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
3635 print '<table id="tablelines" class="noborder noshadow centpercent">';
3636 }
3637
3638 if (!empty($object->lines)) {
3639 $object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 1);
3640 }
3641
3642 // Form to add new line
3643 if ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines') {
3644 if ($action != 'editline') {
3645 $parameters = array();
3646 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3647 if ($reshook < 0) {
3648 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3649 }
3650 if (empty($reshook)) {
3651 $object->formAddObjectLine(1, $mysoc, $soc);
3652 }
3653 } else {
3654 $parameters = array();
3655 $reshook = $hookmanager->executeHooks('formEditObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3656 }
3657 }
3658
3659 if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
3660 print '</table>';
3661 }
3662 print '</div>';
3663
3664 print "</form>\n";
3665 }
3666
3667 print dol_get_fiche_end();
3668
3669
3670 /*
3671 * Button Actions
3672 */
3673
3674 if ($action != 'presend') {
3675 $numlines = count($object->lines);
3676 print '<div class="tabsAction">';
3677
3678 $parameters = array();
3679 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
3680 // modified by hook
3681 if (empty($reshook)) {
3682 if ($action != 'editline') {
3683 // Subtotal
3684 if ($object->status == Propal::STATUS_DRAFT && isModEnabled('subtotals')
3685 && (getDolGlobalInt('SUBTOTAL_TITLE_'.strtoupper($object->element)) || getDolGlobalInt('SUBTOTAL_'.strtoupper($object->element)) || getDolGlobalInt('SUBTOTAL_TEXT_'.strtoupper($object->element)))) {
3686 $langs->load('subtotals');
3687
3688 $url_button = array();
3689
3690 $url_button[] = array(
3691 'lang' => 'subtotals',
3692 'enabled' => (isModEnabled('propal') && $object->status == Propal::STATUS_DRAFT && getDolGlobalInt('SUBTOTAL_TITLE_'.strtoupper($object->element))),
3693 'perm' => (bool) $usercancreate,
3694 'label' => $langs->trans('AddTitleLine'),
3695 'url' => '/comm/propal/card.php?id=' . $object->id . '&action=add_title_line&token=' . newToken()
3696 );
3697
3698 $url_button[] = array(
3699 'lang' => 'subtotals',
3700 'enabled' => (isModEnabled('propal') && $object->status == Propal::STATUS_DRAFT && getDolGlobalInt('SUBTOTAL_'.strtoupper($object->element))),
3701 'perm' => (bool) $usercancreate,
3702 'label' => $langs->trans('AddSubtotalLine'),
3703 'url' => '/comm/propal/card.php?id=' . $object->id . '&action=add_subtotal_line&token=' . newToken()
3704 );
3705
3706 $url_button[] = array(
3707 'lang' => 'subtotals',
3708 'enabled' => (isModEnabled('propal') && $object->status == Propal::STATUS_DRAFT && getDolGlobalInt('SUBTOTAL_TEXT_'.strtoupper($object->element))),
3709 'perm' => (bool) $usercancreate,
3710 'label' => $langs->trans('AddTextLine'),
3711 'url' => '/comm/propal/card.php?id=' . $object->id . '&action=add_text_line&token=' . newToken()
3712 );
3713
3714 print dolGetButtonAction('', $langs->trans('SubTotal'), 'default', $url_button, '', true);
3715 }
3716
3717 // Validate
3718 if (($object->status == Propal::STATUS_DRAFT && $object->total_ttc >= 0 && count($object->lines) > 0)
3719 || ($object->status == Propal::STATUS_DRAFT && getDolGlobalString('PROPAL_ENABLE_NEGATIVE') && count($object->lines) > 0)
3720 ) {
3721 if ($usercanvalidate) {
3722 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=validate&token=' . newToken() . '">' . (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE') ? $langs->trans('Validate') : $langs->trans('ValidateAndSign')) . '</a>';
3723 } else {
3724 print '<a class="butActionRefused classfortooltip" href="#">' . $langs->trans('Validate') . '</a>';
3725 }
3726 }
3727 // Create event
3728 /*if (isModEnabled('agenda') && !empty($conf->global->MAIN_ADD_EVENT_ON_ELEMENT_CARD)) // Add hidden condition because this is not a "workflow" action so should appears somewhere else on page.
3729 {
3730 print '<a class="butAction" href="' . DOL_URL_ROOT . '/comm/action/card.php?action=create&amp;origin=' . $object->element . '&amp;originid=' . $object->id . '&amp;socid=' . $object->socid . '">' . $langs->trans("AddAction") . '</a></div>';
3731 }*/
3732 // Edit
3733 if ($object->status == Propal::STATUS_VALIDATED && $usercancreate) {
3734 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=modif&token=' . newToken() . '">' . $langs->trans('Modify') . '</a>';
3735 }
3736
3737 // ReOpen
3738 if (((getDolGlobalString('PROPAL_REOPEN_UNSIGNED_ONLY') && $object->status == Propal::STATUS_NOTSIGNED) || (!getDolGlobalString('PROPAL_REOPEN_UNSIGNED_ONLY') && ($object->status == Propal::STATUS_SIGNED || $object->status == Propal::STATUS_NOTSIGNED || $object->status == Propal::STATUS_BILLED || $object->status == Propal::STATUS_CANCELED)))) {
3739 if ($usercanreopen) {
3740 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=reopen&token=' . newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#reopen') . '"';
3741 print '>' . $langs->trans('ReOpen') . '</a>';
3742 } else {
3743 print '<a class="butActionRefused classfortooltip" href="#" title="' . $langs->trans("NotEnoughPermissions") . '">' . $langs->trans("ReOpen") . '</a>';
3744 }
3745 }
3746
3747 // Send
3748 if (empty($user->socid)) {
3749 if ($object->status == Propal::STATUS_VALIDATED || $object->status == Propal::STATUS_SIGNED || getDolGlobalString('PROPOSAL_SENDBYEMAIL_FOR_ALL_STATUS')) {
3750 print dolGetButtonAction('', $langs->trans('SendMail'), 'email', $_SERVER["PHP_SELF"] . '?action=presend&token=' . newToken() . '&id=' . $object->id . '&mode=init#formmailbeforetitle', '', $usercansend);
3751 }
3752 }
3753
3754 $arrayforbutaction = array();
3755
3756 // Create a sale order
3757 $arrayforbutaction[] = array(
3758 'lang' => 'orders',
3759 'enabled' => (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED),
3760 'perm' => $usercancreateorder,
3761 'label' => 'AddOrder',
3762 'url' => '/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3763 );
3764 /*if (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED) {
3765 if ($usercancreateorder) {
3766 print '<a class="butAction" href="'.DOL_URL_ROOT.'/commande/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("AddOrder").'</a>';
3767 }
3768 }*/
3769
3770 // Create a purchase order
3771 if (getDolGlobalString('WORKFLOW_CAN_CREATE_PURCHASE_ORDER_FROM_PROPOSAL')) {
3772 $arrayforbutaction[] = array(
3773 'lang' => 'orders',
3774 'enabled' => ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")),
3775 'perm' => $usercancreatepurchaseorder,
3776 'label' => 'AddPurchaseOrder',
3777 'url' => '/fourn/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3778 );
3779 /*if ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")) {
3780 if ($usercancreatepurchaseorder) {
3781 print '<a class="butAction" href="'.DOL_URL_ROOT.'/fourn/commande/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("AddPurchaseOrder").'</a>';
3782 }
3783 }*/
3784 }
3785
3786 // Create an intervention
3787 $arrayforbutaction[] = array(
3788 'lang' => 'interventions',
3789 'enabled' => (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED),
3790 'perm' => $usercancreateintervention,
3791 'label' => 'AddIntervention',
3792 'url' => '/fichinter/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3793 );
3794 /*if (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED) {
3795 if ($usercancreateintervention) {
3796 $langs->load("interventions");
3797 print '<a class="butAction" href="'.DOL_URL_ROOT.'/fichinter/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("AddIntervention").'</a>';
3798 }
3799 }*/
3800
3801 // Create contract
3802 $arrayforbutaction[] = array(
3803 'lang' => 'contracts',
3804 'enabled' => (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED),
3805 'perm' => $usercancreatecontract,
3806 'label' => 'AddContract',
3807 'url' => '/contrat/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3808 );
3809 /*if (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED) {
3810 $langs->load("contracts");
3811
3812 if ($usercancreatecontract) {
3813 print '<a class="butAction" href="'.DOL_URL_ROOT.'/contrat/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans('AddContract').'</a>';
3814 }
3815 }*/
3816
3817 // Create an invoice and classify billed
3818 if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
3819 $arrayforbutaction[] = [
3820 'lang' => 'invoice',
3821 'enabled' => isModEnabled('invoice'),
3822 'perm' => $usercancreateinvoice,
3823 'label' => 'CreateBill',
3824 'url' => '/compta/facture/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid),
3825 ];
3826 /*if (isModEnabled('invoice') && $usercancreateinvoice) {
3827 print '<a class="butAction" href="'.DOL_URL_ROOT.'/compta/facture/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("CreateBill").'</a>';
3828 }*/
3829 }
3830
3831 $actionButtonsParameters = [
3832 "areDropdownButtons" => !getDolGlobalInt("MAIN_REMOVE_DROPDOWN_CREATE_BUTTONS_ON_ORDER"),
3833 "backtopage" => $_SERVER["PHP_SELF"] . "?id=" . ((int) $id)
3834 ];
3835
3836 if ($numlines > 0) {
3837 print dolGetButtonAction('', $langs->trans("Create"), 'default', $arrayforbutaction, (string) $object->id, 1, $actionButtonsParameters);
3838 } else {
3839 print dolGetButtonAction($langs->trans("ErrorObjectMustHaveLinesToBeValidated", $object->ref), $langs->trans("Create"), 'default', $arrayforbutaction, (string) $object->id, 0, $actionButtonsParameters);
3840 }
3841
3842 if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
3843 $arrayofinvoiceforpropal = $object->getInvoiceArrayList();
3844 if ((is_array($arrayofinvoiceforpropal) && count($arrayofinvoiceforpropal) > 0) || !getDolGlobalString('WORKFLOW_PROPAL_NEED_INVOICE_TO_BE_CLASSIFIED_BILLED')) {
3845 if ($usercanclose) {
3846 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=classifybilled&token=' . newToken() . '&socid=' . $object->socid . '">' . $langs->trans("ClassifyBilled") . '</a>';
3847 } else {
3848 print '<a class="butActionRefused classfortooltip" href="#" title="' . $langs->trans("NotEnoughPermissions") . '">' . $langs->trans("ClassifyBilled") . '</a>';
3849 }
3850 }
3851 }
3852
3853 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
3854 // Close as accepted/refused
3855 if ($object->status == Propal::STATUS_VALIDATED) {
3856 if ($usercanclose) {
3857 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=closeas&token=' . newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close') . '"';
3858 print '>' . $langs->trans('SetAcceptedRefused') . '</a>';
3859 } else {
3860 print '<a class="butActionRefused classfortooltip" href="#" title="' . $langs->trans("NotEnoughPermissions") . '"';
3861 print '>' . $langs->trans('SetAcceptedRefused') . '</a>';
3862 }
3863 }
3864 } else {
3865 // Set not signed (close)
3866 if ($object->status == Propal::STATUS_DRAFT && $usercanclose) {
3867 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&token=' . newToken() . '&action=closeas&token=' . newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close') . '"';
3868 print '>' . $langs->trans('SetRefusedAndClose') . '</a>';
3869 }
3870 }
3871
3872 // Cancel propal
3873 if ($object->status > Propal::STATUS_DRAFT && $usercanclose) {
3874 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=cancel&token=' . newToken() . '">' . $langs->trans("CancelPropal") . '</a>';
3875 }
3876
3877 // Clone
3878 if ($usercancreate) {
3879 print '<a class="butAction butActionClone" href="' . $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&socid=' . $object->socid . '&action=clone&token=' . newToken() . '&object=' . $object->element . '">' . $langs->trans("ToClone") . '</a>';
3880 }
3881
3882 // Delete
3883 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=delete&token=' . newToken(), 'delete', $usercandelete);
3884 }
3885 }
3886
3887 print '</div>';
3888 }
3889
3890 //Select mail models is same action as presend
3891 if (GETPOST('modelselected')) {
3892 $action = 'presend';
3893 }
3894
3895 if ($action != 'presend') {
3896 print '<div class="fichecenter"><div class="fichehalfleft">';
3897 print '<a name="builddoc"></a>'; // ancre
3898 /*
3899 * Generated documents
3900 */
3901 $objref = dol_sanitizeFileName($object->ref);
3902 $filedir = $conf->propal->multidir_output[$object->entity ?? $conf->entity] . "/" . dol_sanitizeFileName($object->ref);
3903 $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
3904 $genallowed = $usercanread;
3905 $delallowed = $usercancreate;
3906 $tooltipAfterComboOfModels = '';
3907 if (getDolGlobalString('MAIN_PDF_ADD_TERMSOFSALE_PROPAL')) {
3908 $tooltipAfterComboOfModels = $langs->trans("AccordingToYourSetupTheFileWillBeConcatenated", getDolGlobalString('MAIN_INFO_PROPAL_TERMSOFSALE'));
3909 }
3910
3911 print $formfile->showdocuments('propal', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '0', '', $soc->default_lang, '', $object, 0, 'remove_file', $tooltipAfterComboOfModels);
3912
3913 // Show links to link elements
3914 $tmparray = $form->showLinkToObjectBlock($object, array(), array('propal'), 1);
3915 $linktoelem = $tmparray['linktoelem'];
3916 $htmltoenteralink = $tmparray['htmltoenteralink'];
3917 print $htmltoenteralink;
3918
3919 $compatibleImportElementsList = false;
3920 if ($user->hasRight('propal', 'creer') && $object->status == Propal::STATUS_DRAFT) {
3921 $compatibleImportElementsList = array('commande', 'propal', 'facture', 'subscription'); // import from linked elements
3922 }
3923 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
3924
3925 // Show online signature link
3926 $useonlinesignature = getDolGlobalInt('PROPOSAL_ALLOW_ONLINESIGN');
3927
3928 if ($object->status != Propal::STATUS_DRAFT && $useonlinesignature) {
3929 print '<br><!-- Link to sign -->';
3930 require_once DOL_DOCUMENT_ROOT . '/core/lib/signature.lib.php';
3931 print showOnlineSignatureUrl('proposal', $object->ref, $object) . '<br>';
3932 }
3933
3934 print '</div><div class="fichehalfright">';
3935
3936 $MAXEVENT = 10;
3937
3938 $morehtmlcenter = dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT . '/comm/propal/messaging.php?id=' . $object->id);
3939 $morehtmlcenter .= dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT . '/comm/propal/agenda.php?id=' . $object->id);
3940
3941 // List of actions on element
3942 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php';
3943 $formactions = new FormActions($db);
3944 $somethingshown = $formactions->showactions($object, 'propal', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
3945
3946 print '</div></div>';
3947 }
3948
3949 // Presend form
3950 $modelmail = 'propal_send';
3951 $defaulttopic = 'SendPropalRef';
3952 $diroutput = $conf->propal->multidir_output[$object->entity ?? $conf->entity];
3953 $trackid = 'pro' . $object->id;
3954
3955 include DOL_DOCUMENT_ROOT . '/core/tpl/card_presend.tpl.php';
3956}
3957
3958// End of page
3959llxFooter();
3960$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Class to manage a WYSIWYG editor.
static createDepositFromOrigin(CommonObject $origin, $date, $payment_terms_id, User $user, $notrigger=0, $autoValidateDeposit=false, $overrideFields=array())
Creates a deposit from a proposal or an order by grouping lines by VAT rates.
const TYPE_DEPOSIT
Deposit invoice.
Class to manage building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class to manage "other" html components Only common components are here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage building of HTML components.
Class to manage generation of HTML components for proposal management.
static liste_modeles($db, $maxfilenamelength=0)
Return list of active generation modules.
Class to manage the table of subscription to notifications.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage products or services.
Class to manage projects.
Class to manage proposals.
const STATUS_DRAFT
Draft status.
const STATUS_SIGNED
Signed quote.
const STATUS_NOTSIGNED
Not signed quote.
const STATUS_BILLED
Billed or processed quote.
const STATUS_CANCELED
Canceled status.
const STATUS_VALIDATED
Validated status.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
global $mysoc
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
$date_start
Variables from include:
dol_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolBuildUrl($url, $params=[], $addtoken=false, $anchor='')
Return path of url.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
getDolCurrency()
Return the main currency ('EUR', 'USD', ...)
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
getWarningDelay($module, $parmlevel1, $parmlevel2='')
Return a warning delay You can use it like this: if (getWarningDelay('module', 'paramlevel1')) It rep...
getDictionaryValue($tablename, $field, $id, $checkentity=false, $rowidfield='rowid')
Return the value of a filed into a dictionary for the record $id.
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
Definition html.lib.php:519
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
Definition html.lib.php:717
setEventMessage($mesgs, $style='mesgs', $noduplicate=0, $attop=0)
Set event message in dol_events session object.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
Definition html.lib.php:172
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
propal_prepare_head($object)
Prepare array with list of tabs.
print $langs trans('Date')." left Ref Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right Paid right PaymentTypeShortLIQ right SELECT p pos_change as p datep as date
Definition receipt.php:487
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.