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