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