dolibarr 19.0.3
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-2021 Frédéric France <frederic.france@netlogic.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 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 3 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program. If not, see <https://www.gnu.org/licenses/>.
32 */
33
34
41// Load Dolibarr environment
42require '../../main.inc.php';
43require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
44require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
45require_once DOL_DOCUMENT_ROOT.'/core/class/html.formpropal.class.php';
46require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php';
47require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
48require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
49require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php';
50require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php';
51require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
52require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
53require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
54if (isModEnabled('project')) {
55 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
56 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
57}
58
59if (isModEnabled('variants')) {
60 require_once DOL_DOCUMENT_ROOT.'/variants/class/ProductCombination.class.php';
61}
62
63// Load translation files required by the page
64$langs->loadLangs(array('companies', 'propal', 'compta', 'bills', 'orders', 'products', 'deliveries', 'sendings', 'other'));
65if (isModEnabled('incoterm')) {
66 $langs->load('incoterm');
67}
68if (isModEnabled('margin')) {
69 $langs->load('margins');
70}
71
72$error = 0;
73
74$id = GETPOST('id', 'int');
75$ref = GETPOST('ref', 'alpha');
76$socid = GETPOST('socid', 'int');
77$action = GETPOST('action', 'aZ09');
78$cancel = GETPOST('cancel', 'alpha');
79$origin = GETPOST('origin', 'alpha');
80$originid = GETPOST('originid', 'int');
81$confirm = GETPOST('confirm', 'alpha');
82$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page
83$lineid = GETPOST('lineid', 'int');
84$contactid = GETPOST('contactid', 'int');
85$projectid = GETPOST('projectid', 'int');
86$rank = (GETPOST('rank', 'int') > 0) ? GETPOST('rank', 'int') : -1;
87
88// PDF
89$hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
90$hidedesc = (GETPOST('hidedesc', 'int') ? GETPOST('hidedesc', 'int') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
91$hideref = (GETPOST('hideref', 'int') ? GETPOST('hideref', 'int') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
92
93$object = new Propal($db);
94$extrafields = new ExtraFields($db);
95
96// fetch optionals attributes and labels
97$extrafields->fetch_name_optionals_label($object->table_element);
98
99// Load object
100if ($id > 0 || !empty($ref)) {
101 $ret = $object->fetch($id, $ref);
102 if ($ret > 0) {
103 $ret = $object->fetch_thirdparty();
104 if ($ret > 0 && isset($object->fk_project)) {
105 $ret = $object->fetch_project();
106 }
107 }
108 if ($ret <= 0) {
109 setEventMessages($object->error, $object->errors, 'errors');
110 $action = '';
111 }
112}
113
114// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
115$hookmanager->initHooks(array('propalcard', 'globalcard'));
116
117$usercanread = $user->hasRight("propal", "lire");
118$usercancreate = $user->hasRight("propal", "creer");
119$usercandelete = $user->hasRight("propal", "supprimer");
120
121$usercanclose = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($user->rights->propal->propal_advance->close)));
122$usercanvalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($user->rights->propal->propal_advance->validate)));
123$usercansend = (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($user->rights->propal->propal_advance->send)));
124
125$usermustrespectpricemin = ((getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && empty($user->rights->produit->ignore_price_min_advance)) || !getDolGlobalString('MAIN_USE_ADVANCED_PERMS'));
126$usercancreateorder = $user->hasRight('commande', 'creer');
127$usercancreateinvoice = $user->hasRight('facture', 'creer');
128$usercancreatecontract = $user->hasRight('contrat', 'creer');
129$usercancreateintervention = $user->hasRight('ficheinter', 'creer');
130$usercancreatepurchaseorder = ($user->hasRight('fournisseur', 'commande', 'creer') || $user->hasRight('supplier_order', 'creer'));
131
132$permissionnote = $usercancreate; // Used by the include of actions_setnotes.inc.php
133$permissiondellink = $usercancreate; // Used by the include of actions_dellink.inc.php
134$permissiontoedit = $usercancreate; // Used by the include of actions_lineupdown.inc.php
135
136// Security check
137if (!empty($user->socid)) {
138 $socid = $user->socid;
139}
140restrictedArea($user, 'propal', $object->id);
141
142
143/*
144 * Actions
145 */
146
147$parameters = array('socid' => $socid);
148$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
149if ($reshook < 0) {
150 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
151}
152
153if (empty($reshook)) {
154 $backurlforlist = DOL_URL_ROOT.'/comm/propal/list.php';
155
156 if (empty($backtopage) || ($cancel && empty($id))) {
157 if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
158 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
159 $backtopage = $backurlforlist;
160 } else {
161 $backtopage = DOL_URL_ROOT.'/comm/propal/card.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
162 }
163 }
164 }
165
166 if ($cancel) {
167 if (!empty($backtopageforcancel)) {
168 header("Location: ".$backtopageforcancel);
169 exit;
170 } elseif (!empty($backtopage)) {
171 header("Location: ".$backtopage);
172 exit;
173 }
174 $action = '';
175 }
176
177 include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once
178
179 include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once
180
181 include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be include, not include_once
182
183 // Action clone object
184 if ($action == 'confirm_clone' && $confirm == 'yes' && $usercancreate) {
185 if (!($socid > 0)) {
186 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('IdThirdParty')), null, 'errors');
187 } else {
188 if ($object->id > 0) {
189 if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY')) {
190 //Get difference between old and new delivery date and change lines according to difference
191 $date_delivery = dol_mktime(
192 12,
193 0,
194 0,
195 GETPOST('date_deliverymonth', 'int'),
196 GETPOST('date_deliveryday', 'int'),
197 GETPOST('date_deliveryyear', 'int')
198 );
199 $date_delivery_old = $object->delivery_date;
200 if (!empty($date_delivery_old) && !empty($date_delivery)) {
201 //Attempt to get the date without possible hour rounding errors
202 $old_date_delivery = dol_mktime(
203 12,
204 0,
205 0,
206 dol_print_date($date_delivery_old, '%m'),
207 dol_print_date($date_delivery_old, '%d'),
208 dol_print_date($date_delivery_old, '%Y')
209 );
210 //Calculate the difference and apply if necessary
211 $difference = $date_delivery - $old_date_delivery;
212 if ($difference != 0) {
213 $object->delivery_date = $date_delivery;
214 foreach ($object->lines as $line) {
215 if (isset($line->date_start)) {
216 $line->date_start = $line->date_start + $difference;
217 }
218 if (isset($line->date_end)) {
219 $line->date_end = $line->date_end + $difference;
220 }
221 }
222 }
223 }
224 }
225
226 $result = $object->createFromClone($user, $socid, (GETPOSTISSET('entity') ? GETPOST('entity', 'int') : null), (GETPOST('update_prices', 'aZ') ? true : false), (GETPOST('update_desc', 'aZ') ? true : false));
227 if ($result > 0) {
228 header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result);
229 exit();
230 } else {
231 if (count($object->errors) > 0) {
232 setEventMessages($object->error, $object->errors, 'errors');
233 }
234 $action = '';
235 }
236 }
237 }
238 } elseif ($action == 'confirm_delete' && $confirm == 'yes' && $usercandelete) {
239 // Delete proposal
240 $result = $object->delete($user);
241 if ($result > 0) {
242 header('Location: '.DOL_URL_ROOT.'/comm/propal/list.php?restore_lastsearch_values=1');
243 exit();
244 } else {
245 $langs->load("errors");
246 setEventMessages($object->error, $object->errors, 'errors');
247 }
248 } elseif ($action == 'confirm_deleteline' && $confirm == 'yes' && $usercancreate) {
249 // Remove line
250 $result = $object->deleteline($lineid);
251 // reorder lines
252 if ($result > 0) {
253 $object->line_order(true);
254 } else {
255 $langs->load("errors");
256 setEventMessages($object->error, $object->errors, 'errors');
257 }
258
259 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
260 // Define output language
261 $outputlangs = $langs;
262 if (getDolGlobalInt('MAIN_MULTILANGS')) {
263 $outputlangs = new Translate("", $conf);
264 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
265 $outputlangs->setDefaultLang($newlang);
266 }
267 $ret = $object->fetch($id); // Reload to get new records
268 if ($ret > 0) {
269 $object->fetch_thirdparty();
270 }
271 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
272 }
273
274 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id);
275 exit();
276 } elseif ($action == 'confirm_validate' && $confirm == 'yes' && $usercanvalidate) {
277 // Validation
278 $idwarehouse = GETPOST('idwarehouse', 'int');
279 $result = $object->valid($user);
280 if ($result > 0 && getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
281 $result = $object->closeProposal($user, $object::STATUS_SIGNED);
282 }
283 if ($result >= 0) {
284 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
285 $outputlangs = $langs;
286 $newlang = '';
287 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
288 $newlang = GETPOST('lang_id', 'aZ09');
289 }
290 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
291 $newlang = $object->thirdparty->default_lang;
292 }
293 if (!empty($newlang)) {
294 $outputlangs = new Translate("", $conf);
295 $outputlangs->setDefaultLang($newlang);
296 }
297 $model = $object->model_pdf;
298 $ret = $object->fetch($id); // Reload to get new records
299 if ($ret > 0) {
300 $object->fetch_thirdparty();
301 }
302
303 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
304 }
305 } else {
306 $langs->load("errors");
307 if (count($object->errors) > 0) {
308 setEventMessages($object->error, $object->errors, 'errors');
309 } else {
310 setEventMessages($langs->trans($object->error), null, 'errors');
311 }
312 }
313 } elseif ($action == 'setdate' && $usercancreate) {
314 $datep = dol_mktime(12, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
315
316 if (empty($datep)) {
317 $error++;
318 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
319 }
320
321 if (!$error) {
322 $result = $object->set_date($user, $datep);
323 if ($result > 0 && !empty($object->duree_validite) && !empty($object->fin_validite)) {
324 $datev = $datep + ($object->duree_validite * 24 * 3600);
325 $result = $object->set_echeance($user, $datev, 1);
326 }
327 if ($result < 0) {
328 dol_print_error($db, $object->error);
329 } elseif (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
330 $outputlangs = $langs;
331 $newlang = '';
332 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
333 $newlang = GETPOST('lang_id', 'aZ09');
334 }
335 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
336 $newlang = $object->thirdparty->default_lang;
337 }
338 if (!empty($newlang)) {
339 $outputlangs = new Translate("", $conf);
340 $outputlangs->setDefaultLang($newlang);
341 }
342 $model = $object->model_pdf;
343 $ret = $object->fetch($id); // Reload to get new records
344 if ($ret > 0) {
345 $object->fetch_thirdparty();
346 }
347
348 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
349 }
350 }
351 } elseif ($action == 'setecheance' && $usercancreate) {
352 $result = $object->set_echeance($user, dol_mktime(12, 0, 0, GETPOST('echmonth', 'int'), GETPOST('echday', 'int'), GETPOST('echyear', 'int')));
353 if ($result >= 0) {
354 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
355 $outputlangs = $langs;
356 $newlang = '';
357 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
358 $newlang = GETPOST('lang_id', 'aZ09');
359 }
360 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
361 $newlang = $object->thirdparty->default_lang;
362 }
363 if (!empty($newlang)) {
364 $outputlangs = new Translate("", $conf);
365 $outputlangs->setDefaultLang($newlang);
366 }
367 $model = $object->model_pdf;
368 $ret = $object->fetch($id); // Reload to get new records
369 if ($ret > 0) {
370 $object->fetch_thirdparty();
371 }
372
373 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
374 }
375 } else {
376 setEventMessages($object->error, $object->errors, 'errors');
377 }
378 } elseif ($action == 'setdate_livraison' && $usercancreate) {
379 $result = $object->setDeliveryDate($user, dol_mktime(12, 0, 0, GETPOST('date_livraisonmonth', 'int'), GETPOST('date_livraisonday', 'int'), GETPOST('date_livraisonyear', 'int')));
380 if ($result < 0) {
381 dol_print_error($db, $object->error);
382 }
383 } elseif ($action == 'setref_client' && $usercancreate) {
384 // Positionne ref client
385 $result = $object->set_ref_client($user, GETPOST('ref_client'));
386 if ($result < 0) {
387 setEventMessages($object->error, $object->errors, 'errors');
388 }
389 } elseif ($action == 'set_incoterms' && isModEnabled('incoterm') && $usercancreate) {
390 // Set incoterm
391 $result = $object->setIncoterms(GETPOST('incoterm_id', 'int'), GETPOST('location_incoterms', 'alpha'));
392 } elseif ($action == 'add' && $usercancreate) {
393 // Create proposal
394 $object->socid = $socid;
395 $object->fetch_thirdparty();
396
397 $datep = dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear'));
398 $date_delivery = dol_mktime(12, 0, 0, GETPOST('date_livraisonmonth'), GETPOST('date_livraisonday'), GETPOST('date_livraisonyear'));
399 $duration = GETPOST('duree_validite', 'int');
400
401 if (empty($datep)) {
402 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("DatePropal")), null, 'errors');
403 $action = 'create';
404 $error++;
405 }
406 if (empty($duration)) {
407 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ValidityDuration")), null, 'errors');
408 $action = 'create';
409 $error++;
410 }
411
412 if ($socid < 1) {
413 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Customer")), null, 'errors');
414
415 $action = 'create';
416 $error++;
417 }
418
419 if (!$error) {
420 $db->begin();
421
422 // If we select proposal to clone during creation (when option PROPAL_CLONE_ON_CREATE_PAGE is on)
423 if (GETPOST('createmode') == 'copy' && GETPOST('copie_propal')) {
424 if ($object->fetch(GETPOST('copie_propal', 'int')) > 0) {
425 $object->ref = GETPOST('ref');
426 $object->datep = $datep;
427 $object->date = $datep;
428 $object->delivery_date = $date_delivery;
429 $object->availability_id = GETPOST('availability_id');
430 $object->demand_reason_id = GETPOST('demand_reason_id');
431 $object->fk_delivery_address = GETPOST('fk_address', 'int');
432 $object->shipping_method_id = GETPOST('shipping_method_id', 'int');
433 $object->warehouse_id = GETPOST('warehouse_id', 'int');
434 $object->duree_validite = $duration;
435 $object->cond_reglement_id = GETPOST('cond_reglement_id');
436 $object->deposit_percent = GETPOST('cond_reglement_id_deposit_percent', 'alpha');
437 $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int');
438 $object->fk_account = GETPOST('fk_account', 'int');
439 $object->socid = GETPOST('socid', 'int');
440 $object->contact_id = GETPOST('contactid', 'int');
441 $object->fk_project = GETPOST('projectid', 'int');
442 $object->model_pdf = GETPOST('model', 'alphanohtml');
443 $object->author = $user->id; // deprecated
444 $object->user_author_id = $user->id;
445 $object->note_private = GETPOST('note_private', 'restricthtml');
446 $object->note_public = GETPOST('note_public', 'restricthtml');
447 $object->statut = Propal::STATUS_DRAFT;
448 $object->status = Propal::STATUS_DRAFT;
449 $object->fk_incoterms = GETPOST('incoterm_id', 'int');
450 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
451 } else {
452 setEventMessages($langs->trans("ErrorFailedToCopyProposal", GETPOST('copie_propal')), null, 'errors');
453 }
454 } else {
455 $object->ref = GETPOST('ref');
456 $object->ref_client = GETPOST('ref_client');
457 $object->datep = $datep;
458 $object->date = $datep;
459 $object->delivery_date = $date_delivery;
460 $object->availability_id = GETPOST('availability_id', 'int');
461 $object->demand_reason_id = GETPOST('demand_reason_id', 'int');
462 $object->fk_delivery_address = GETPOST('fk_address', 'int');
463 $object->shipping_method_id = GETPOST('shipping_method_id', 'int');
464 $object->warehouse_id = GETPOST('warehouse_id', 'int');
465 $object->duree_validite = price2num(GETPOST('duree_validite', 'alpha'));
466 $object->cond_reglement_id = GETPOST('cond_reglement_id', 'int');
467 $object->deposit_percent = GETPOST('cond_reglement_id_deposit_percent', 'alpha');
468 $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int');
469 $object->fk_account = GETPOST('fk_account', 'int');
470 $object->contact_id = GETPOST('contactid', 'int');
471 $object->fk_project = GETPOST('projectid', 'int');
472 $object->model_pdf = GETPOST('model');
473 $object->author = $user->id; // deprecated
474 $object->note_private = GETPOST('note_private', 'restricthtml');
475 $object->note_public = GETPOST('note_public', 'restricthtml');
476 $object->fk_incoterms = GETPOST('incoterm_id', 'int');
477 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
478
479 $object->origin = GETPOST('origin');
480 $object->origin_id = GETPOST('originid');
481
482 // Multicurrency
483 if (isModEnabled("multicurrency")) {
484 $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
485 }
486
487 // Fill array 'array_options' with data from add form
488 $ret = $extrafields->setOptionalsFromPost(null, $object);
489 if ($ret < 0) {
490 $error++;
491 $action = 'create';
492 }
493 }
494
495 if (!$error) {
496 if ($origin && $originid) {
497 // Parse element/subelement (ex: project_task)
498 $element = $subelement = $origin;
499 $regs = array();
500 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
501 $element = $regs[1];
502 $subelement = $regs[2];
503 }
504
505 // For compatibility
506 if ($element == 'order') {
507 $element = $subelement = 'commande';
508 }
509 if ($element == 'propal') {
510 $element = 'comm/propal';
511 $subelement = 'propal';
512 }
513 if ($element == 'contract') {
514 $element = $subelement = 'contrat';
515 }
516 if ($element == 'inter') {
517 $element = $subelement = 'ficheinter';
518 }
519 if ($element == 'shipping') {
520 $element = $subelement = 'expedition';
521 }
522
523 $object->origin = $origin;
524 $object->origin_id = $originid;
525
526 // Possibility to add external linked objects with hooks
527 $object->linked_objects [$object->origin] = $object->origin_id;
528 if (is_array($_POST['other_linked_objects']) && !empty($_POST['other_linked_objects'])) {
529 $object->linked_objects = array_merge($object->linked_objects, $_POST['other_linked_objects']);
530 }
531
532 $id = $object->create($user);
533 if ($id > 0) {
534 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
535
536 $classname = ucfirst($subelement);
537 $srcobject = new $classname($db);
538
539 dol_syslog("Try to find source object origin=".$object->origin." originid=".$object->origin_id." to add lines");
540 $result = $srcobject->fetch($object->origin_id);
541
542 if ($result > 0) {
543 $lines = $srcobject->lines;
544 if (empty($lines) && method_exists($srcobject, 'fetch_lines')) {
545 $srcobject->fetch_lines();
546 $lines = $srcobject->lines;
547 }
548
549 $fk_parent_line = 0;
550 $num = count($lines);
551 for ($i = 0; $i < $num; $i++) {
552 $label = (!empty($lines[$i]->label) ? $lines[$i]->label : '');
553 $desc = (!empty($lines[$i]->desc) ? $lines[$i]->desc : $lines[$i]->label);
554
555 // Positive line
556 $product_type = ($lines[$i]->product_type ? $lines[$i]->product_type : 0);
557
558 // Date start
559 $date_start = false;
560 if ($lines[$i]->date_debut_prevue) {
561 $date_start = $lines[$i]->date_debut_prevue;
562 }
563 if ($lines[$i]->date_debut_reel) {
564 $date_start = $lines[$i]->date_debut_reel;
565 }
566 if ($lines[$i]->date_start) {
567 $date_start = $lines[$i]->date_start;
568 }
569
570 // Date end
571 $date_end = false;
572 if ($lines[$i]->date_fin_prevue) {
573 $date_end = $lines[$i]->date_fin_prevue;
574 }
575 if ($lines[$i]->date_fin_reel) {
576 $date_end = $lines[$i]->date_fin_reel;
577 }
578 if ($lines[$i]->date_end) {
579 $date_end = $lines[$i]->date_end;
580 }
581
582 // Reset fk_parent_line for no child products and special product
583 if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
584 $fk_parent_line = 0;
585 }
586
587 // Extrafields
588 if (method_exists($lines[$i], 'fetch_optionals')) {
589 $lines[$i]->fetch_optionals();
590 $array_options = $lines[$i]->array_options;
591 }
592
593 $tva_tx = $lines[$i]->tva_tx;
594 if (!empty($lines[$i]->vat_src_code) && !preg_match('/\‍(/', $tva_tx)) {
595 $tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
596 }
597
598 $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, 'HT', 0, $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);
599
600 if ($result > 0) {
601 $lineid = $result;
602 } else {
603 $lineid = 0;
604 $error++;
605 break;
606 }
607
608 // Defined the new fk_parent_line
609 if ($result > 0 && $lines[$i]->product_type == 9) {
610 $fk_parent_line = $result;
611 }
612 }
613
614 // Hooks
615 $parameters = array('objFrom' => $srcobject);
616 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been
617 // modified by hook
618 if ($reshook < 0) {
619 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
620 $error++;
621 }
622 } else {
623 setEventMessages($srcobject->error, $srcobject->errors, 'errors');
624 $error++;
625 }
626 } else {
627 setEventMessages($object->error, $object->errors, 'errors');
628 $error++;
629 }
630 } else {
631 // Standard creation
632 $id = $object->create($user);
633 }
634
635 if ($id > 0) {
636 // Insert default contacts if defined
637 if (GETPOST('contactid') > 0) {
638 $result = $object->add_contact(GETPOST('contactid'), 'CUSTOMER', 'external');
639 if ($result < 0) {
640 $error++;
641 setEventMessages($langs->trans("ErrorFailedToAddContact"), null, 'errors');
642 }
643 }
644
645 if (getDolGlobalString('PROPOSAL_AUTO_ADD_AUTHOR_AS_CONTACT')) {
646 $result = $object->add_contact($user->id, 'SALESREPFOLL', 'internal');
647 if ($result < 0) {
648 $error++;
649 setEventMessages($langs->trans("ErrorFailedToAddUserAsContact"), null, 'errors');
650 }
651 }
652
653 if (!$error) {
654 $db->commit();
655
656 // Define output language
657 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
658 $outputlangs = $langs;
659 $newlang = '';
660 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
661 $newlang = GETPOST('lang_id', 'aZ09');
662 }
663 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
664 $newlang = $object->thirdparty->default_lang;
665 }
666 if (!empty($newlang)) {
667 $outputlangs = new Translate("", $conf);
668 $outputlangs->setDefaultLang($newlang);
669 }
670 $model = $object->model_pdf;
671
672 $ret = $object->fetch($id); // Reload to get new records
673 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
674 if ($result < 0) {
675 dol_print_error($db, $result);
676 }
677 }
678
679 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id);
680 exit();
681 } else {
682 $db->rollback();
683 $action = 'create';
684 }
685 } else {
686 setEventMessages($object->error, $object->errors, 'errors');
687 $db->rollback();
688 $action = 'create';
689 }
690 }
691 }
692 } elseif ($action == 'classifybilled' && $usercanclose) {
693 // Classify billed
694 $db->begin();
695
696 $result = $object->classifyBilled($user, 0, '');
697 if ($result < 0) {
698 setEventMessages($object->error, $object->errors, 'errors');
699 $error++;
700 }
701
702 if (!$error) {
703 $db->commit();
704 } else {
705 $db->rollback();
706 }
707 } elseif ($action == 'confirm_closeas' && $usercanclose && !GETPOST('cancel', 'alpha')) {
708 // Close proposal
709 if (!(GETPOST('statut', 'int') > 0)) {
710 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CloseAs")), null, 'errors');
711 $action = 'closeas';
712 } elseif (GETPOST('statut', 'int') == $object::STATUS_SIGNED || GETPOST('statut', 'int') == $object::STATUS_NOTSIGNED) {
713 $locationTarget = '';
714 // prevent browser refresh from closing proposal several times
715 if ($object->statut == $object::STATUS_VALIDATED || (getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE') && $object->statut == $object::STATUS_DRAFT)) {
716 $db->begin();
717
718 $result = $object->closeProposal($user, GETPOST('statut', 'int'), GETPOST('note_private', 'restricthtml'));
719 if ($result < 0) {
720 setEventMessages($object->error, $object->errors, 'errors');
721 $error++;
722 } else {
723 // Needed if object linked modified by trigger (because linked objects can't be fetched two times : linkedObjectsFullLoaded)
724 $locationTarget = DOL_URL_ROOT . '/comm/propal/card.php?id=' . $object->id;
725 }
726
727 $deposit = null;
728
729 $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
730
731 if (
732 !$error && GETPOST('statut', 'int') == $object::STATUS_SIGNED && GETPOST('generate_deposit', 'alpha') == 'on'
733 && !empty($deposit_percent_from_payment_terms) && isModEnabled('facture') && $user->hasRight('facture', 'creer')
734 ) {
735 require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
736
737 $date = dol_mktime(0, 0, 0, GETPOST('datefmonth', 'int'), GETPOST('datefday', 'int'), GETPOST('datefyear', 'int'));
738 $forceFields = array();
739
740 if (GETPOSTISSET('date_pointoftax')) {
741 $forceFields['date_pointoftax'] = dol_mktime(0, 0, 0, GETPOST('date_pointoftaxmonth', 'int'), GETPOST('date_pointoftaxday', 'int'), GETPOST('date_pointoftaxyear', 'int'));
742 }
743
744 $deposit = Facture::createDepositFromOrigin($object, $date, GETPOST('cond_reglement_id', 'int'), $user, 0, GETPOST('validate_generated_deposit', 'alpha') == 'on', $forceFields);
745
746 if ($deposit) {
747 setEventMessage('DepositGenerated');
748 $locationTarget = DOL_URL_ROOT . '/compta/facture/card.php?id=' . $deposit->id;
749 } else {
750 $error++;
751 setEventMessages($object->error, $object->errors, 'errors');
752 }
753 }
754
755 if (!$error) {
756 $db->commit();
757
758 if ($deposit && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
759 $ret = $deposit->fetch($deposit->id); // Reload to get new records
760 $outputlangs = $langs;
761
762 if (getDolGlobalInt('MAIN_MULTILANGS')) {
763 $outputlangs = new Translate('', $conf);
764 $outputlangs->setDefaultLang($deposit->thirdparty->default_lang);
765 $outputlangs->load('products');
766 }
767
768 $result = $deposit->generateDocument($deposit->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
769
770 if ($result < 0) {
771 setEventMessages($deposit->error, $deposit->errors, 'errors');
772 }
773 }
774
775 if ($locationTarget) {
776 header('Location: ' . $locationTarget);
777 exit;
778 }
779 } else {
780 $db->rollback();
781 $action = '';
782 }
783 }
784 }
785 } elseif ($action == 'confirm_reopen' && $usercanclose && !GETPOST('cancel', 'alpha')) {
786 // Reopen proposal
787 // prevent browser refresh from reopening proposal several times
788 if ($object->statut == Propal::STATUS_SIGNED || $object->statut == Propal::STATUS_NOTSIGNED || $object->statut == Propal::STATUS_BILLED) {
789 $db->begin();
790
791 $newstatus = (getDolGlobalInt('PROPAL_SKIP_ACCEPT_REFUSE') ? Propal::STATUS_DRAFT : Propal::STATUS_VALIDATED);
792 $result = $object->reopen($user, $newstatus);
793 if ($result < 0) {
794 setEventMessages($object->error, $object->errors, 'errors');
795 $error++;
796 } else {
797 $object->statut = $newstatus;
798 $object->status = $newstatus;
799 }
800
801 if (!$error) {
802 $db->commit();
803 } else {
804 $db->rollback();
805 }
806 }
807 } elseif ($action == 'import_lines_from_object'
808 && $user->hasRight('propal', 'creer')
809 && $object->statut == Propal::STATUS_DRAFT
810 ) {
811 // add lines from objectlinked
812 $fromElement = GETPOST('fromelement');
813 $fromElementid = GETPOST('fromelementid');
814 $importLines = GETPOST('line_checkbox');
815
816 if (!empty($importLines) && is_array($importLines) && !empty($fromElement) && ctype_alpha($fromElement) && !empty($fromElementid)) {
817 if ($fromElement == 'commande') {
818 dol_include_once('/'.$fromElement.'/class/'.$fromElement.'.class.php');
819 $lineClassName = 'OrderLine';
820 } elseif ($fromElement == 'propal') {
821 dol_include_once('/comm/'.$fromElement.'/class/'.$fromElement.'.class.php');
822 $lineClassName = 'PropaleLigne';
823 } elseif ($fromElement == 'facture') {
824 dol_include_once('/compta/'.$fromElement.'/class/'.$fromElement.'.class.php');
825 $lineClassName = 'FactureLigne';
826 }
827 $nextRang = count($object->lines) + 1;
828 $importCount = 0;
829 $error = 0;
830 foreach ($importLines as $lineId) {
831 $lineId = intval($lineId);
832 $originLine = new $lineClassName($db);
833 if (intval($fromElementid) > 0 && $originLine->fetch($lineId) > 0) {
834 $originLine->fetch_optionals();
835 $desc = $originLine->desc;
836 $pu_ht = $originLine->subprice;
837 $qty = $originLine->qty;
838 $txtva = $originLine->tva_tx;
839 $txlocaltax1 = $originLine->localtax1_tx;
840 $txlocaltax2 = $originLine->localtax2_tx;
841 $fk_product = $originLine->fk_product;
842 $remise_percent = $originLine->remise_percent;
843 $date_start = $originLine->date_start;
844 $date_end = $originLine->date_end;
845 $ventil = 0;
846 $info_bits = $originLine->info_bits;
847 $fk_remise_except = $originLine->fk_remise_except;
848 $price_base_type = 'HT';
849 $pu_ttc = 0;
850 $type = $originLine->product_type;
851 $rang = $nextRang++;
852 $special_code = $originLine->special_code;
853 $origin = $originLine->element;
854 $origin_id = $originLine->id;
855 $fk_parent_line = 0;
856 $fk_fournprice = $originLine->fk_fournprice;
857 $pa_ht = $originLine->pa_ht;
858 $label = $originLine->label;
859 $array_options = $originLine->array_options;
860 $situation_percent = 100;
861 $fk_prev_id = '';
862 $fk_unit = $originLine->fk_unit;
863 $pu_ht_devise = $originLine->multicurrency_subprice;
864
865 $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);
866
867 if ($res > 0) {
868 $importCount++;
869 } else {
870 $error++;
871 }
872 } else {
873 $error++;
874 }
875 }
876
877 if ($error) {
878 setEventMessages($langs->trans('ErrorsOnXLines', $error), null, 'errors');
879 }
880 }
881 }
882
883 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
884
885 // Actions to send emails
886 $actiontypecode = 'AC_OTH_AUTO';
887 $triggersendname = 'PROPAL_SENTBYMAIL';
888 $autocopy = 'MAIN_MAIL_AUTOCOPY_PROPOSAL_TO';
889 $trackid = 'pro'.$object->id;
890 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
891
892
893 // Go back to draft
894 if ($action == 'modif' && $usercancreate) {
895 $object->setDraft($user);
896
897 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
898 // Define output language
899 $outputlangs = $langs;
900 if (getDolGlobalInt('MAIN_MULTILANGS')) {
901 $outputlangs = new Translate("", $conf);
902 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
903 $outputlangs->setDefaultLang($newlang);
904 }
905 $ret = $object->fetch($id); // Reload to get new records
906 if ($ret > 0) {
907 $object->fetch_thirdparty();
908 }
909 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
910 }
911 } elseif ($action == "setabsolutediscount" && $usercancreate) {
912 if (GETPOST("remise_id", "int")) {
913 if ($object->id > 0) {
914 $result = $object->insert_discount(GETPOST("remise_id", "int"));
915 if ($result < 0) {
916 setEventMessages($object->error, $object->errors, 'errors');
917 }
918 }
919 }
920 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '' && $usercancreate) {
921 // Define a vat_rate for all lines
922 $vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0);
923 $vat_rate = str_replace('*', '', $vat_rate);
924 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
925 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
926 foreach ($object->lines as $line) {
927 $result = $object->updateline($line->id, $line->subprice, $line->qty, $line->remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $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, $line->multicurrency_subprice);
928 }
929 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('remiseforalllines', 'alpha') !== '' && $usercancreate) {
930 // Define a discount for all lines
931 $remise_percent = (GETPOST('remiseforalllines') ? GETPOST('remiseforalllines') : 0);
932 $remise_percent = str_replace('*', '', $remise_percent);
933 foreach ($object->lines as $line) {
934 $result = $object->updateline($line->id, $line->subprice, $line->qty, $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, $line->multicurrency_subprice);
935 }
936 } elseif ($action == 'addline' && GETPOST('submitforallmargins', 'alpha') && GETPOST('marginforalllines') !== '' && $usercancreate) {
937 // Define margin
938 $margin_rate = (GETPOST('marginforalllines') ? GETPOST('marginforalllines') : 0);
939 foreach ($object->lines as &$line) {
940 $subprice = price2num($line->pa_ht * (1 + $margin_rate/100), 'MU');
941 $prod = new Product($db);
942 $prod->fetch($line->fk_product);
943 if ($prod->price_min > $subprice) {
944 $price_subprice = price($subprice, 0, $outlangs, 1, -1, -1, 'auto');
945 $price_price_min = price($prod->price_min, 0, $outlangs, 1, -1, -1, 'auto');
946 setEventMessages($prod->ref.' - '.$prod->label.' ('.$price_subprice.' < '.$price_price_min.' '.strtolower($langs->trans("MinPrice")).')'."\n", null, 'warnings');
947 }
948 // Manage $line->subprice and $line->multicurrency_subprice
949 $multicurrency_subprice = $subprice * $line->multicurrency_subprice / $line->subprice;
950 // Update DB
951 $result = $object->updateline($line->id, $subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_rate, $line->localtax2_rate, $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);
952 // Update $object with new margin info
953 $line->price = $subprice;
954 $line->marge_tx = $margin_rate;
955 $line->marque_tx = $margin_rate * $line->pa_ht / $subprice;
956 $line->total_ht = $line->qty * $subprice;
957 $line->total_tva = $line->tva_tx * $line->qty * $subprice;
958 $line->total_ttc = (1 + $line->tva_tx) * $line->qty * $subprice;
959 // Manage $line->subprice and $line->multicurrency_subprice
960 $line->multicurrency_total_ht = $line->qty * $subprice * $line->multicurrency_subprice / $line->subprice;
961 $line->multicurrency_total_tva = $line->tva_tx * $line->qty * $subprice * $line->multicurrency_subprice / $line->subprice;
962 $line->multicurrency_total_ttc = (1 + $line->tva_tx) * $line->qty * $subprice * $line->multicurrency_subprice / $line->subprice;
963 // Used previous $line->subprice and $line->multicurrency_subprice above, now they can be set to their new values
964 $line->subprice = $subprice;
965 $line->multicurrency_subprice = $multicurrency_subprice;
966 }
967 } elseif ($action == 'addline' && $usercancreate) { // Add line
968 // Set if we used free entry or predefined product
969 $predef = '';
970 $product_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
971
972 $price_ht = '';
973 $price_ht_devise = '';
974 $price_ttc = '';
975 $price_ttc_devise = '';
976
977 // TODO Implement if (getDolGlobalInt('MAIN_UNIT_PRICE_WITH_TAX_IS_FOR_ALL_TAXES'))
978
979 if (GETPOST('price_ht') !== '') {
980 $price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
981 }
982 if (GETPOST('multicurrency_price_ht') !== '') {
983 $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
984 }
985 if (GETPOST('price_ttc') !== '') {
986 $price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2);
987 }
988 if (GETPOST('multicurrency_price_ttc') !== '') {
989 $price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2);
990 }
991
992 $prod_entry_mode = GETPOST('prod_entry_mode', 'aZ09');
993 if ($prod_entry_mode == 'free') {
994 $idprod = 0;
995 } else {
996 $idprod = GETPOST('idprod', 'int');
997
998 if (getDolGlobalString('MAIN_DISABLE_FREE_LINES') && $idprod <= 0) {
999 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
1000 $error++;
1001 }
1002 }
1003
1004 $tva_tx = GETPOST('tva_tx', 'alpha');
1005
1006 $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS', 2);
1007 $remise_percent = (GETPOSTISSET('remise_percent'.$predef) ? price2num(GETPOST('remise_percent'.$predef, 'alpha'), '', 2) : 0);
1008 if (empty($remise_percent)) {
1009 $remise_percent = 0;
1010 }
1011
1012 // Extrafields
1013 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1014 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
1015 // Unset extrafield
1016 if (is_array($extralabelsline)) {
1017 // Get extra fields
1018 foreach ($extralabelsline as $key => $value) {
1019 unset($_POST["options_".$key]);
1020 }
1021 }
1022
1023 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
1024 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1025 $error++;
1026 }
1027
1028 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.
1029 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
1030 $error++;
1031 }
1032 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && empty($product_desc)) {
1033 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), null, 'errors');
1034 $error++;
1035 }
1036
1037 if (!$error && isModEnabled('variants') && $prod_entry_mode != 'free') {
1038 if ($combinations = GETPOST('combinations', 'array')) {
1039 //Check if there is a product with the given combination
1040 $prodcomb = new ProductCombination($db);
1041
1042 if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
1043 $idprod = $res->fk_product_child;
1044 } else {
1045 setEventMessages($langs->trans('ErrorProductCombinationNotFound'), null, 'errors');
1046 $error++;
1047 }
1048 }
1049 }
1050
1051 $propal_qty_requirement = (getDolGlobalString('PROPAL_ENABLE_NEGATIVE_QTY') ? ($qty >= 0 || $qty <= 0) : $qty >= 0);
1052 if (!$error && $propal_qty_requirement && (!empty($product_desc) || (!empty($idprod) && $idprod > 0))) {
1053 $pu_ht = 0;
1054 $pu_ttc = 0;
1055 $pu_ht_devise = 0;
1056 $pu_ttc_devise = 0;
1057 $price_min = 0;
1058 $price_min_ttc = 0;
1059 $tva_npr=0;
1060 $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
1061
1062 $db->begin();
1063
1064 // $tva_tx can be 'x.x (XXX)'
1065
1066 // Ecrase $pu par celui du produit
1067 // Ecrase $desc par celui du produit
1068 // Replaces $fk_unit with the product unit
1069 if (!empty($idprod) && $idprod > 0) {
1070 $prod = new Product($db);
1071 $prod->fetch($idprod);
1072
1073 $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
1074
1075 // Update if prices fields are defined
1076 /*$tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id);
1077 $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id);
1078 if (empty($tva_tx)) {
1079 $tva_npr = 0;
1080 }*/
1081
1082 // Price unique per product
1083 $pu_ht = $prod->price;
1084 $pu_ttc = $prod->price_ttc;
1085 $price_min = $prod->price_min;
1086 $price_min_ttc = $prod->price_min_ttc;
1087 $price_base_type = $prod->price_base_type;
1088
1089 // If price per segment
1090 if (getDolGlobalString('PRODUIT_MULTIPRICES') && $object->thirdparty->price_level) {
1091 $pu_ht = $prod->multiprices[$object->thirdparty->price_level];
1092 $pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
1093 $price_min = $prod->multiprices_min[$object->thirdparty->price_level];
1094 $price_min_ttc = $prod->multiprices_min_ttc[$object->thirdparty->price_level];
1095 $price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level];
1096 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
1097 if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) {
1098 $tva_tx = $prod->multiprices_tva_tx[$object->thirdparty->price_level];
1099 }
1100 if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) {
1101 $tva_npr = $prod->multiprices_recuperableonly[$object->thirdparty->price_level];
1102 }
1103 }
1104 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
1105 // If price per customer
1106 require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
1107
1108 $prodcustprice = new ProductCustomerPrice($db);
1109
1110 $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $object->thirdparty->id);
1111
1112 $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
1113 if ($result) {
1114 // If there is some prices specific to the customer
1115 if (count($prodcustprice->lines) > 0) {
1116 $pu_ht = price($prodcustprice->lines[0]->price);
1117 $pu_ttc = price($prodcustprice->lines[0]->price_ttc);
1118 $price_min = price($prodcustprice->lines[0]->price_min);
1119 $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc);
1120 $price_base_type = $prodcustprice->lines[0]->price_base_type;
1121 /*$tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx);
1122 if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\‍(.*\‍)/', $tva_tx)) {
1123 $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')';
1124 }
1125 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
1126 if (empty($tva_tx)) {
1127 $tva_npr = 0;
1128 }*/
1129 }
1130 }
1131 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY')) {
1132 // If price per quantity
1133 if ($prod->prices_by_qty[0]) { // yes, this product has some prices per quantity
1134 // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
1135 $pqp = GETPOST('pbq', 'int');
1136
1137 // Search price into product_price_by_qty from $prod->id
1138 foreach ($prod->prices_by_qty_list[0] as $priceforthequantityarray) {
1139 if ($priceforthequantityarray['rowid'] != $pqp) {
1140 continue;
1141 }
1142 // We found the price
1143 if ($priceforthequantityarray['price_base_type'] == 'HT') {
1144 $pu_ht = $priceforthequantityarray['unitprice'];
1145 } else {
1146 $pu_ttc = $priceforthequantityarray['unitprice'];
1147 }
1148 // Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
1149 break;
1150 }
1151 }
1152 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
1153 // If price per quantity and customer
1154 if ($prod->prices_by_qty[$object->thirdparty->price_level]) { // yes, this product has some prices per quantity
1155 // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
1156 $pqp = GETPOST('pbq', 'int');
1157
1158 // Search price into product_price_by_qty from $prod->id
1159 foreach ($prod->prices_by_qty_list[$object->thirdparty->price_level] as $priceforthequantityarray) {
1160 if ($priceforthequantityarray['rowid'] != $pqp) {
1161 continue;
1162 }
1163 // We found the price
1164 if ($priceforthequantityarray['price_base_type'] == 'HT') {
1165 $pu_ht = $priceforthequantityarray['unitprice'];
1166 } else {
1167 $pu_ttc = $priceforthequantityarray['unitprice'];
1168 }
1169 // Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
1170 break;
1171 }
1172 }
1173 }
1174
1175 $tmpvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
1176 $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $prod->tva_tx));
1177
1178 // Set unit price to use
1179 if (!empty($price_ht) || (string) $price_ht === '0') {
1180 $pu_ht = price2num($price_ht, 'MU');
1181 $pu_ttc = price2num($pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
1182 } elseif (!empty($price_ht_devise) || (string) $price_ht_devise === '0') {
1183 $pu_ht_devise = price2num($price_ht_devise, 'MU');
1184 $pu_ht = '';
1185 $pu_ttc = '';
1186 } elseif (!empty($price_ttc) || (string) $price_ttc === '0') {
1187 $pu_ttc = price2num($price_ttc, 'MU');
1188 $pu_ht = price2num($pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
1189 } elseif ($tmpvat != $tmpprodvat) {
1190 // Is this still used ?
1191 if ($price_base_type != 'HT') {
1192 $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
1193 } else {
1194 $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
1195 }
1196 }
1197
1198 $desc = '';
1199
1200 // Define output language
1201 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1202 $outputlangs = $langs;
1203 $newlang = '';
1204 if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1205 $newlang = GETPOST('lang_id', 'aZ09');
1206 }
1207 if (empty($newlang)) {
1208 $newlang = $object->thirdparty->default_lang;
1209 }
1210 if (!empty($newlang)) {
1211 $outputlangs = new Translate("", $conf);
1212 $outputlangs->setDefaultLang($newlang);
1213 }
1214
1215 $desc = (!empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description;
1216 } else {
1217 $desc = $prod->description;
1218 }
1219
1220 //If text set in desc is the same as product description (as now it's preloaded) whe add it only one time
1221 if ($product_desc==$desc && getDolGlobalString('PRODUIT_AUTOFILL_DESC')) {
1222 $product_desc='';
1223 }
1224
1225 if (!empty($product_desc) && getDolGlobalString('MAIN_NO_CONCAT_DESCRIPTION')) {
1226 $desc = $product_desc;
1227 } else {
1228 $desc = dol_concatdesc($desc, $product_desc, '', getDolGlobalString('MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION'));
1229 }
1230
1231 // Add custom code and origin country into description
1232 if (!getDolGlobalString('MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE') && (!empty($prod->customcode) || !empty($prod->country_code))) {
1233 $tmptxt = '(';
1234 // Define output language
1235 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1236 $outputlangs = $langs;
1237 $newlang = '';
1238 if (empty($newlang) && GETPOST('lang_id', 'alpha')) {
1239 $newlang = GETPOST('lang_id', 'alpha');
1240 }
1241 if (empty($newlang)) {
1242 $newlang = $object->thirdparty->default_lang;
1243 }
1244 if (!empty($newlang)) {
1245 $outputlangs = new Translate("", $conf);
1246 $outputlangs->setDefaultLang($newlang);
1247 $outputlangs->load('products');
1248 }
1249 if (!empty($prod->customcode)) {
1250 $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
1251 }
1252 if (!empty($prod->customcode) && !empty($prod->country_code)) {
1253 $tmptxt .= ' - ';
1254 }
1255 if (!empty($prod->country_code)) {
1256 $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $outputlangs, 0);
1257 }
1258 } else {
1259 if (!empty($prod->customcode)) {
1260 $tmptxt .= $langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
1261 }
1262 if (!empty($prod->customcode) && !empty($prod->country_code)) {
1263 $tmptxt .= ' - ';
1264 }
1265 if (!empty($prod->country_code)) {
1266 $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $langs, 0);
1267 }
1268 }
1269 $tmptxt .= ')';
1270 $desc = dol_concatdesc($desc, $tmptxt);
1271 }
1272
1273 $type = $prod->type;
1274 $fk_unit = $prod->fk_unit;
1275 } else {
1276 $pu_ht = price2num($price_ht, 'MU');
1277 $pu_ttc = price2num($price_ttc, 'MU');
1278 $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
1279 if (empty($tva_tx)) {
1280 $tva_npr = 0;
1281 }
1282 $tva_tx = str_replace('*', '', $tva_tx);
1283 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1284 $desc = $product_desc;
1285 $type = GETPOST('type');
1286 $fk_unit = GETPOST('units', 'alpha');
1287 $pu_ht_devise = price2num($price_ht_devise, 'MU');
1288 $pu_ttc_devise = price2num($price_ttc_devise, 'MU');
1289
1290 if ($pu_ttc && !$pu_ht) {
1291 $price_base_type = 'TTC';
1292 }
1293 }
1294
1295 $info_bits = 0;
1296 if ($tva_npr) {
1297 $info_bits |= 0x01;
1298 }
1299
1300 // Local Taxes
1301 $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $tva_npr);
1302 $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $tva_npr);
1303
1304 // Margin
1305 $fournprice = price2num(GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : '');
1306 $buyingprice = price2num(GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''); // If buying_price is '0', we muste keep this value
1307
1308 $date_start = dol_mktime(GETPOST('date_start'.$predef.'hour'), GETPOST('date_start'.$predef.'min'), GETPOST('date_start'.$predef.'sec'), GETPOST('date_start'.$predef.'month'), GETPOST('date_start'.$predef.'day'), GETPOST('date_start'.$predef.'year'));
1309 $date_end = dol_mktime(GETPOST('date_end'.$predef.'hour'), GETPOST('date_end'.$predef.'min'), GETPOST('date_end'.$predef.'sec'), GETPOST('date_end'.$predef.'month'), GETPOST('date_end'.$predef.'day'), GETPOST('date_end'.$predef.'year'));
1310
1311 // Prepare a price equivalent for minimum price check
1312 $pu_equivalent = $pu_ht;
1313 $pu_equivalent_ttc = $pu_ttc;
1314 $currency_tx = $object->multicurrency_tx;
1315
1316 // Check if we have a foreign currency
1317 // If so, we update the pu_equiv as the equivalent price in base currency
1318 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1319 $pu_equivalent = $pu_ht_devise * $currency_tx;
1320 }
1321 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1322 $pu_equivalent_ttc = $pu_ttc_devise * $currency_tx;
1323 }
1324
1325 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1326 /*
1327 if ($pu_equivalent) {
1328 $tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
1329 $pu_equivalent_ttc = ...
1330 } else {
1331 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $tva_tx, -1, -1, 0, 'TTC', $info_bits, $type);
1332 $pu_equivalent_ht = ...
1333 }
1334 */
1335
1336 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1337 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1338
1339 // Check price is not lower than minimum
1340 if ($usermustrespectpricemin) {
1341 if ($pu_equivalent && $price_min && ((price2num($pu_equivalent) * (1 - $remise_percent / 100)) < price2num($price_min)) && $price_base_type == 'HT') {
1342 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1343 setEventMessages($mesg, null, 'errors');
1344 $error++;
1345 } elseif ($pu_equivalent_ttc && $price_min_ttc && ((price2num($pu_equivalent_ttc) * (1 - $remise_percent / 100)) < price2num($price_min_ttc)) && $price_base_type == 'TTC') {
1346 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1347 setEventMessages($mesg, null, 'errors');
1348 $error++;
1349 }
1350 }
1351
1352 if (!$error) {
1353 // Insert line
1354 $result = $object->addline($desc, $pu_ht, $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, GETPOST('fk_parent_line'), $fournprice, $buyingprice, $label, $date_start, $date_end, $array_options, $fk_unit, '', 0, $pu_ht_devise);
1355
1356 if ($result > 0) {
1357 $db->commit();
1358
1359 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1360 // Define output language
1361 $outputlangs = $langs;
1362 if (getDolGlobalInt('MAIN_MULTILANGS')) {
1363 $outputlangs = new Translate("", $conf);
1364 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
1365 $outputlangs->setDefaultLang($newlang);
1366 }
1367 $ret = $object->fetch($id); // Reload to get new records
1368 if ($ret > 0) {
1369 $object->fetch_thirdparty();
1370 }
1371 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1372 }
1373
1374 unset($_POST['prod_entry_mode']);
1375
1376 unset($_POST['qty']);
1377 unset($_POST['type']);
1378 unset($_POST['remise_percent']);
1379 unset($_POST['price_ht']);
1380 unset($_POST['multicurrency_price_ht']);
1381 unset($_POST['price_ttc']);
1382 unset($_POST['tva_tx']);
1383 unset($_POST['product_ref']);
1384 unset($_POST['product_label']);
1385 unset($_POST['product_desc']);
1386 unset($_POST['fournprice']);
1387 unset($_POST['buying_price']);
1388 unset($_POST['np_marginRate']);
1389 unset($_POST['np_markRate']);
1390 unset($_POST['dp_desc']);
1391 unset($_POST['idprod']);
1392 unset($_POST['units']);
1393
1394 unset($_POST['date_starthour']);
1395 unset($_POST['date_startmin']);
1396 unset($_POST['date_startsec']);
1397 unset($_POST['date_startday']);
1398 unset($_POST['date_startmonth']);
1399 unset($_POST['date_startyear']);
1400 unset($_POST['date_endhour']);
1401 unset($_POST['date_endmin']);
1402 unset($_POST['date_endsec']);
1403 unset($_POST['date_endday']);
1404 unset($_POST['date_endmonth']);
1405 unset($_POST['date_endyear']);
1406 } else {
1407 $db->rollback();
1408
1409 setEventMessages($object->error, $object->errors, 'errors');
1410 }
1411 }
1412 }
1413 } elseif ($action == 'updateline' && $usercancreate && GETPOST('save')) {
1414 // Update a line within proposal
1415
1416 // Clean parameters
1417 $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml'));
1418
1419 // Define info_bits
1420 $info_bits = 0;
1421 if (preg_match('/\*/', GETPOST('tva_tx'))) {
1422 $info_bits |= 0x01;
1423 }
1424
1425 // Define vat_rate
1426 $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
1427 $vat_rate = str_replace('*', '', $vat_rate);
1428 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
1429 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
1430 $pu_ht = price2num(GETPOST('price_ht'), '', 2);
1431 $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
1432
1433 // Add buying price
1434 $fournprice = price2num(GETPOST('fournprice') ? GETPOST('fournprice') : '');
1435 $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''); // If buying_price is '0', we muste keep this value
1436
1437 $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
1438 $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
1439
1440 $date_start = dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear'));
1441 $date_end = dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear'));
1442
1443 $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1444 if (empty($remise_percent)) {
1445 $remise_percent = 0;
1446 }
1447
1448 // Prepare a price equivalent for minimum price check
1449 $pu_equivalent = $pu_ht;
1450 $pu_equivalent_ttc = $pu_ttc;
1451
1452 $currency_tx = $object->multicurrency_tx;
1453
1454 // Check if we have a foreign currency
1455 // If so, we update the pu_equiv as the equivalent price in base currency
1456 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1457 $pu_equivalent = $pu_ht_devise * $currency_tx;
1458 }
1459 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1460 $pu_equivalent_ttc = $pu_ttc_devise * $currency_tx;
1461 }
1462
1463 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1464 /*
1465 if ($pu_equivalent) {
1466 $tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
1467 $pu_equivalent_ttc = ...
1468 } else {
1469 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
1470 $pu_equivalent_ht = ...
1471 }
1472 */
1473
1474 // Extrafields
1475 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1476 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
1477 // Unset extrafield
1478 if (is_array($extralabelsline)) {
1479 // Get extra fields
1480 foreach ($extralabelsline as $key => $value) {
1481 unset($_POST["options_".$key]);
1482 }
1483 }
1484
1485 // Define special_code for special lines
1486 $special_code = GETPOST('special_code', 'int');
1487 if (!GETPOST('qty')) {
1488 $special_code = 3;
1489 }
1490
1491 // Check minimum price
1492 $productid = GETPOST('productid', 'int');
1493 if (!empty($productid)) {
1494 $product = new Product($db);
1495 $res = $product->fetch($productid);
1496
1497 $type = $product->type;
1498 $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
1499
1500 $price_min = $product->price_min;
1501 if (getDolGlobalString('PRODUIT_MULTIPRICES') && !empty($object->thirdparty->price_level)) {
1502 $price_min = $product->multiprices_min[$object->thirdparty->price_level];
1503 }
1504 $price_min_ttc = $product->price_min_ttc;
1505 if (getDolGlobalString('PRODUIT_MULTIPRICES') && !empty($object->thirdparty->price_level)) {
1506 $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
1507 }
1508
1509 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1510 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1511
1512 // Check price is not lower than minimum
1513 if ($usermustrespectpricemin) {
1514 if ($pu_equivalent && $price_min && ((price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < price2num($price_min)) && $price_base_type == 'HT') {
1515 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1516 setEventMessages($mesg, null, 'errors');
1517 $error++;
1518 $action = 'editline';
1519 } elseif ($pu_equivalent_ttc && $price_min_ttc && ((price2num($pu_equivalent_ttc) * (1 - (float) $remise_percent / 100)) < price2num($price_min_ttc)) && $price_base_type == 'TTC') {
1520 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1521 setEventMessages($mesg, null, 'errors');
1522 $error++;
1523 $action = 'editline';
1524 }
1525 }
1526 } else {
1527 $type = GETPOST('type');
1528 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1529
1530 // Check parameters
1531 if (GETPOST('type') < 0) {
1532 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1533 $error++;
1534 }
1535 }
1536
1537 if (!$error) {
1538 $db->begin();
1539
1540 if (!$user->hasRight('margins', 'creer')) {
1541 foreach ($object->lines as &$line) {
1542 if ($line->id == GETPOST('lineid', 'int')) {
1543 $fournprice = $line->fk_fournprice;
1544 $buyingprice = $line->pa_ht;
1545 break;
1546 }
1547 }
1548 }
1549
1550 $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
1551
1552 $pu = $pu_ht;
1553 $price_base_type = 'HT';
1554 if (empty($pu) && !empty($pu_ttc)) {
1555 $pu = $pu_ttc;
1556 $price_base_type = 'TTC';
1557 }
1558
1559 $result = $object->updateline(GETPOST('lineid', 'int'), $pu, $qty, $remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $description, $price_base_type, $info_bits, $special_code, GETPOST('fk_parent_line'), 0, $fournprice, $buyingprice, $label, $type, $date_start, $date_end, $array_options, GETPOST("units"), $pu_ht_devise);
1560
1561 if ($result >= 0) {
1562 $db->commit();
1563
1564 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1565 // Define output language
1566 $outputlangs = $langs;
1567 if (getDolGlobalInt('MAIN_MULTILANGS')) {
1568 $outputlangs = new Translate("", $conf);
1569 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
1570 $outputlangs->setDefaultLang($newlang);
1571 }
1572 $ret = $object->fetch($id); // Reload to get new records
1573 if ($ret > 0) {
1574 $object->fetch_thirdparty();
1575 }
1576 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1577 }
1578
1579 unset($_POST['qty']);
1580 unset($_POST['type']);
1581 unset($_POST['productid']);
1582 unset($_POST['remise_percent']);
1583 unset($_POST['price_ht']);
1584 unset($_POST['multicurrency_price_ht']);
1585 unset($_POST['price_ttc']);
1586 unset($_POST['tva_tx']);
1587 unset($_POST['product_ref']);
1588 unset($_POST['product_label']);
1589 unset($_POST['product_desc']);
1590 unset($_POST['fournprice']);
1591 unset($_POST['buying_price']);
1592
1593 unset($_POST['date_starthour']);
1594 unset($_POST['date_startmin']);
1595 unset($_POST['date_startsec']);
1596 unset($_POST['date_startday']);
1597 unset($_POST['date_startmonth']);
1598 unset($_POST['date_startyear']);
1599 unset($_POST['date_endhour']);
1600 unset($_POST['date_endmin']);
1601 unset($_POST['date_endsec']);
1602 unset($_POST['date_endday']);
1603 unset($_POST['date_endmonth']);
1604 unset($_POST['date_endyear']);
1605 } else {
1606 $db->rollback();
1607
1608 setEventMessages($object->error, $object->errors, 'errors');
1609 }
1610 }
1611 } elseif ($action == 'updateline' && $usercancreate && GETPOST('cancel', 'alpha')) {
1612 header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // Pour reaffichage de la fiche en cours d'edition
1613 exit();
1614 } elseif ($action == 'classin' && $usercancreate) {
1615 // Set project
1616 $object->setProject(GETPOST('projectid', 'int'));
1617 } elseif ($action == 'setavailability' && $usercancreate) {
1618 // Delivery time
1619 $result = $object->set_availability($user, GETPOST('availability_id', 'int'));
1620 } elseif ($action == 'setdemandreason' && $usercancreate) {
1621 // Origin of the commercial proposal
1622 $result = $object->set_demand_reason($user, GETPOST('demand_reason_id', 'int'));
1623 } elseif ($action == 'setconditions' && $usercancreate) {
1624 // Terms of payment
1625 $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int'), GETPOST('cond_reglement_id_deposit_percent', 'alpha'));
1626 //} elseif ($action == 'setremisepercent' && $usercancreate) {
1627 // $result = $object->set_remise_percent($user, price2num(GETPOST('remise_percent'), '', 2));
1628 //} elseif ($action == 'setremiseabsolue' && $usercancreate) {
1629 // $result = $object->set_remise_absolue($user, price2num(GETPOST('remise_absolue'), 'MU', 2));
1630 } elseif ($action == 'setmode' && $usercancreate) {
1631 // Payment choice
1632 $result = $object->setPaymentMethods(GETPOST('mode_reglement_id', 'int'));
1633 } elseif ($action == 'setmulticurrencycode' && $usercancreate) {
1634 // Multicurrency Code
1635 $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
1636 } elseif ($action == 'setmulticurrencyrate' && $usercancreate) {
1637 // Multicurrency rate
1638 $result = $object->setMulticurrencyRate(price2num(GETPOST('multicurrency_tx')), GETPOST('calculation_mode', 'int'));
1639 } elseif ($action == 'setbankaccount' && $usercancreate) {
1640 // bank account
1641 $result = $object->setBankAccount(GETPOST('fk_account', 'int'));
1642 } elseif ($action == 'setshippingmethod' && $usercancreate) {
1643 // shipping method
1644 $result = $object->setShippingMethod(GETPOST('shipping_method_id', 'int'));
1645 } elseif ($action == 'setwarehouse' && $usercancreate) {
1646 // warehouse
1647 $result = $object->setWarehouse(GETPOST('warehouse_id', 'int'));
1648 } elseif ($action == 'update_extras') {
1649 $object->oldcopy = dol_clone($object, 2);
1650 $attribute_name = GETPOST('attribute', 'restricthtml');
1651
1652 // Fill array 'array_options' with data from update form
1653 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
1654 if ($ret < 0) {
1655 $error++;
1656 }
1657 if (!$error) {
1658 $result = $object->updateExtraField($attribute_name, 'PROPAL_MODIFY');
1659 if ($result < 0) {
1660 setEventMessages($object->error, $object->errors, 'errors');
1661 $error++;
1662 }
1663 }
1664 if ($error) {
1665 $action = 'edit_extras';
1666 }
1667 }
1668
1669 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB') && $usercancreate) {
1670 if ($action == 'addcontact') {
1671 if ($object->id > 0) {
1672 $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'));
1673 $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
1674 $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
1675 }
1676
1677 if ($result >= 0) {
1678 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
1679 exit();
1680 } else {
1681 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1682 $langs->load("errors");
1683 setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
1684 } else {
1685 setEventMessages($object->error, $object->errors, 'errors');
1686 }
1687 }
1688 } elseif ($action == 'swapstatut') {
1689 // Toggle the status of a contact
1690 if ($object->fetch($id) > 0) {
1691 $result = $object->swapContactStatus(GETPOST('ligne', 'int'));
1692 } else {
1693 dol_print_error($db);
1694 }
1695 } elseif ($action == 'deletecontact') {
1696 // Delete a contact
1697 $object->fetch($id);
1698 $result = $object->delete_contact($lineid);
1699
1700 if ($result >= 0) {
1701 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
1702 exit();
1703 } else {
1704 dol_print_error($db);
1705 }
1706 }
1707 }
1708
1709 // Actions to build doc
1710 $upload_dir = !empty($conf->propal->multidir_output[$object->entity]) ? $conf->propal->multidir_output[$object->entity] : $conf->propal->dir_output;
1711 $permissiontoadd = $usercancreate;
1712 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
1713}
1714
1715
1716/*
1717 * View
1718 */
1719
1720$form = new Form($db);
1721$formfile = new FormFile($db);
1722$formpropal = new FormPropal($db);
1723$formmargin = new FormMargin($db);
1724if (isModEnabled('project')) {
1725 $formproject = new FormProjets($db);
1726}
1727
1728$title = $object->ref." - ".$langs->trans('Card');
1729if ($action == 'create') {
1730 $title = $langs->trans("NewPropal");
1731}
1732$help_url = 'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos|DE:Modul_Angebote';
1733
1734llxHeader('', $title, $help_url);
1735
1736$now = dol_now();
1737
1738// Add new proposal
1739if ($action == 'create') {
1740 $currency_code = $conf->currency;
1741
1742 print load_fiche_titre($langs->trans("NewProp"), '', 'propal');
1743
1744 $soc = new Societe($db);
1745 if ($socid > 0) {
1746 $res = $soc->fetch($socid);
1747 }
1748
1749 $currency_code = $conf->currency;
1750
1751 $cond_reglement_id = GETPOST('cond_reglement_id', 'int');
1752 $deposit_percent = GETPOST('cond_reglement_id_deposit_percent', 'alpha');
1753 $mode_reglement_id = GETPOST('mode_reglement_id', 'int');
1754 $fk_account = GETPOST('fk_account', 'int');
1755
1756 // Load objectsrc
1757 if (!empty($origin) && !empty($originid)) {
1758 // Parse element/subelement (ex: project_task)
1759 $element = $subelement = $origin;
1760 $regs = array();
1761 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
1762 $element = $regs[1];
1763 $subelement = $regs[2];
1764 }
1765
1766 if ($element == 'project') {
1767 $projectid = $originid;
1768 } else {
1769 // For compatibility
1770 if ($element == 'order' || $element == 'commande') {
1771 $element = $subelement = 'commande';
1772 }
1773 if ($element == 'propal') {
1774 $element = 'comm/propal';
1775 $subelement = 'propal';
1776 }
1777 if ($element == 'contract') {
1778 $element = $subelement = 'contrat';
1779 }
1780 if ($element == 'shipping') {
1781 $element = $subelement = 'expedition';
1782 }
1783
1784 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
1785
1786 $classname = ucfirst($subelement);
1787 $objectsrc = new $classname($db);
1788 $objectsrc->fetch($originid);
1789 if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
1790 $objectsrc->fetch_lines();
1791 }
1792 $objectsrc->fetch_thirdparty();
1793
1794 $projectid = (!empty($objectsrc->fk_project) ? $objectsrc->fk_project : 0);
1795 $ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : '');
1796
1797 $soc = $objectsrc->thirdparty;
1798
1799 $cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0));
1800 $mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
1801 $warehouse_id = (!empty($objectsrc->warehouse_id) ? $objectsrc->warehouse_id : (!empty($soc->warehouse_id) ? $soc->warehouse_id : 0));
1802
1803 // Replicate extrafields
1804 $objectsrc->fetch_optionals();
1805 $object->array_options = $objectsrc->array_options;
1806
1807 if (isModEnabled("multicurrency")) {
1808 if (!empty($objectsrc->multicurrency_code)) {
1809 $currency_code = $objectsrc->multicurrency_code;
1810 }
1811 if (getDolGlobalString('MULTICURRENCY_USE_ORIGIN_TX') && !empty($objectsrc->multicurrency_tx)) {
1812 $currency_tx = $objectsrc->multicurrency_tx;
1813 }
1814 }
1815 }
1816 } else {
1817 $cond_reglement_id = empty($soc->cond_reglement_id) ? $cond_reglement_id : $soc->cond_reglement_id;
1818 $deposit_percent = empty($soc->deposit_percent) ? $deposit_percent : $soc->deposit_percent;
1819 $mode_reglement_id = empty($soc->mode_reglement_id) ? $mode_reglement_id : $soc->mode_reglement_id;
1820 $fk_account = empty($soc->fk_account) ? $fk_account : $soc->fk_account;
1821 $shipping_method_id = $soc->shipping_method_id;
1822 $warehouse_id = $soc->fk_warehouse;
1823 $remise_percent = $soc->remise_percent;
1824
1825 if (isModEnabled("multicurrency") && !empty($soc->multicurrency_code)) {
1826 $currency_code = $soc->multicurrency_code;
1827 }
1828 }
1829
1830 // If form was posted (but error returned), we must reuse the value posted in priority (standard Dolibarr behaviour)
1831 if (!GETPOST('changecompany')) {
1832 if (GETPOSTISSET('cond_reglement_id')) {
1833 $cond_reglement_id = GETPOST('cond_reglement_id', 'int');
1834 }
1835 if (GETPOSTISSET('deposit_percent')) {
1836 $deposit_percent = price2num(GETPOST('deposit_percent', 'alpha'));
1837 }
1838 if (GETPOSTISSET('mode_reglement_id')) {
1839 $mode_reglement_id = GETPOST('mode_reglement_id', 'int');
1840 }
1841 if (GETPOSTISSET('cond_reglement_id')) {
1842 $fk_account = GETPOST('fk_account', 'int');
1843 }
1844 }
1845
1846 // Warehouse default if null
1847 if ($soc->fk_warehouse > 0) {
1848 $warehouse_id = $soc->fk_warehouse;
1849 }
1850 if (isModEnabled('stock') && empty($warehouse_id) && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_ORDER')) {
1851 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE')) {
1852 $warehouse_id = $conf->global->MAIN_DEFAULT_WAREHOUSE;
1853 }
1854 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER')) {
1855 $warehouse_id = $user->fk_warehouse;
1856 }
1857 }
1858
1859 print '<form name="addprop" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
1860 print '<input type="hidden" name="token" value="'.newToken().'">';
1861 print '<input type="hidden" name="action" value="add">';
1862 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
1863 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
1864 if ($origin != 'project' && $originid) {
1865 print '<input type="hidden" name="origin" value="'.$origin.'">';
1866 print '<input type="hidden" name="originid" value="'.$originid.'">';
1867 } elseif ($origin == 'project' && !empty($projectid)) {
1868 print '<input type="hidden" name="projectid" value="'.$projectid.'">';
1869 }
1870
1871 print dol_get_fiche_head();
1872
1873 // Call Hook tabContentCreateProposal
1874 $parameters = array();
1875 // Note that $action and $object may be modified by hook
1876 $reshook = $hookmanager->executeHooks('tabContentCreateProposal', $parameters, $object, $action);
1877 if (empty($reshook)) {
1878 print '<table class="border centpercent">';
1879
1880 // Reference
1881 print '<tr class="field_ref"><td class="titlefieldcreate fieldrequired">'.$langs->trans('Ref').'</td><td class="valuefieldcreate">'.$langs->trans("Draft").'</td></tr>';
1882
1883 // Ref customer
1884 print '<tr class="field_ref_client"><td class="titlefieldcreate">'.$langs->trans('RefCustomer').'</td><td class="valuefieldcreate">';
1885 print '<input type="text" name="ref_client" value="'.(!empty($ref_client) ? $ref_client : GETPOST('ref_client')).'"></td>';
1886 print '</tr>';
1887
1888 // Third party
1889 print '<tr class="field_socid">';
1890 print '<td class="titlefieldcreate fieldrequired">'.$langs->trans('Customer').'</td>';
1891 $shipping_method_id = 0;
1892 if ($socid > 0) {
1893 print '<td class="valuefieldcreate">';
1894 print $soc->getNomUrl(1, 'customer');
1895 print '<input type="hidden" name="socid" value="'.$soc->id.'">';
1896 print '</td>';
1897 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
1898 $shipping_method_id = $soc->shipping_method_id;
1899 }
1900 //$warehouse_id = $soc->warehouse_id;
1901 } else {
1902 print '<td class="valuefieldcreate">';
1903 $filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
1904 print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company('', 'socid', $filter, 'SelectThirdParty', 1, 0, null, 0, 'minwidth300 maxwidth500 widthcentpercentminusxx');
1905 // reload page to retrieve customer informations
1906 if (!getDolGlobalString('RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED')) {
1907 print '<script>
1908 $(document).ready(function() {
1909 $("#socid").change(function() {
1910 console.log("We have changed the company - Reload page");
1911 var socid = $(this).val();
1912 // reload page
1913 $("input[name=action]").val("create");
1914 $("input[name=changecompany]").val("1");
1915 $("form[name=addprop]").submit();
1916 });
1917 });
1918 </script>';
1919 }
1920 print ' <a href="'.DOL_URL_ROOT.'/societe/card.php?action=create&client=3&fournisseur=0&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create').'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddThirdParty").'"></span></a>';
1921 print '</td>';
1922 }
1923 print '</tr>'."\n";
1924
1925 if ($socid > 0) {
1926 // Contacts (ask contact only if thirdparty already defined).
1927 print '<tr class="field_contactid"><td class="titlefieldcreate">'.$langs->trans("DefaultContact").'</td><td class="valuefieldcreate">';
1928 print img_picto('', 'contact', 'class="pictofixedwidth"');
1929 print $form->selectcontacts($soc->id, $contactid, 'contactid', 1, '', '', 0, 'minwidth300');
1930 print '</td></tr>';
1931
1932 // Third party discounts info line
1933 print '<tr class="field_discount_info"><td class="titlefieldcreate">'.$langs->trans('Discounts').'</td><td class="valuefieldcreate">';
1934
1935 $absolute_discount = $soc->getAvailableDiscounts();
1936
1937 $thirdparty = $soc;
1938 $discount_type = 0;
1939 $backtopage = $_SERVER["PHP_SELF"].'?socid='.$thirdparty->id.'&action='.$action.'&origin='.urlencode(GETPOST('origin')).'&originid='.urlencode(GETPOSTINT('originid'));
1940 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
1941 print '</td></tr>';
1942 }
1943
1944 // Date
1945 print '<tr class="field_addprop"><td class="titlefieldcreate fieldrequired">'.$langs->trans('DatePropal').'</td><td class="valuefieldcreate">';
1946 print img_picto('', 'action', 'class="pictofixedwidth"');
1947 print $form->selectDate('', '', '', '', '', "addprop", 1, 1);
1948 print '</td></tr>';
1949
1950 // Validaty duration
1951 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') : $conf->global->PROPALE_VALIDITY_DURATION).'"> '.$langs->trans("days").'</td></tr>';
1952
1953 // Terms of payment
1954 print '<tr class="field_cond_reglement_id"><td class="nowrap">'.$langs->trans('PaymentConditionsShort').'</td><td>';
1955 print img_picto('', 'payment', 'class="pictofixedwidth"');
1956 // at last resort we take the payment term id which may be filled by default values set (if not getpostisset)
1957 print $form->getSelectConditionsPaiements($cond_reglement_id, 'cond_reglement_id', 1, 1, 0, '', $deposit_percent);
1958 print '</td></tr>';
1959
1960 // Mode of payment
1961 print '<tr class="field_mode_reglement_id"><td class="titlefieldcreate">'.$langs->trans('PaymentMode').'</td><td class="valuefieldcreate">';
1962 print img_picto('', 'bank', 'class="pictofixedwidth"');
1963 print $form->select_types_paiements($mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
1964 print '</td></tr>';
1965
1966 // Bank Account
1967 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("banque")) {
1968 print '<tr class="field_fk_account"><td class="titlefieldcreate">'.$langs->trans('BankAccount').'</td><td class="valuefieldcreate">';
1969 print img_picto('', 'bank_account', 'class="pictofixedwidth"').$form->select_comptes($fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
1970 print '</td></tr>';
1971 }
1972
1973 // Source / Channel - What trigger creation
1974 print '<tr class="field_demand_reason_id"><td class="titlefieldcreate">'.$langs->trans('Source').'</td><td class="valuefieldcreate">';
1975 print img_picto('', 'question', 'class="pictofixedwidth"');
1976 $form->selectInputReason((GETPOSTISSET('demand_reason_id') ? GETPOST('demand_reason_id', 'int') : ''), 'demand_reason_id', "SRC_PROP", 1, 'maxwidth200 widthcentpercentminusx');
1977 print '</td></tr>';
1978
1979 // Shipping Method
1980 if (isModEnabled("expedition")) {
1981 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
1982 $shipping_method_id = $soc->shipping_method_id;
1983 }
1984 print '<tr class="field_shipping_method_id"><td class="titlefieldcreate">'.$langs->trans('SendingMethod').'</td><td class="valuefieldcreate">';
1985 print img_picto('', 'dolly', 'class="pictofixedwidth"');
1986 $form->selectShippingMethod((GETPOSTISSET('shipping_method_id') ? GETPOST('shipping_method_id', 'int') : $shipping_method_id), 'shipping_method_id', '', 1, '', 0, 'maxwidth200 widthcentpercentminusx');
1987 print '</td></tr>';
1988 }
1989
1990 // Warehouse
1991 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
1992 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
1993 $formproduct = new FormProduct($db);
1994 print '<tr class="field_warehouse_id"><td class="titlefieldcreate">'.$langs->trans('Warehouse').'</td><td class="valuefieldcreate">';
1995 print img_picto('', 'stock', 'class="pictofixedwidth"').$formproduct->selectWarehouses($warehouse_id, 'warehouse_id', '', 1, 0, 0, '', 0, 0, array(), 'maxwidth500 widthcentpercentminusxx');
1996 print '</td></tr>';
1997 }
1998
1999 // Delivery delay
2000 print '<tr class="field_availability_id"><td class="titlefieldcreate">'.$langs->trans('AvailabilityPeriod');
2001 if (isModEnabled('commande')) {
2002 print ' ('.$langs->trans('AfterOrder').')';
2003 }
2004 print '</td><td class="valuefieldcreate">';
2005 print img_picto('', 'clock', 'class="pictofixedwidth"');
2006 $form->selectAvailabilityDelay((GETPOSTISSET('availability_id') ? GETPOST('availability_id', 'int') : ''), 'availability_id', '', 1, 'maxwidth200 widthcentpercentminusx');
2007 print '</td></tr>';
2008
2009 // Delivery date (or manufacturing)
2010 print '<tr class="field_date_livraison"><td class="titlefieldcreate">'.$langs->trans("DeliveryDate").'</td>';
2011 print '<td class="valuefieldcreate">';
2012 print img_picto('', 'action', 'class="pictofixedwidth"');
2013 if (is_numeric(getDolGlobalString('DATE_LIVRAISON_WEEK_DELAY'))) { // If value set to 0 or a num, not empty
2014 $tmpdte = time() + (7 * getDolGlobalInt('DATE_LIVRAISON_WEEK_DELAY') * 24 * 60 * 60);
2015 $syear = date("Y", $tmpdte);
2016 $smonth = date("m", $tmpdte);
2017 $sday = date("d", $tmpdte);
2018 print $form->selectDate($syear."-".$smonth."-".$sday, 'date_livraison', '', '', '', "addprop");
2019 } else {
2020 print $form->selectDate(-1, 'date_livraison', '', '', '', "addprop", 1, 1);
2021 }
2022 print '</td></tr>';
2023
2024 // Project
2025 if (isModEnabled('project')) {
2026 $langs->load("projects");
2027 print '<tr class="field_projectid">';
2028 print '<td class="titlefieldcreate">'.$langs->trans("Project").'</td><td class="valuefieldcreate">';
2029 print img_picto('', 'project', 'class="pictofixedwidth"').$formproject->select_projects(($soc->id > 0 ? $soc->id : -1), $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500 widthcentpercentminusxx');
2030 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>';
2031 print '</td>';
2032 print '</tr>';
2033 }
2034
2035 // Incoterms
2036 if (isModEnabled('incoterm')) {
2037 print '<tr class="field_incoterm_id">';
2038 print '<td class="titlefieldcreate"><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), $soc->label_incoterms, 1).'</label></td>';
2039 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2040 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
2041 print $form->select_incoterms((!empty($soc->fk_incoterms) ? $soc->fk_incoterms : ''), (!empty($soc->location_incoterms) ? $soc->location_incoterms : ''));
2042 print '</td></tr>';
2043 }
2044
2045 // Template to use by default
2046 print '<tr class="field_model">';
2047 print '<td class="titlefieldcreate">'.$langs->trans("DefaultModel").'</td>';
2048 print '<td class="valuefieldcreate">';
2049 print img_picto('', 'pdf', 'class="pictofixedwidth"');
2051 $preselected = (getDolGlobalString('PROPALE_ADDON_PDF_ODT_DEFAULT') ? $conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT : getDolGlobalString("PROPALE_ADDON_PDF"));
2052 print $form->selectarray('model', $liste, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
2053 print "</td></tr>";
2054
2055 // Multicurrency
2056 if (isModEnabled("multicurrency")) {
2057 print '<tr class="field_currency">';
2058 print '<td class="titlefieldcreate">'.$form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0).'</td>';
2059 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2060 print img_picto('', 'currency', 'class="pictofixedwidth"').$form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0);
2061 print '</td></tr>';
2062 }
2063
2064 // Public note
2065 print '<tr class="field_note_public">';
2066 print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePublic').'</td>';
2067 print '<td class="valuefieldcreate">';
2068 $note_public = $object->getDefaultCreateValueFor('note_public', (!empty($objectsrc) ? $objectsrc->note_public : (getDolGlobalString('PROPALE_ADDON_NOTE_PUBLIC_DEFAULT') ? $conf->global->PROPALE_ADDON_NOTE_PUBLIC_DEFAULT : null)), 'restricthtml');
2069 $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
2070 print $doleditor->Create(1);
2071
2072 // Private note
2073 if (empty($user->socid)) {
2074 print '<tr class="field_note_private">';
2075 print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePrivate').'</td>';
2076 print '<td class="valuefieldcreate">';
2077 $note_private = $object->getDefaultCreateValueFor('note_private', ((!empty($origin) && !empty($originid) && is_object($objectsrc)) ? $objectsrc->note_private : null));
2078 $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
2079 print $doleditor->Create(1);
2080 // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
2081 print '</td></tr>';
2082 }
2083
2084 // Other attributes
2085 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
2086
2087 // Lines from source
2088 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2089 // TODO for compatibility
2090 if ($origin == 'contrat') {
2091 // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
2092 //$objectsrc->remise_absolue = $remise_absolue; // deprecated
2093 //$objectsrc->remise_percent = $remise_percent;
2094 $objectsrc->update_price(1, 'auto', 1);
2095 }
2096
2097 print "\n<!-- ".$classname." info -->";
2098 print "\n";
2099 print '<input type="hidden" name="amount" value="'.$objectsrc->total_ht.'">'."\n";
2100 print '<input type="hidden" name="total" value="'.$objectsrc->total_ttc.'">'."\n";
2101 print '<input type="hidden" name="tva" value="'.$objectsrc->total_tva.'">'."\n";
2102 print '<input type="hidden" name="origin" value="'.$objectsrc->element.'">';
2103 print '<input type="hidden" name="originid" value="'.$objectsrc->id.'">';
2104
2105 $newclassname = $classname;
2106 if ($newclassname == 'Propal') {
2107 $newclassname = 'CommercialProposal';
2108 } elseif ($newclassname == 'Commande') {
2109 $newclassname = 'Order';
2110 } elseif ($newclassname == 'Expedition') {
2111 $newclassname = 'Sending';
2112 } elseif ($newclassname == 'Fichinter') {
2113 $newclassname = 'Intervention';
2114 }
2115
2116 print '<tr><td>'.$langs->trans($newclassname).'</td><td>'.$objectsrc->getNomUrl(1).'</td></tr>';
2117 print '<tr><td>'.$langs->trans('AmountHT').'</td><td>'.price($objectsrc->total_ht, 0, $langs, 1, -1, -1, $conf->currency).'</td></tr>';
2118 print '<tr><td>'.$langs->trans('AmountVAT').'</td><td>'.price($objectsrc->total_tva, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2119 if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
2120 print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2121 }
2122
2123 if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
2124 print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2125 }
2126 print '<tr><td>'.$langs->trans('AmountTTC').'</td><td>'.price($objectsrc->total_ttc, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2127
2128 if (isModEnabled("multicurrency")) {
2129 print '<tr><td>'.$langs->trans('MulticurrencyAmountHT').'</td><td>'.price($objectsrc->multicurrency_total_ht).'</td></tr>';
2130 print '<tr><td>'.$langs->trans('MulticurrencyAmountVAT').'</td><td>'.price($objectsrc->multicurrency_total_tva)."</td></tr>";
2131 print '<tr><td>'.$langs->trans('MulticurrencyAmountTTC').'</td><td>'.price($objectsrc->multicurrency_total_ttc)."</td></tr>";
2132 }
2133 }
2134
2135 print "</table>\n";
2136
2137
2138 /*
2139 * Combobox for copy function
2140 */
2141
2142 if (!getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2143 print '<input type="hidden" name="createmode" value="empty">';
2144 }
2145
2146 if (getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2147 print '<br><table>';
2148
2149 // For backward compatibility
2150 print '<tr>';
2151 print '<td><input type="radio" name="createmode" value="copy"></td>';
2152 print '<td>'.$langs->trans("CopyPropalFrom").' </td>';
2153 print '<td>';
2154 $liste_propal = array();
2155 $liste_propal [0] = '';
2156
2157 $sql = "SELECT p.rowid as id, p.ref, s.nom";
2158 $sql .= " FROM ".MAIN_DB_PREFIX."propal p";
2159 $sql .= ", ".MAIN_DB_PREFIX."societe s";
2160 $sql .= " WHERE s.rowid = p.fk_soc";
2161 $sql .= " AND p.entity IN (".getEntity('propal').")";
2162 $sql .= " AND p.fk_statut <> 0";
2163 $sql .= " ORDER BY Id";
2164
2165 $resql = $db->query($sql);
2166 if ($resql) {
2167 $num = $db->num_rows($resql);
2168 $i = 0;
2169 while ($i < $num) {
2170 $row = $db->fetch_row($resql);
2171 $propalRefAndSocName = $row[1]." - ".$row[2];
2172 $liste_propal[$row[0]] = $propalRefAndSocName;
2173 $i++;
2174 }
2175 print $form->selectarray("copie_propal", $liste_propal, 0);
2176 } else {
2177 dol_print_error($db);
2178 }
2179 print '</td></tr>';
2180
2181 print '<tr><td class="tdtop"><input type="radio" name="createmode" value="empty" checked></td>';
2182 print '<td valign="top" colspan="2">'.$langs->trans("CreateEmptyPropal").'</td></tr>';
2183 print '</table>';
2184 }
2185 }
2186
2187 print dol_get_fiche_end();
2188
2189 $langs->load("bills");
2190
2191 print $form->buttonsSaveCancel("CreateDraft");
2192
2193 print "</form>";
2194
2195
2196 // Show origin lines
2197 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2198 print '<br>';
2199
2200 $title = $langs->trans('ProductsAndServices');
2201 print load_fiche_titre($title);
2202
2203 print '<div class="div-table-responsive-no-min">';
2204 print '<table class="noborder centpercent">';
2205
2206 $objectsrc->printOriginLinesList();
2207
2208 print '</table>';
2209 print '</div>';
2210 }
2211} elseif ($object->id > 0) {
2212 /*
2213 * Show object in view mode
2214 */
2215 $object->fetch_thirdparty();
2216 if ($object->thirdparty) {
2217 $soc = $object->thirdparty;
2218 } else {
2219 $soc = new Societe($db);
2220 }
2221
2222 $head = propal_prepare_head($object);
2223 print dol_get_fiche_head($head, 'comm', $langs->trans('Proposal'), -1, 'propal');
2224
2225 $formconfirm = '';
2226
2227 // Clone confirmation
2228 if ($action == 'clone') {
2229 // Create an array for form
2230 $filter = '(s.client:IN:1,2,3)';
2231 $formquestion = array(
2232 // 'text' => $langs->trans("ConfirmClone"),
2233 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
2234 array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOST('socid', 'int'), 'socid', $filter, '', 0, 0, null, 0, 'maxwidth300')),
2235 array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => 0),
2236 array('type' => 'checkbox', 'name' => 'update_desc', 'label' => $langs->trans('PuttingDescUpToDate'), 'value' => 0),
2237 );
2238 if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY') && !empty($object->delivery_date)) {
2239 $formquestion[] = array('type' => 'date', 'name' => 'date_delivery', 'label' => $langs->trans("DeliveryDate"), 'value' => $object->delivery_date);
2240 }
2241 // Incomplete payment. We ask if reason = discount or other
2242 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmClonePropal', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
2243 }
2244
2245 if ($action == 'closeas') {
2246 //Form to close proposal (signed or not)
2247 $formquestion = array();
2248 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
2249 $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)));
2250 }
2251 $formquestion[] = array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"), 'value' => ''); // Field to complete private note (not replace)
2252
2253 if (getDolGlobalInt('PROPOSAL_SUGGEST_DOWN_PAYMENT_INVOICE_CREATION')) {
2254 // This is a hidden option:
2255 // Suggestion to create invoice during proposal signature is not enabled by default.
2256 // Such choice should be managed by the workflow module and trigger. This option generates conflicts with some setup.
2257 // It may also break step of creating an order when invoicing must be done from orders and not from proposal
2258 $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
2259
2260 if (!empty($deposit_percent_from_payment_terms) && isModEnabled('facture') && $user->hasRight('facture', 'creer')) {
2261 require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
2262
2263 $object->fetchObjectLinked();
2264
2265 $eligibleForDepositGeneration = true;
2266
2267 if (array_key_exists('facture', $object->linkedObjects)) {
2268 foreach ($object->linkedObjects['facture'] as $invoice) {
2269 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2270 $eligibleForDepositGeneration = false;
2271 break;
2272 }
2273 }
2274 }
2275
2276 if ($eligibleForDepositGeneration && array_key_exists('commande', $object->linkedObjects)) {
2277 foreach ($object->linkedObjects['commande'] as $order) {
2278 $order->fetchObjectLinked();
2279
2280 if (array_key_exists('facture', $order->linkedObjects)) {
2281 foreach ($order->linkedObjects['facture'] as $invoice) {
2282 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2283 $eligibleForDepositGeneration = false;
2284 break 2;
2285 }
2286 }
2287 }
2288 }
2289 }
2290
2291
2292 if ($eligibleForDepositGeneration) {
2293 $formquestion[] = array(
2294 'type' => 'checkbox',
2295 'tdclass' => 'showonlyifsigned',
2296 'name' => 'generate_deposit',
2297 'morecss' => 'margintoponly marginbottomonly',
2298 'label' => $form->textwithpicto($langs->trans('GenerateDeposit', $object->deposit_percent), $langs->trans('DepositGenerationPermittedByThePaymentTermsSelected'))
2299 );
2300
2301 $formquestion[] = array(
2302 'type' => 'date',
2303 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2304 'name' => 'datef',
2305 'label' => $langs->trans('DateInvoice'),
2306 'value' => dol_now(),
2307 'datenow' => true
2308 );
2309
2310 if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
2311 $formquestion[] = array(
2312 'type' => 'date',
2313 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2314 'name' => 'date_pointoftax',
2315 'label' => $langs->trans('DatePointOfTax'),
2316 'value' => dol_now(),
2317 'datenow' => true
2318 );
2319 }
2320
2321 $paymentTermsSelect = $form->getSelectConditionsPaiements(0, 'cond_reglement_id', -1, 0, 1, 'minwidth200');
2322
2323 $formquestion[] = array(
2324 'type' => 'other',
2325 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2326 'name' => 'cond_reglement_id',
2327 'label' => $langs->trans('PaymentTerm'),
2328 'value' => $paymentTermsSelect
2329 );
2330
2331 $formquestion[] = array(
2332 'type' => 'checkbox',
2333 'tdclass' => 'showonlyifgeneratedeposit',
2334 'name' => 'validate_generated_deposit',
2335 'morecss' => 'margintoponly marginbottomonly',
2336 'label' => $langs->trans('ValidateGeneratedDeposit')
2337 );
2338
2339 $formquestion[] = array(
2340 'type' => 'onecolumn',
2341 'value' => '
2342 <script>
2343 let signedValue = ' . $object::STATUS_SIGNED . ';
2344
2345 $(document).ready(function() {
2346 $("[name=generate_deposit]").change(function () {
2347 let $self = $(this);
2348 let $target = $(".showonlyifgeneratedeposit").parent(".tagtr");
2349
2350 if (! $self.parents(".tagtr").is(":hidden") && $self.is(":checked")) {
2351 $target.show();
2352 } else {
2353 $target.hide();
2354 }
2355
2356 return true;
2357 });
2358
2359 $("#statut").change(function() {
2360 let $target = $(".showonlyifsigned").parent(".tagtr");
2361
2362 if ($(this).val() == signedValue) {
2363 $target.show();
2364 } else {
2365 $target.hide();
2366 }
2367
2368 $("[name=generate_deposit]").trigger("change");
2369
2370 return true;
2371 });
2372
2373 $("#statut").trigger("change");
2374 });
2375 </script>
2376 '
2377 );
2378 }
2379 }
2380 }
2381
2382 if (isModEnabled('notification')) {
2383 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2384 $notify = new Notify($db);
2385 $formquestion = array_merge($formquestion, array(
2386 array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PROPAL_CLOSE_SIGNED', $object->socid, $object)),
2387 ));
2388 }
2389
2390 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
2391 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetAcceptedRefused'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2392 } else {
2393 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?statut=3&id=' . $object->id, $langs->trans('Close'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2394 }
2395 } elseif ($action == 'delete') {
2396 // Confirm delete
2397 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteProp'), $langs->trans('ConfirmDeleteProp', $object->ref), 'confirm_delete', '', 0, 1);
2398 } elseif ($action == 'reopen') {
2399 // Confirm reopen
2400 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenProp', $object->ref), 'confirm_reopen', '', 0, 1);
2401 } elseif ($action == 'ask_deleteline') {
2402 // Confirmation delete product/service line
2403 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 0, 1);
2404 } elseif ($action == 'validate') {
2405 // Confirm validate proposal
2406 $error = 0;
2407
2408 // We verify whether the object is provisionally numbering
2409 $ref = substr($object->ref, 1, 4);
2410 if ($ref == 'PROV' || $ref == '') {
2411 $numref = $object->getNextNumRef($soc);
2412 if (empty($numref)) {
2413 $error++;
2414 setEventMessages($object->error, $object->errors, 'errors');
2415 }
2416 } else {
2417 $numref = $object->ref;
2418 }
2419
2420 $text = $langs->trans('ConfirmValidateProp', $numref);
2421 if (isModEnabled('notification')) {
2422 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2423 $notify = new Notify($db);
2424 $text .= '<br>';
2425 $text .= $notify->confirmMessage('PROPAL_VALIDATE', $object->socid, $object);
2426 }
2427
2428 // mandatoryPeriod
2429 $nbMandated = 0;
2430 foreach ($object->lines as $line) {
2431 $res = $line->fetch_product();
2432 if ($res > 0) {
2433 if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end))) {
2434 $nbMandated++;
2435 break;
2436 }
2437 }
2438 }
2439 if ($nbMandated > 0) {
2440 $text .= '<div><span class="clearboth nowraponall warning">'.$langs->trans("mandatoryPeriodNeedTobeSetMsgValidate").'</span></div>';
2441 }
2442
2443 if (!$error) {
2444 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateProp'), $text, 'confirm_validate', '', 0, 1);
2445 }
2446 }
2447
2448 // Call Hook formConfirm
2449 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
2450 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2451 if (empty($reshook)) {
2452 $formconfirm .= $hookmanager->resPrint;
2453 } elseif ($reshook > 0) {
2454 $formconfirm = $hookmanager->resPrint;
2455 }
2456
2457 // Print form confirm
2458 print $formconfirm;
2459
2460
2461 // Proposal card
2462
2463 $linkback = '<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
2464
2465 $morehtmlref = '<div class="refidno">';
2466 // Ref customer
2467 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
2468 $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);
2469 // Thirdparty
2470 $morehtmlref .= '<br><span class="hideonsmartphone">'.$langs->trans('ThirdParty').' : </span>'.$soc->getNomUrl(1, 'customer');
2471 if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $soc->id > 0) {
2472 $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?socid='.$soc->id.'&search_societe='.urlencode($soc->name).'">'.$langs->trans("OtherProposals").'</a>)';
2473 }
2474 // Project
2475 if (isModEnabled('project')) {
2476 $langs->load("projects");
2477 $morehtmlref .= '<br>';
2478 if ($usercancreate) {
2479 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
2480 if ($action != 'classify') {
2481 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
2482 }
2483 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
2484 } else {
2485 if (!empty($object->fk_project)) {
2486 $proj = new Project($db);
2487 $proj->fetch($object->fk_project);
2488 $morehtmlref .= $proj->getNomUrl(1);
2489 if ($proj->title) {
2490 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
2491 }
2492 }
2493 }
2494 }
2495 $morehtmlref .= '</div>';
2496
2497
2498 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
2499
2500 // Call Hook tabContentViewProposal
2501 $parameters = array();
2502 // Note that $action and $object may be modified by hook
2503 $reshook = $hookmanager->executeHooks('tabContentViewProposal', $parameters, $object, $action);
2504 if (empty($reshook)) {
2505 print '<div class="fichecenter">';
2506 print '<div class="fichehalfleft">';
2507 print '<div class="underbanner clearboth"></div>';
2508
2509 print '<table class="border tableforfield centpercent">';
2510
2511 // Link for thirdparty discounts
2512 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
2513 $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
2514 $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
2515 } else {
2516 $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
2517 $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
2518 }
2519
2520 print '<tr><td class="titlefield">'.$langs->trans('Discounts').'</td><td>';
2521
2522 $absolute_discount = $soc->getAvailableDiscounts('', $filterabsolutediscount);
2523 $absolute_creditnote = $soc->getAvailableDiscounts('', $filtercreditnote);
2524 $absolute_discount = price2num($absolute_discount, 'MT');
2525 $absolute_creditnote = price2num($absolute_creditnote, 'MT');
2526
2527 $caneditfield = ($object->statut != Propal::STATUS_SIGNED && $object->statut != Propal::STATUS_BILLED);
2528
2529 $thirdparty = $soc;
2530 $discount_type = 0;
2531 $backtopage = $_SERVER["PHP_SELF"].'?id='.$object->id;
2532 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
2533
2534 print '</td></tr>';
2535
2536 // Date of proposal
2537 print '<tr>';
2538 print '<td>';
2539 // print '<table class="nobordernopadding" width="100%"><tr><td>';
2540 // print $langs->trans('DatePropal');
2541 // print '</td>';
2542 // if ($action != 'editdate' && $usercancreate && $caneditfield) {
2543 // 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>';
2544 // }
2545
2546 // print '</tr></table>';
2547 $editenable = $usercancreate && $caneditfield && $object->statut == Propal::STATUS_DRAFT;
2548 print $form->editfieldkey("DatePropal", 'date', '', $object, $editenable);
2549 print '</td><td class="valuefield">';
2550 if ($action == 'editdate' && $usercancreate && $caneditfield) {
2551 print '<form name="editdate" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2552 print '<input type="hidden" name="token" value="'.newToken().'">';
2553 print '<input type="hidden" name="action" value="setdate">';
2554 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2555 print $form->selectDate($object->date, 're', '', '', 0, "editdate");
2556 print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
2557 print '</form>';
2558 } else {
2559 if ($object->date) {
2560 print dol_print_date($object->date, 'day');
2561 } else {
2562 print '&nbsp;';
2563 }
2564 }
2565 print '</td>';
2566
2567 // Date end proposal
2568 print '<tr>';
2569 print '<td>';
2570 print '<table class="nobordernopadding centpercent"><tr><td>';
2571 print $langs->trans('DateEndPropal');
2572 print '</td>';
2573 if ($action != 'editecheance' && $usercancreate && $caneditfield) {
2574 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>';
2575 }
2576 print '</tr></table>';
2577 print '</td><td class="valuefield">';
2578 if ($action == 'editecheance' && $usercancreate && $caneditfield) {
2579 print '<form name="editecheance" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2580 print '<input type="hidden" name="token" value="'.newToken().'">';
2581 print '<input type="hidden" name="action" value="setecheance">';
2582 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2583 print $form->selectDate($object->fin_validite, 'ech', '', '', '', "editecheance");
2584 print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
2585 print '</form>';
2586 } else {
2587 if (!empty($object->fin_validite)) {
2588 print dol_print_date($object->fin_validite, 'day');
2589 if ($object->statut == Propal::STATUS_VALIDATED && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) {
2590 print img_warning($langs->trans("Late"));
2591 }
2592 } else {
2593 print '&nbsp;';
2594 }
2595 }
2596 print '</td>';
2597 print '</tr>';
2598
2599 // Payment term
2600 print '<tr><td>';
2601 print '<table class="nobordernopadding" width="100%"><tr><td>';
2602 print $langs->trans('PaymentConditionsShort');
2603 print '</td>';
2604 if ($action != 'editconditions' && $usercancreate && $caneditfield) {
2605 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>';
2606 }
2607 print '</tr></table>';
2608 print '</td><td class="valuefield">';
2609 if ($action == 'editconditions' && $usercancreate && $caneditfield) {
2610 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 0, '', 1, $object->deposit_percent);
2611 } else {
2612 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none', 0, '', 1, $object->deposit_percent);
2613 }
2614 print '</td>';
2615 print '</tr>';
2616
2617 // Payment mode
2618 print '<tr class="field_mode_reglement_id">';
2619 print '<td class="titlefieldcreate">';
2620 print '<table class="nobordernopadding centpercent"><tr><td>';
2621 print $langs->trans('PaymentMode');
2622 print '</td>';
2623 if ($action != 'editmode' && $usercancreate && $caneditfield) {
2624 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>';
2625 }
2626 print '</tr></table>';
2627 print '</td><td class="valuefieldcreate">';
2628 if ($action == 'editmode' && $usercancreate && $caneditfield) {
2629 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
2630 } else {
2631 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'none');
2632 }
2633 print '</td></tr>';
2634
2635 // Delivery date
2636 $langs->load('deliveries');
2637 print '<tr><td>';
2638 print $form->editfieldkey($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
2639 print '</td><td class="valuefieldedit">';
2640 print $form->editfieldval($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
2641 print '</td>';
2642 print '</tr>';
2643
2644 // Delivery delay
2645 print '<tr class="fielddeliverydelay"><td>';
2646 print '<table class="nobordernopadding" width="100%"><tr><td>';
2647 if (isModEnabled('commande')) {
2648 print $form->textwithpicto($langs->trans('AvailabilityPeriod'), $langs->trans('AvailabilityPeriod').' ('.$langs->trans('AfterOrder').')');
2649 } else {
2650 print $langs->trans('AvailabilityPeriod');
2651 }
2652 print '</td>';
2653 if ($action != 'editavailability' && $usercancreate && $caneditfield) {
2654 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>';
2655 }
2656 print '</tr></table>';
2657 print '</td><td class="valuefield">';
2658 if ($action == 'editavailability' && $usercancreate && $caneditfield) {
2659 $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'availability_id', 1);
2660 } else {
2661 $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'none', 1);
2662 }
2663
2664 print '</td>';
2665 print '</tr>';
2666
2667 // Shipping Method
2668 if (isModEnabled("expedition")) {
2669 print '<tr><td>';
2670 print '<table class="nobordernopadding centpercent"><tr><td>';
2671 print $langs->trans('SendingMethod');
2672 print '</td>';
2673 if ($action != 'editshippingmethod' && $usercancreate && $caneditfield) {
2674 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>';
2675 }
2676 print '</tr></table>';
2677 print '</td><td class="valuefield">';
2678 if ($action == 'editshippingmethod' && $usercancreate && $caneditfield) {
2679 $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'shipping_method_id', 1);
2680 } else {
2681 $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'none');
2682 }
2683 print '</td>';
2684 print '</tr>';
2685 }
2686
2687 // Warehouse
2688 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
2689 $langs->load('stocks');
2690 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
2691 $formproduct = new FormProduct($db);
2692 print '<tr class="field_warehouse_id"><td class="titlefieldcreate">';
2693 $editenable = $usercancreate;
2694 print $form->editfieldkey("Warehouse", 'warehouse', '', $object, $editenable);
2695 print '</td><td class="valuefieldcreate">';
2696 if ($action == 'editwarehouse') {
2697 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'warehouse_id', 1);
2698 } else {
2699 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'none');
2700 }
2701 print '</td>';
2702 print '</tr>';
2703 }
2704
2705 // Origin of demand
2706 print '<tr><td>';
2707 print '<table class="nobordernopadding centpercent"><tr><td>';
2708 print $langs->trans('Source');
2709 print '</td>';
2710 if ($action != 'editdemandreason' && $usercancreate) {
2711 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>';
2712 }
2713 print '</tr></table>';
2714 print '</td><td class="valuefield">';
2715 if ($action == 'editdemandreason' && $usercancreate) {
2716 $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'demand_reason_id', 1);
2717 } else {
2718 $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'none');
2719 }
2720 print '</td>';
2721 print '</tr>';
2722
2723 // Multicurrency
2724 if (isModEnabled("multicurrency")) {
2725 // Multicurrency code
2726 print '<tr>';
2727 print '<td>';
2728 print '<table class="nobordernopadding" width="100%"><tr><td>';
2729 print $form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0);
2730 print '</td>';
2731 if ($action != 'editmulticurrencycode' && $object->statut == $object::STATUS_DRAFT && $usercancreate) {
2732 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmulticurrencycode&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1).'</a></td>';
2733 }
2734 print '</tr></table>';
2735 print '</td><td class="valuefield">';
2736 if ($object->statut == $object::STATUS_DRAFT && $action == 'editmulticurrencycode' && $usercancreate) {
2737 $form->form_multicurrency_code($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_code, 'multicurrency_code');
2738 } else {
2739 $form->form_multicurrency_code($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_code, 'none');
2740 }
2741 print '</td></tr>';
2742
2743 // Multicurrency rate
2744 if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
2745 print '<tr>';
2746 print '<td>';
2747 print '<table class="nobordernopadding" width="100%"><tr>';
2748 print '<td>';
2749 print $form->editfieldkey('CurrencyRate', 'multicurrency_tx', '', $object, 0);
2750 print '</td>';
2751 if ($action != 'editmulticurrencyrate' && $object->statut == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency && $usercancreate) {
2752 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmulticurrencyrate&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1).'</a></td>';
2753 }
2754 print '</tr></table>';
2755 print '</td><td class="valuefield">';
2756 if ($object->statut == $object::STATUS_DRAFT && ($action == 'editmulticurrencyrate' || $action == 'actualizemulticurrencyrate') && $usercancreate) {
2757 if ($action == 'actualizemulticurrencyrate') {
2758 list($object->fk_multicurrency, $object->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($object->db, $object->multicurrency_code);
2759 }
2760 $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, 'multicurrency_tx', $object->multicurrency_code);
2761 } else {
2762 $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, 'none', $object->multicurrency_code);
2763 if ($object->statut == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) {
2764 print '<div class="inline-block"> &nbsp; &nbsp; &nbsp; &nbsp; ';
2765 print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=actualizemulticurrencyrate">'.$langs->trans("ActualizeCurrency").'</a>';
2766 print '</div>';
2767 }
2768 }
2769 print '</td></tr>';
2770 }
2771 }
2772
2773 if ($soc->outstanding_limit) {
2774 // Outstanding Bill
2775 print '<tr><td>';
2776 print $langs->trans('OutstandingBill');
2777 print '</td><td class="valuefield">';
2778 $arrayoutstandingbills = $soc->getOutstandingBills();
2779 print($arrayoutstandingbills['opened'] > $soc->outstanding_limit ? img_warning() : '');
2780 print price($arrayoutstandingbills['opened']).' / ';
2781 print price($soc->outstanding_limit, 0, $langs, 1, - 1, - 1, $conf->currency);
2782 print '</td>';
2783 print '</tr>';
2784 }
2785
2786 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("banque")) {
2787 // Bank Account
2788 print '<tr><td>';
2789 print '<table width="100%" class="nobordernopadding"><tr><td>';
2790 print $langs->trans('BankAccount');
2791 print '</td>';
2792 if ($action != 'editbankaccount' && $usercancreate) {
2793 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>';
2794 }
2795 print '</tr></table>';
2796 print '</td><td class="valuefield">';
2797 if ($action == 'editbankaccount') {
2798 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1);
2799 } else {
2800 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none');
2801 }
2802 print '</td>';
2803 print '</tr>';
2804 }
2805
2806 $tmparray = $object->getTotalWeightVolume();
2807 $totalWeight = $tmparray['weight'];
2808 $totalVolume = $tmparray['volume'];
2809 if ($totalWeight) {
2810 print '<tr><td>'.$langs->trans("CalculatedWeight").'</td>';
2811 print '<td class="valuefield">';
2812 print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, isset($conf->global->MAIN_WEIGHT_DEFAULT_ROUND) ? $conf->global->MAIN_WEIGHT_DEFAULT_ROUND : -1, isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT) ? $conf->global->MAIN_WEIGHT_DEFAULT_UNIT : 'no', 0);
2813 print '</td></tr>';
2814 }
2815 if ($totalVolume) {
2816 print '<tr><td>'.$langs->trans("CalculatedVolume").'</td>';
2817 print '<td class="valuefield">';
2818 print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND) ? $conf->global->MAIN_VOLUME_DEFAULT_ROUND : -1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT) ? $conf->global->MAIN_VOLUME_DEFAULT_UNIT : 'no', 0);
2819 print '</td></tr>';
2820 }
2821
2822 // Incoterms
2823 if (isModEnabled('incoterm')) {
2824 print '<tr><td>';
2825 print '<table width="100%" class="nobordernopadding"><tr><td>';
2826 print $langs->trans('IncotermLabel');
2827 print '<td><td class="right">';
2828 if ($action != 'editincoterm' && $usercancreate && $caneditfield) {
2829 print '<a class="editfielda" href="'.DOL_URL_ROOT.'/comm/propal/card.php?id='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
2830 } else {
2831 print '&nbsp;';
2832 }
2833 print '</td></tr></table>';
2834 print '</td>';
2835 print '<td class="valuefield">';
2836 if ($action == 'editincoterm' && $usercancreate && $caneditfield) {
2837 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
2838 } else {
2839 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
2840 }
2841 print '</td></tr>';
2842 }
2843
2844 // Other attributes
2845 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
2846
2847 print '</table>';
2848
2849 print '</div>';
2850 print '<div class="fichehalfright">';
2851 print '<div class="underbanner clearboth"></div>';
2852
2853 print '<table class="border tableforfield centpercent">';
2854
2855 print '<tr>';
2856 print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
2857 print '<td class="nowrap amountcard right">' . price($object->total_ht, '', $langs, 1, -1, -1, $conf->currency) . '</td>';
2858 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2859 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ht, '', $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2860 }
2861 print '</tr>';
2862
2863 print '<tr>';
2864 print '<td class="titlefieldmiddle">' . $langs->trans('AmountVAT') . '</td>';
2865 print '<td class="nowrap amountcard right">' . price($object->total_tva, '', $langs, 1, -1, -1, $conf->currency) . '</td>';
2866 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2867 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_tva, '', $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2868 }
2869 print '</tr>';
2870
2871 if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
2872 print '<tr>';
2873 print '<td class="titlefieldmiddle">' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
2874 print '<td class="nowrap amountcard right">' . price($object->total_localtax1, '', $langs, 1, -1, -1, $conf->currency) . '</td>';
2875 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2876 $object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
2877
2878 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax1, '', $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2879 }
2880 print '</tr>';
2881 }
2882
2883 if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
2884 print '<tr>';
2885 print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
2886 print '<td class="nowrap amountcard right">' . price($object->total_localtax2, '', $langs, 1, -1, -1, $conf->currency) . '</td>';
2887 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2888 $object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
2889
2890 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax2, '', $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2891 }
2892 print '</tr>';
2893 }
2894
2895 print '<tr>';
2896 print '<td>' . $langs->trans('AmountTTC') . '</td>';
2897 print '<td class="nowrap amountcard right">' . price($object->total_ttc, '', $langs, 1, -1, -1, $conf->currency) . '</td>';
2898 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2899 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ttc, '', $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2900 }
2901 print '</tr>';
2902
2903 print '</table>';
2904
2905 // Margin Infos
2906 if (isModEnabled('margin')) {
2907 $formmargin->displayMarginInfos($object);
2908 }
2909
2910 print '</div>';
2911 print '</div>';
2912
2913 print '<div class="clearboth"></div><br>';
2914
2915 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
2916 $blocname = 'contacts';
2917 $title = $langs->trans('ContactsAddresses');
2918 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
2919 }
2920
2921 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
2922 $blocname = 'notes';
2923 $title = $langs->trans('Notes');
2924 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
2925 }
2926
2927 /*
2928 * Lines
2929 */
2930
2931 // Get object lines
2932 $result = $object->getLinesArray();
2933
2934 // Add products/services form
2935 //$forceall = 1;
2936 global $inputalsopricewithtax;
2937 $inputalsopricewithtax = 1;
2938
2939 print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">
2940 <input type="hidden" name="token" value="' . newToken().'">
2941 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
2942 <input type="hidden" name="mode" value="">
2943 <input type="hidden" name="page_y" value="">
2944 <input type="hidden" name="backtopage" value="'.$backtopage.'">
2945 <input type="hidden" name="id" value="' . $object->id.'">
2946 ';
2947
2948 if (!empty($conf->use_javascript_ajax) && $object->statut == Propal::STATUS_DRAFT) {
2949 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
2950 }
2951
2952 print '<div class="div-table-responsive-no-min">';
2953 if (!empty($object->lines) || ($object->statut == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
2954 print '<table id="tablelines" class="noborder noshadow centpercent">';
2955 }
2956
2957 if (!empty($object->lines)) {
2958 $object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 1);
2959 }
2960
2961 // Form to add new line
2962 if ($object->statut == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines') {
2963 if ($action != 'editline') {
2964 $parameters = array();
2965 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2966 if ($reshook < 0) {
2967 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2968 }
2969 if (empty($reshook)) {
2970 $object->formAddObjectLine(1, $mysoc, $soc);
2971 }
2972 } else {
2973 $parameters = array();
2974 $reshook = $hookmanager->executeHooks('formEditObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2975 }
2976 }
2977
2978 if (!empty($object->lines) || ($object->statut == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
2979 print '</table>';
2980 }
2981 print '</div>';
2982
2983 print "</form>\n";
2984 }
2985
2986 print dol_get_fiche_end();
2987
2988
2989 /*
2990 * Button Actions
2991 */
2992
2993 if ($action != 'presend') {
2994 print '<div class="tabsAction">';
2995
2996 $parameters = array();
2997 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
2998 // modified by hook
2999 if (empty($reshook)) {
3000 if ($action != 'editline') {
3001 // Validate
3002 if (($object->statut == Propal::STATUS_DRAFT && $object->total_ttc >= 0 && count($object->lines) > 0)
3003 || ($object->statut == Propal::STATUS_DRAFT && getDolGlobalString('PROPAL_ENABLE_NEGATIVE') && count($object->lines) > 0)) {
3004 if ($usercanvalidate) {
3005 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>';
3006 } else {
3007 print '<a class="butActionRefused classfortooltip" href="#">'.$langs->trans('Validate').'</a>';
3008 }
3009 }
3010 // Create event
3011 /*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.
3012 {
3013 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>';
3014 }*/
3015 // Edit
3016 if ($object->statut == Propal::STATUS_VALIDATED && $usercancreate) {
3017 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=modif&token='.newToken().'">'.$langs->trans('Modify').'</a>';
3018 }
3019
3020 // ReOpen
3021 if (((getDolGlobalString('PROPAL_REOPEN_UNSIGNED_ONLY') && $object->statut == Propal::STATUS_NOTSIGNED) || (!getDolGlobalString('PROPAL_REOPEN_UNSIGNED_ONLY') && ($object->statut == Propal::STATUS_SIGNED || $object->statut == Propal::STATUS_NOTSIGNED || $object->statut == Propal::STATUS_BILLED))) && $usercanclose) {
3022 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken().(!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#reopen').'"';
3023 print '>'.$langs->trans('ReOpen').'</a>';
3024 }
3025
3026 // Send
3027 if (empty($user->socid)) {
3028 if ($object->statut == Propal::STATUS_VALIDATED || $object->statut == Propal::STATUS_SIGNED || getDolGlobalString('PROPOSAL_SENDBYEMAIL_FOR_ALL_STATUS')) {
3029 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?action=presend&token='.newToken().'&id='.$object->id.'&mode=init#formmailbeforetitle', '', $usercansend);
3030 }
3031 }
3032
3033 // Create a sale order
3034 if (isModEnabled('commande') && $object->statut == Propal::STATUS_SIGNED) {
3035 if ($usercancreateorder) {
3036 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>';
3037 }
3038 }
3039
3040 // Create a purchase order
3041 if (getDolGlobalString('WORKFLOW_CAN_CREATE_PURCHASE_ORDER_FROM_PROPOSAL')) {
3042 if ($object->statut == Propal::STATUS_SIGNED && isModEnabled("supplier_order")) {
3043 if ($usercancreatepurchaseorder) {
3044 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>';
3045 }
3046 }
3047 }
3048
3049 // Create an intervention
3050 if (isModEnabled("service") && isModEnabled('ficheinter') && $object->statut == Propal::STATUS_SIGNED) {
3051 if ($usercancreateintervention) {
3052 $langs->load("interventions");
3053 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>';
3054 }
3055 }
3056
3057 // Create contract
3058 if (isModEnabled('contrat') && $object->statut == Propal::STATUS_SIGNED) {
3059 $langs->load("contracts");
3060
3061 if ($usercancreatecontract) {
3062 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>';
3063 }
3064 }
3065
3066 // Create an invoice and classify billed
3067 if ($object->statut == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
3068 if (isModEnabled('facture') && $usercancreateinvoice) {
3069 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>';
3070 }
3071
3072 $arrayofinvoiceforpropal = $object->getInvoiceArrayList();
3073 if ((is_array($arrayofinvoiceforpropal) && count($arrayofinvoiceforpropal) > 0) || !getDolGlobalString('WORKFLOW_PROPAL_NEED_INVOICE_TO_BE_CLASSIFIED_BILLED')) {
3074 if ($usercanclose) {
3075 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=classifybilled&token='.newToken().'&socid='.$object->socid.'">'.$langs->trans("ClassifyBilled").'</a>';
3076 } else {
3077 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("ClassifyBilled").'</a>';
3078 }
3079 }
3080 }
3081
3082 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
3083 // Close as accepted/refused
3084 if ($object->statut == Propal::STATUS_VALIDATED) {
3085 if ($usercanclose) {
3086 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=closeas&token='.newToken().(!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close').'"';
3087 print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3088 } else {
3089 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'"';
3090 print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3091 }
3092 }
3093 } else {
3094 // Set not signed (close)
3095 if ($object->statut == Propal::STATUS_DRAFT && $usercanclose) {
3096 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&token='.newToken().'&action=closeas&token='.newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close') . '"';
3097 print '>' . $langs->trans('SetRefusedAndClose') . '</a>';
3098 }
3099 }
3100
3101 // Clone
3102 if ($usercancreate) {
3103 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&socid='.$object->socid.'&action=clone&token='.newToken().'&object='.$object->element.'">'.$langs->trans("ToClone").'</a>';
3104 }
3105
3106 // Delete
3107 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $usercandelete);
3108 }
3109 }
3110
3111 print '</div>';
3112 }
3113
3114 //Select mail models is same action as presend
3115 if (GETPOST('modelselected')) {
3116 $action = 'presend';
3117 }
3118
3119 if ($action != 'presend') {
3120 print '<div class="fichecenter"><div class="fichehalfleft">';
3121 print '<a name="builddoc"></a>'; // ancre
3122 /*
3123 * Generated documents
3124 */
3125 $objref = dol_sanitizeFileName($object->ref);
3126 $filedir = $conf->propal->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref);
3127 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
3128 $genallowed = $usercanread;
3129 $delallowed = $usercancreate;
3130
3131 print $formfile->showdocuments('propal', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', 0, '', $soc->default_lang, '', $object);
3132
3133 // Show links to link elements
3134 $linktoelem = $form->showLinkToObjectBlock($object, null, array('propal'));
3135
3136 $compatibleImportElementsList = false;
3137 if ($user->hasRight('propal', 'creer') && $object->statut == Propal::STATUS_DRAFT) {
3138 $compatibleImportElementsList = array('commande', 'propal', 'facture'); // import from linked elements
3139 }
3140 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
3141
3142 // Show online signature link
3143 $useonlinesignature = getDolGlobalInt('PROPOSAL_ALLOW_ONLINESIGN');
3144
3145 if ($object->statut != Propal::STATUS_DRAFT && $useonlinesignature) {
3146 print '<br><!-- Link to sign -->';
3147 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
3148 print showOnlineSignatureUrl('proposal', $object->ref).'<br>';
3149 }
3150
3151 print '</div><div class="fichehalfright">';
3152
3153 $MAXEVENT = 10;
3154
3155 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/comm/propal/agenda.php?id='.$object->id);
3156
3157 // List of actions on element
3158 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
3159 $formactions = new FormActions($db);
3160 $somethingshown = $formactions->showactions($object, 'propal', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
3161
3162 print '</div></div>';
3163 }
3164
3165 // Presend form
3166 $modelmail = 'propal_send';
3167 $defaulttopic = 'SendPropalRef';
3168 $diroutput = $conf->propal->multidir_output[$object->entity];
3169 $trackid = 'pro'.$object->id;
3170
3171 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
3172}
3173
3174// End of page
3175llxFooter();
3176$db->close();
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action=='set') elseif( $action=='specimen') elseif($action=='setmodel') elseif( $action=='del') elseif($action=='setdoc') $formactions
View.
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:55
llxFooter()
Empty footer.
Definition wrapper.php:69
Class to manage a WYSIWYG editor.
Class to manage standard extra fields.
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.
Classe permettant la generation de composants html autre 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.
static getIdAndTxFromCode($dbs, $code, $date_document='')
Get id and rate of currency from code.
Class to manage notifications.
Class ProductCombination Used to represent a product combination.
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_VALIDATED
Validated status.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
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.
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0)
Set event message in dol_events session object.
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.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
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...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
getDictionaryValue($tablename, $field, $id, $checkentity=false, $rowidfield='rowid')
Return the value of a filed into a dictionary for the record $id.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
propal_prepare_head($object)
Prepare array with list of tabs.
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.