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