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