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