dolibarr 21.0.4
card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
5 * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
6 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
7 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
8 * Copyright (C) 2010-2023 Juanjo Menent <jmenent@2byte.es>
9 * Copyright (C) 2010-2022 Philippe Grand <philippe.grand@atoo-net.com>
10 * Copyright (C) 2012-2023 Christophe Battarel <christophe.battarel@altairis.fr>
11 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
12 * Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
13 * Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
14 * Copyright (C) 2016 Marcos García <marcosgdf@gmail.com>
15 * Copyright (C) 2018-2024 Frédéric France <frederic.france@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), (GETPOST('update_prices') == 'on'), (GETPOST('update_desc') == 'on'));
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 ? (int) $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 // multicurrency_tx is the number of foreign currency units for 1 unit of base
1433 // (see calcul_price_total() in price.lib.php which uses $pu = $pu_devise / $multicurrency_tx),
1434 // so the conversion back to base must divide, not multiply (see issue #33042).
1435 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1436 $pu_equivalent = (float) $pu_ht_devise / (float) $currency_tx;
1437 }
1438 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1439 $pu_equivalent_ttc = (float) $pu_ttc_devise / (float) $currency_tx;
1440 }
1441
1442 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1443 /*
1444 if ($pu_equivalent) {
1445 $tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
1446 $pu_equivalent_ttc = ...
1447 } else {
1448 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $tva_tx, -1, -1, 0, 'TTC', $info_bits, $type);
1449 $pu_equivalent_ht = ...
1450 }
1451 */
1452
1453 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1454 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1455
1456 // Check price is not lower than minimum
1457 if ($usermustrespectpricemin) {
1458 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < price2num($price_min)) && $price_base_type == 'HT') {
1459 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1460 setEventMessages($mesg, null, 'errors');
1461 $error++;
1462 } elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - $remise_percent / 100)) < price2num($price_min_ttc)) && $price_base_type == 'TTC') {
1463 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1464 setEventMessages($mesg, null, 'errors');
1465 $error++;
1466 }
1467 }
1468
1469 if (!$error) {
1470 // Insert line
1471 $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);
1472
1473 if ($result > 0) {
1474 $db->commit();
1475
1476 $ret = $object->fetch($id); // Reload to get new records
1477 if ($ret > 0) {
1478 $object->fetch_thirdparty();
1479 }
1480
1481 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1482 // Define output language
1483 $outputlangs = $langs;
1484 if (getDolGlobalInt('MAIN_MULTILANGS')) {
1485 $outputlangs = new Translate("", $conf);
1486 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
1487 $outputlangs->setDefaultLang($newlang);
1488 }
1489 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1490 }
1491
1492 unset($_POST['prod_entry_mode']);
1493
1494 unset($_POST['qty']);
1495 unset($_POST['type']);
1496 unset($_POST['remise_percent']);
1497 unset($_POST['price_ht']);
1498 unset($_POST['multicurrency_price_ht']);
1499 unset($_POST['price_ttc']);
1500 unset($_POST['tva_tx']);
1501 unset($_POST['product_ref']);
1502 unset($_POST['product_label']);
1503 unset($_POST['product_desc']);
1504 unset($_POST['fournprice']);
1505 unset($_POST['buying_price']);
1506 unset($_POST['np_marginRate']);
1507 unset($_POST['np_markRate']);
1508 unset($_POST['dp_desc']);
1509 unset($_POST['idprod']);
1510 unset($_POST['units']);
1511
1512 unset($_POST['date_starthour']);
1513 unset($_POST['date_startmin']);
1514 unset($_POST['date_startsec']);
1515 unset($_POST['date_startday']);
1516 unset($_POST['date_startmonth']);
1517 unset($_POST['date_startyear']);
1518 unset($_POST['date_endhour']);
1519 unset($_POST['date_endmin']);
1520 unset($_POST['date_endsec']);
1521 unset($_POST['date_endday']);
1522 unset($_POST['date_endmonth']);
1523 unset($_POST['date_endyear']);
1524 } else {
1525 $db->rollback();
1526
1527 setEventMessages($object->error, $object->errors, 'errors');
1528 }
1529 }
1530 }
1531 } elseif ($action == 'updateline' && $usercancreate && GETPOST('save')) {
1532 // Update a line within proposal
1533
1534 // Clean parameters
1535 $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml'));
1536
1537 // Define info_bits
1538 $info_bits = 0;
1539 if (preg_match('/\*/', GETPOST('tva_tx'))) {
1540 $info_bits |= 0x01;
1541 }
1542
1543 // Define vat_rate
1544 $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
1545 $vat_rate = str_replace('*', '', $vat_rate);
1546 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
1547 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
1548 $pu_ht = price2num(GETPOST('price_ht'), '', 2);
1549 $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
1550
1551 // Add buying price
1552 $fournprice = price2num(GETPOST('fournprice') ? GETPOST('fournprice') : '');
1553 $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''); // If buying_price is '0', we must keep this value
1554
1555 $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
1556 $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
1557
1558 $date_start = dol_mktime(GETPOSTINT('date_starthour'), GETPOSTINT('date_startmin'), GETPOSTINT('date_startsec'), GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
1559 $date_end = dol_mktime(GETPOSTINT('date_endhour'), GETPOSTINT('date_endmin'), GETPOSTINT('date_endsec'), GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
1560
1561 $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1562 if (empty($remise_percent)) {
1563 $remise_percent = 0;
1564 }
1565
1566 // Prepare a price equivalent for minimum price check
1567 $pu_equivalent = $pu_ht;
1568 $pu_equivalent_ttc = $pu_ttc;
1569
1570 $currency_tx = $object->multicurrency_tx;
1571
1572 // Check if we have a foreign currency
1573 // If so, we update the pu_equiv as the equivalent price in base currency.
1574 // multicurrency_tx is the number of foreign currency units for 1 unit of base
1575 // (see calcul_price_total() in price.lib.php which uses $pu = $pu_devise / $multicurrency_tx),
1576 // so the conversion back to base must divide, not multiply (see issue #33042).
1577 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1578 $pu_equivalent = (float) $pu_ht_devise / (float) $currency_tx;
1579 }
1580 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1581 $pu_equivalent_ttc = (float) $pu_ttc_devise / (float) $currency_tx;
1582 }
1583
1584 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1585 /*
1586 if ($pu_equivalent) {
1587 $tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
1588 $pu_equivalent_ttc = ...
1589 } else {
1590 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
1591 $pu_equivalent_ht = ...
1592 }
1593 */
1594
1595 // Extrafields
1596 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1597 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
1598 // Unset extrafield
1599 if (is_array($extralabelsline)) {
1600 // Get extra fields
1601 foreach ($extralabelsline as $key => $value) {
1602 unset($_POST["options_".$key]);
1603 }
1604 }
1605
1606 // Define special_code for special lines
1607 $special_code = GETPOSTINT('special_code');
1608 if (!GETPOST('qty')) {
1609 $special_code = 3;
1610 }
1611
1612 $pu = $pu_ht;
1613 $price_base_type = 'HT';
1614 if (empty($pu) && !empty($pu_ttc)) {
1615 $pu = $pu_ttc;
1616 $price_base_type = 'TTC';
1617 }
1618
1619 // Check minimum price
1620 $productid = GETPOSTINT('productid');
1621 if (!empty($productid)) {
1622 $product = new Product($db);
1623 $res = $product->fetch($productid);
1624
1625 $type = $product->type;
1626 $price_base_type = $product->price_base_type;
1627 $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
1628
1629 $price_min = $product->price_min;
1630 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
1631 $price_min = $product->multiprices_min[$object->thirdparty->price_level];
1632 }
1633 $price_min_ttc = $product->price_min_ttc;
1634 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
1635 $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
1636 }
1637
1638 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1639 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1640
1641 // Check price is not lower than minimum
1642 if ($usermustrespectpricemin) {
1643 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
1644 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1645 setEventMessages($mesg, null, 'errors');
1646 $error++;
1647 $action = 'editline';
1648 } 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') {
1649 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1650 setEventMessages($mesg, null, 'errors');
1651 $error++;
1652 $action = 'editline';
1653 }
1654 }
1655 } else {
1656 $type = GETPOST('type');
1657 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1658
1659 // Check parameters
1660 if (GETPOST('type') < 0) {
1661 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1662 $error++;
1663 }
1664 }
1665
1666 if (!$error) {
1667 $db->begin();
1668
1669 if (!$user->hasRight('margins', 'creer')) {
1670 foreach ($object->lines as &$line) {
1671 if ($line->id == GETPOSTINT('lineid')) {
1672 $fournprice = $line->fk_fournprice;
1673 $buyingprice = $line->pa_ht;
1674 break;
1675 }
1676 }
1677 }
1678
1679 $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
1680
1681 $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);
1682
1683 if ($result >= 0) {
1684 $db->commit();
1685
1686 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1687 // Define output language
1688 $outputlangs = $langs;
1689 if (getDolGlobalInt('MAIN_MULTILANGS')) {
1690 $outputlangs = new Translate("", $conf);
1691 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
1692 $outputlangs->setDefaultLang($newlang);
1693 }
1694 $ret = $object->fetch($id); // Reload to get new records
1695 if ($ret > 0) {
1696 $object->fetch_thirdparty();
1697 }
1698 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1699 }
1700
1701 unset($_POST['qty']);
1702 unset($_POST['type']);
1703 unset($_POST['productid']);
1704 unset($_POST['remise_percent']);
1705 unset($_POST['price_ht']);
1706 unset($_POST['multicurrency_price_ht']);
1707 unset($_POST['price_ttc']);
1708 unset($_POST['tva_tx']);
1709 unset($_POST['product_ref']);
1710 unset($_POST['product_label']);
1711 unset($_POST['product_desc']);
1712 unset($_POST['fournprice']);
1713 unset($_POST['buying_price']);
1714
1715 unset($_POST['date_starthour']);
1716 unset($_POST['date_startmin']);
1717 unset($_POST['date_startsec']);
1718 unset($_POST['date_startday']);
1719 unset($_POST['date_startmonth']);
1720 unset($_POST['date_startyear']);
1721 unset($_POST['date_endhour']);
1722 unset($_POST['date_endmin']);
1723 unset($_POST['date_endsec']);
1724 unset($_POST['date_endday']);
1725 unset($_POST['date_endmonth']);
1726 unset($_POST['date_endyear']);
1727 } else {
1728 $db->rollback();
1729
1730 setEventMessages($object->error, $object->errors, 'errors');
1731 }
1732 }
1733 } elseif ($action == 'updateline' && $usercancreate && GETPOST('cancel', 'alpha')) {
1734 header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // To re-display card in edit mode
1735 exit();
1736 } elseif ($action == 'classin' && $usercancreate) {
1737 // Set project
1738 $object->setProject(GETPOSTINT('projectid'));
1739 } elseif ($action == 'setavailability' && $usercancreate) {
1740 // Delivery time
1741 $result = $object->set_availability($user, GETPOSTINT('availability_id'));
1742 } elseif ($action == 'setdemandreason' && $usercancreate) {
1743 // Origin of the commercial proposal
1744 $result = $object->set_demand_reason($user, GETPOSTINT('demand_reason_id'));
1745 } elseif ($action == 'setconditions' && $usercancreate) {
1746 // Terms of payment
1747 $sql = "SELECT code ";
1748 $sql .= "FROM " . $db->prefix() . "c_payment_term";
1749 $sql .= " WHERE rowid = " . ((int) GETPOST('cond_reglement_id', 'int'));
1750 $result = $db->query($sql);
1751 if ($result) {
1752 $obj = $db->fetch_object($result);
1753 if ($obj->code == 'DEP30PCTDEL') {
1754 $result = $object->setPaymentTerms(GETPOSTINT('cond_reglement_id'), GETPOSTFLOAT('cond_reglement_id_deposit_percent'));
1755 } else {
1756 $object->deposit_percent = 0;
1757 $object->update($user);
1758 $result = $object->setPaymentTerms(GETPOSTINT('cond_reglement_id'), $object->deposit_percent);
1759 }
1760 }
1761 //} elseif ($action == 'setremisepercent' && $usercancreate) {
1762 // $result = $object->set_remise_percent($user, price2num(GETPOST('remise_percent'), '', 2));
1763 //} elseif ($action == 'setremiseabsolue' && $usercancreate) {
1764 // $result = $object->set_remise_absolue($user, price2num(GETPOST('remise_absolue'), 'MU', 2));
1765 } elseif ($action == 'setmode' && $usercancreate) {
1766 // Payment choice
1767 $result = $object->setPaymentMethods(GETPOSTINT('mode_reglement_id'));
1768 } elseif ($action == 'setmulticurrencycode' && $usercancreate) {
1769 // Multicurrency Code
1770 $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
1771 } elseif ($action == 'setmulticurrencyrate' && $usercancreate) {
1772 // Multicurrency rate
1773 $result = $object->setMulticurrencyRate(price2num(GETPOST('multicurrency_tx')), GETPOSTINT('calculation_mode'));
1774 } elseif ($action == 'setbankaccount' && $usercancreate) {
1775 // bank account
1776 $result = $object->setBankAccount(GETPOSTINT('fk_account'));
1777 } elseif ($action == 'setshippingmethod' && $usercancreate) {
1778 // shipping method
1779 $result = $object->setShippingMethod(GETPOSTINT('shipping_method_id'));
1780 } elseif ($action == 'setwarehouse' && $usercancreate) {
1781 // warehouse
1782 $result = $object->setWarehouse(GETPOSTINT('warehouse_id'));
1783 } elseif ($action == 'update_extras' && $usercancreate) {
1784 $object->oldcopy = dol_clone($object, 2);
1785 $attribute_name = GETPOST('attribute', 'restricthtml');
1786
1787 // Fill array 'array_options' with data from update form
1788 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
1789 if ($ret < 0) {
1790 $error++;
1791 }
1792 if (!$error) {
1793 $result = $object->updateExtraField($attribute_name, 'PROPAL_MODIFY');
1794 if ($result < 0) {
1795 setEventMessages($object->error, $object->errors, 'errors');
1796 $error++;
1797 }
1798 }
1799 if ($error) {
1800 $action = 'edit_extras';
1801 }
1802 }
1803
1804 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
1805 if ($action == 'addcontact' && $usercancreate) {
1806 if ($object->id > 0) {
1807 $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'));
1808 $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
1809 $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
1810 }
1811
1812 if ($result >= 0) {
1813 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
1814 exit();
1815 } else {
1816 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1817 $langs->load("errors");
1818 setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
1819 } else {
1820 setEventMessages($object->error, $object->errors, 'errors');
1821 }
1822 }
1823 } elseif ($action == 'swapstatut' && $usercancreate) {
1824 // Toggle the status of a contact
1825 if ($object->fetch($id) > 0) {
1826 $result = $object->swapContactStatus(GETPOSTINT('ligne'));
1827 } else {
1828 dol_print_error($db);
1829 }
1830 } elseif ($action == 'deletecontact' && $usercancreate) {
1831 // Delete a contact
1832 $object->fetch($id);
1833 $result = $object->delete_contact($lineid);
1834
1835 if ($result >= 0) {
1836 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
1837 exit();
1838 } else {
1839 dol_print_error($db);
1840 }
1841 }
1842 }
1843
1844 // Actions to build doc
1845 $upload_dir = !empty($conf->propal->multidir_output[$object->entity]) ? $conf->propal->multidir_output[$object->entity] : $conf->propal->dir_output;
1846 $permissiontoadd = $usercancreate;
1847 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
1848}
1849
1850
1851/*
1852 * View
1853 */
1854
1855$form = new Form($db);
1856$formfile = new FormFile($db);
1857$formpropal = new FormPropal($db);
1858$formmargin = new FormMargin($db);
1859$formproject = null;
1860if (isModEnabled('project')) {
1861 $formproject = new FormProjets($db);
1862}
1863
1864$title = $object->ref." - ".$langs->trans('Card');
1865if ($action == 'create') {
1866 $title = $langs->trans("NewPropal");
1867}
1868$help_url = 'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos|DE:Modul_Angebote';
1869
1870llxHeader('', $title, $help_url);
1871
1872$now = dol_now();
1873
1874// Add new proposal
1875if ($action == 'create') {
1876 $currency_code = $conf->currency;
1877
1878 print load_fiche_titre($langs->trans("NewProp"), '', 'propal');
1879
1880 $soc = new Societe($db);
1881 if ($socid > 0) {
1882 $res = $soc->fetch($socid);
1883 }
1884
1885 $currency_code = $conf->currency;
1886
1887 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
1888 $deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
1889 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
1890 $fk_account = GETPOSTINT('fk_account');
1891 $datepropal = (empty($datepropal) ? (!getDolGlobalString('MAIN_AUTOFILL_DATE_PROPOSAL') ? -1 : '') : $datepropal);
1892
1893 // Load objectsrc
1894 $objectsrc = null;
1895 if (!empty($origin) && !empty($originid)) {
1896 // Parse element/subelement (ex: project_task)
1897 $element = $subelement = $origin;
1898 $regs = array();
1899 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
1900 $element = $regs[1];
1901 $subelement = $regs[2];
1902 }
1903
1904 if ($element == 'project') {
1905 $projectid = $originid;
1906
1907 // Fetch project and thirdparty
1908 $project = new Project($db);
1909 $project->fetch($projectid);
1910 if ($project->socid > 0) {
1911 $soc = new Societe($db);
1912 $soc->fetch($project->socid);
1913 }
1914 } else {
1915 // For compatibility
1916 if ($element == 'order' || $element == 'commande') {
1917 $element = $subelement = 'commande';
1918 }
1919 if ($element == 'propal') {
1920 $element = 'comm/propal';
1921 $subelement = 'propal';
1922 }
1923 if ($element == 'contract') {
1924 $element = $subelement = 'contrat';
1925 }
1926 if ($element == 'shipping') {
1927 $element = $subelement = 'expedition';
1928 }
1929
1930 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
1931
1932 $classname = ucfirst($subelement);
1933 $objectsrc = new $classname($db);
1934 '@phan-var-force Commande|Propal|Contrat|Expedition $objectsrc'; // Can be other class, but CommonObject is too generic
1935 $objectsrc->fetch($originid);
1936 if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
1937 $objectsrc->fetch_lines();
1938 }
1939 $objectsrc->fetch_thirdparty();
1940
1941 $projectid = (!empty($objectsrc->fk_project) ? $objectsrc->fk_project : 0);
1942 $ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : '');
1943
1944 $soc = $objectsrc->thirdparty;
1945
1946 $cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0));
1947 $mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
1948 $warehouse_id = (!empty($objectsrc->warehouse_id) ? $objectsrc->warehouse_id : (!empty($soc->warehouse_id) ? $soc->warehouse_id : 0));
1949
1950 // Replicate extrafields
1951 $objectsrc->fetch_optionals();
1952 $object->array_options = $objectsrc->array_options;
1953
1954 if (isModEnabled("multicurrency")) {
1955 if (!empty($objectsrc->multicurrency_code)) {
1956 $currency_code = $objectsrc->multicurrency_code;
1957 }
1958 if (getDolGlobalString('MULTICURRENCY_USE_ORIGIN_TX') && !empty($objectsrc->multicurrency_tx)) {
1959 $currency_tx = $objectsrc->multicurrency_tx;
1960 }
1961 }
1962 }
1963 }
1964
1965 // Load default values from thirdparty
1966 if (!empty($soc)) {
1967 $cond_reglement_id = empty($soc->cond_reglement_id) ? $cond_reglement_id : $soc->cond_reglement_id;
1968 $deposit_percent = empty($soc->deposit_percent) ? $deposit_percent : $soc->deposit_percent;
1969 $mode_reglement_id = empty($soc->mode_reglement_id) ? $mode_reglement_id : $soc->mode_reglement_id;
1970 $fk_account = empty($soc->fk_account) ? $fk_account : $soc->fk_account;
1971 $shipping_method_id = $soc->shipping_method_id;
1972 $warehouse_id = $soc->fk_warehouse;
1973 $remise_percent = $soc->remise_percent;
1974
1975 if (isModEnabled("multicurrency") && !empty($soc->multicurrency_code)) {
1976 $currency_code = $soc->multicurrency_code;
1977 }
1978 }
1979
1980 // If form was posted (but error returned), we must reuse the value posted in priority (standard Dolibarr behaviour)
1981 if (!GETPOST('changecompany')) {
1982 if (GETPOSTISSET('cond_reglement_id')) {
1983 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
1984 }
1985 if (GETPOSTISSET('deposit_percent')) {
1986 $deposit_percent = price2num(GETPOST('deposit_percent', 'alpha'));
1987 }
1988 if (GETPOSTISSET('mode_reglement_id')) {
1989 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
1990 }
1991 if (GETPOSTISSET('fk_account')) {
1992 $fk_account = GETPOSTINT('fk_account');
1993 }
1994 }
1995
1996 // Warehouse default if null
1997 if ($soc->fk_warehouse > 0) {
1998 $warehouse_id = $soc->fk_warehouse;
1999 }
2000 if (isModEnabled('stock') && empty($warehouse_id) && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_ORDER')) {
2001 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE')) {
2002 $warehouse_id = getDolGlobalString('MAIN_DEFAULT_WAREHOUSE');
2003 }
2004 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER') && !empty($user->fk_warehouse)) {
2005 $warehouse_id = $user->fk_warehouse;
2006 }
2007 }
2008
2009 print '<form name="addprop" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2010 print '<input type="hidden" name="token" value="'.newToken().'">';
2011 print '<input type="hidden" name="action" value="add">';
2012 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
2013 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2014 if ($origin != 'project' && $originid) {
2015 print '<input type="hidden" name="origin" value="'.$origin.'">';
2016 print '<input type="hidden" name="originid" value="'.$originid.'">';
2017 } elseif ($origin == 'project' && !empty($projectid)) {
2018 print '<input type="hidden" name="projectid" value="'.$projectid.'">';
2019 }
2020
2021 print dol_get_fiche_head();
2022
2023 // Call Hook tabContentCreateProposal
2024 $parameters = array();
2025 // Note that $action and $object may be modified by hook
2026 $reshook = $hookmanager->executeHooks('tabContentCreateProposal', $parameters, $object, $action);
2027 if (empty($reshook)) {
2028 print '<table class="border centpercent">';
2029
2030 // Reference
2031 print '<tr class="field_ref"><td class="titlefieldcreate fieldrequired">'.$langs->trans('Ref').'</td><td class="valuefieldcreate">'.$langs->trans("Draft").'</td></tr>';
2032
2033 // Ref customer
2034 print '<tr class="field_ref_client"><td class="titlefieldcreate">'.$langs->trans('RefCustomer').'</td><td class="valuefieldcreate">';
2035 print '<input type="text" name="ref_client" value="'.(!empty($ref_client) ? $ref_client : GETPOST('ref_client')).'"></td>';
2036 print '</tr>';
2037
2038 // Third party
2039 print '<tr class="field_socid">';
2040 print '<td class="titlefieldcreate fieldrequired">'.$langs->trans('Customer').'</td>';
2041 $shipping_method_id = 0;
2042 $warehouse_id = 0;
2043 if ($socid > 0) {
2044 print '<td class="valuefieldcreate">';
2045 print $soc->getNomUrl(1, 'customer');
2046 print '<input type="hidden" name="socid" value="'.$soc->id.'">';
2047 print '</td>';
2048 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
2049 $shipping_method_id = $soc->shipping_method_id;
2050 }
2051 //$warehouse_id = $soc->warehouse_id;
2052 } else {
2053 print '<td class="valuefieldcreate">';
2054 $filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
2055 print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company('', 'socid', $filter, 'SelectThirdParty', 1, 0, array(), 0, 'minwidth300 maxwidth500 widthcentpercentminusxx');
2056 // reload page to retrieve customer information
2057 if (!getDolGlobalString('RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED')) {
2058 print '<script>
2059 $(document).ready(function() {
2060 $("#socid").change(function() {
2061 console.log("We have changed the company - Reload page");
2062 var socid = $(this).val();
2063 // reload page
2064 $("input[name=action]").val("create");
2065 $("input[name=changecompany]").val("1");
2066 $("form[name=addprop]").submit();
2067 });
2068 });
2069 </script>';
2070 }
2071 print ' <a href="'.DOL_URL_ROOT.'/societe/card.php?action=create&prospect=3&fournisseur=0&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create').'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddThirdParty").'"></span></a>';
2072 print '</td>';
2073 }
2074 print '</tr>'."\n";
2075
2076 if ($socid > 0) {
2077 // Contacts (ask contact only if thirdparty already defined).
2078 print '<tr class="field_contactid"><td class="titlefieldcreate">'.$langs->trans("DefaultContact").'</td><td class="valuefieldcreate">';
2079 print img_picto('', 'contact', 'class="pictofixedwidth"');
2080 //print $form->selectcontacts($soc->id, $contactid, 'contactid', 1, '', '', 0, 'minwidth300 widthcentpercentminusx');
2081 print $form->select_contact($soc->id, $contactid, 'contactid', 1, '', '', 1, 'maxwidth300 widthcentpercentminusx', true);
2082 print '</td></tr>';
2083
2084 // Third party discounts info line
2085 print '<tr class="field_discount_info"><td class="titlefieldcreate">'.$langs->trans('Discounts').'</td><td class="valuefieldcreate">';
2086
2087 $absolute_discount = $soc->getAvailableDiscounts();
2088
2089 $thirdparty = $soc;
2090 $discount_type = 0;
2091 $backtopage = $_SERVER["PHP_SELF"].'?socid='.$thirdparty->id.'&action='.$action.'&origin='.urlencode((string) (GETPOST('origin'))).'&originid='.urlencode((string) (GETPOSTINT('originid')));
2092 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
2093 print '</td></tr>';
2094 }
2095
2096 $newdatepropal = dol_mktime(0, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'), 'tzserver');
2097 // Date
2098 print '<tr class="field_addprop"><td class="titlefieldcreate fieldrequired">'.$langs->trans('DatePropal').'</td><td class="valuefieldcreate">';
2099 print img_picto('', 'action', 'class="pictofixedwidth"');
2100 print $form->selectDate($newdatepropal ? $newdatepropal : $datepropal, '', 0, 0, 0, "addprop", 1, 1);
2101 print '</td></tr>';
2102
2103 // Validaty duration
2104 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') : getDolGlobalString('PROPALE_VALIDITY_DURATION')).'"> '.$langs->trans("days").'</td></tr>';
2105
2106 // Terms of payment
2107 print '<tr class="field_cond_reglement_id"><td class="nowrap">'.$langs->trans('PaymentConditionsShort').'</td><td>';
2108 print img_picto('', 'payment', 'class="pictofixedwidth"');
2109 // at last resort we take the payment term id which may be filled by default values set (if not getpostisset)
2110 print $form->getSelectConditionsPaiements($cond_reglement_id, 'cond_reglement_id', 1, 1, 0, '', $deposit_percent);
2111 print '</td></tr>';
2112
2113 // Mode of payment
2114 print '<tr class="field_mode_reglement_id"><td class="titlefieldcreate">'.$langs->trans('PaymentMode').'</td><td class="valuefieldcreate">';
2115 print img_picto('', 'bank', 'class="pictofixedwidth"');
2116 print $form->select_types_paiements($mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
2117 print '</td></tr>';
2118
2119 // Bank Account
2120 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
2121 print '<tr class="field_fk_account"><td class="titlefieldcreate">'.$langs->trans('BankAccount').'</td><td class="valuefieldcreate">';
2122 print img_picto('', 'bank_account', 'class="pictofixedwidth"').$form->select_comptes($fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
2123 print '</td></tr>';
2124 }
2125
2126 // Source / Channel - What trigger creation
2127 print '<tr class="field_demand_reason_id"><td class="titlefieldcreate">'.$langs->trans('Source').'</td><td class="valuefieldcreate">';
2128 print img_picto('', 'question', 'class="pictofixedwidth"');
2129 $form->selectInputReason((GETPOSTISSET('demand_reason_id') ? GETPOSTINT('demand_reason_id') : ''), 'demand_reason_id', "SRC_PROP", 1, 'maxwidth200 widthcentpercentminusx');
2130 print '</td></tr>';
2131
2132 // Shipping Method
2133 if (isModEnabled("shipping")) {
2134 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
2135 $shipping_method_id = $soc->shipping_method_id;
2136 }
2137 print '<tr class="field_shipping_method_id"><td class="titlefieldcreate">'.$langs->trans('SendingMethod').'</td><td class="valuefieldcreate">';
2138 print img_picto('', 'dolly', 'class="pictofixedwidth"');
2139 $form->selectShippingMethod((GETPOSTISSET('shipping_method_id') ? GETPOSTINT('shipping_method_id') : $shipping_method_id), 'shipping_method_id', '', 1, '', 0, 'maxwidth200 widthcentpercentminusx');
2140 print '</td></tr>';
2141 }
2142
2143 $formproduct = null;
2144 // Warehouse
2145 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
2146 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
2147 $formproduct = new FormProduct($db);
2148 print '<tr class="field_warehouse_id"><td class="titlefieldcreate">'.$langs->trans('Warehouse').'</td><td class="valuefieldcreate">';
2149 print img_picto('', 'stock', 'class="pictofixedwidth"').$formproduct->selectWarehouses($warehouse_id, 'warehouse_id', '', 1, 0, 0, '', 0, 0, array(), 'maxwidth500 widthcentpercentminusxx');
2150 print '</td></tr>';
2151 }
2152
2153 // Delivery delay
2154 print '<tr class="field_availability_id"><td class="titlefieldcreate">'.$langs->trans('AvailabilityPeriod');
2155 if (isModEnabled('order')) {
2156 print ' ('.$langs->trans('AfterOrder').')';
2157 }
2158 print '</td><td class="valuefieldcreate">';
2159 print img_picto('', 'clock', 'class="pictofixedwidth"');
2160 $form->selectAvailabilityDelay((GETPOSTISSET('availability_id') ? GETPOSTINT('availability_id') : ''), 'availability_id', '', 1, 'maxwidth200 widthcentpercentminusx');
2161 print '</td></tr>';
2162
2163 // Delivery date (or manufacturing)
2164 print '<tr class="field_date_livraison"><td class="titlefieldcreate">'.$langs->trans("DeliveryDate").'</td>';
2165 print '<td class="valuefieldcreate">';
2166 print img_picto('', 'action', 'class="pictofixedwidth"');
2167 if (is_numeric(getDolGlobalString('DATE_LIVRAISON_WEEK_DELAY'))) { // If value set to 0 or a num, not empty
2168 $tmpdte = time() + (7 * getDolGlobalInt('DATE_LIVRAISON_WEEK_DELAY') * 24 * 60 * 60);
2169 $syear = date("Y", $tmpdte);
2170 $smonth = date("m", $tmpdte);
2171 $sday = date("d", $tmpdte);
2172 print $form->selectDate($syear."-".$smonth."-".$sday, 'date_livraison', 0, 0, 0, "addprop");
2173 } else {
2174 $tmp_date_delivery = GETPOST('date_delivery') ? : -1;
2175 print $form->selectDate($tmp_date_delivery, 'date_livraison', 0, 0, 0, "addprop", 1, 1);
2176 }
2177 print '</td></tr>';
2178
2179 // Project
2180 if (isModEnabled('project') && is_object($formproject)) {
2181 $langs->load("projects");
2182 print '<tr class="field_projectid">';
2183 print '<td class="titlefieldcreate">'.$langs->trans("Project").'</td><td class="valuefieldcreate">';
2184 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');
2185 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>';
2186 print '</td>';
2187 print '</tr>';
2188 }
2189
2190 // Incoterms
2191 if (isModEnabled('incoterm')) {
2192 print '<tr class="field_incoterm_id">';
2193 print '<td class="titlefieldcreate"><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), $soc->label_incoterms, 1).'</label></td>';
2194 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2195 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
2196 print $form->select_incoterms((!empty($soc->fk_incoterms) ? $soc->fk_incoterms : ''), (!empty($soc->location_incoterms) ? $soc->location_incoterms : ''));
2197 print '</td></tr>';
2198 }
2199
2200 // Template to use by default
2201 print '<tr class="field_model">';
2202 print '<td class="titlefieldcreate">'.$langs->trans("DefaultModel").'</td>';
2203 print '<td class="valuefieldcreate">';
2204 print img_picto('', 'pdf', 'class="pictofixedwidth"');
2206 $preselected = (getDolGlobalString('PROPALE_ADDON_PDF_ODT_DEFAULT') ? $conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT : getDolGlobalString("PROPALE_ADDON_PDF"));
2207 print $form->selectarray('model', $liste, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
2208 print "</td></tr>";
2209
2210 // Multicurrency
2211 if (isModEnabled("multicurrency")) {
2212 print '<tr class="field_currency">';
2213 print '<td class="titlefieldcreate">'.$form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0).'</td>';
2214 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2215 print img_picto('', 'currency', 'class="pictofixedwidth"').$form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0);
2216 print '</td></tr>';
2217 }
2218
2219 // Public note
2220 print '<tr class="field_note_public">';
2221 print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePublic').'</td>';
2222 print '<td class="valuefieldcreate">';
2223 $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');
2224 $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
2225 print $doleditor->Create(1);
2226
2227 // Private note
2228 if (empty($user->socid)) {
2229 print '<tr class="field_note_private">';
2230 print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePrivate').'</td>';
2231 print '<td class="valuefieldcreate">';
2232 $note_private = $object->getDefaultCreateValueFor('note_private', ((!empty($origin) && !empty($originid) && is_object($objectsrc)) ? $objectsrc->note_private : null));
2233 $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
2234 print $doleditor->Create(1);
2235 // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
2236 print '</td></tr>';
2237 }
2238
2239 // Other attributes
2240 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
2241
2242 // Lines from source
2243 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2244 // TODO for compatibility
2245 if ($origin == 'contrat') {
2246 // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
2247 //$objectsrc->remise_absolue = $remise_absolue; // deprecated
2248 //$objectsrc->remise_percent = $remise_percent;
2249 $objectsrc->update_price(1, 'auto', 1);
2250 }
2251
2252 print "\n<!-- ".$classname." info -->";
2253 print "\n";
2254 print '<input type="hidden" name="amount" value="'.$objectsrc->total_ht.'">'."\n";
2255 print '<input type="hidden" name="total" value="'.$objectsrc->total_ttc.'">'."\n";
2256 print '<input type="hidden" name="tva" value="'.$objectsrc->total_tva.'">'."\n";
2257 print '<input type="hidden" name="origin" value="'.$objectsrc->element.'">';
2258 print '<input type="hidden" name="originid" value="'.$objectsrc->id.'">';
2259
2260 $newclassname = $classname;
2261 if ($newclassname == 'Propal') {
2262 $newclassname = 'CommercialProposal';
2263 } elseif ($newclassname == 'Commande') {
2264 $newclassname = 'Order';
2265 } elseif ($newclassname == 'Expedition') {
2266 $newclassname = 'Sending';
2267 } elseif ($newclassname == 'Fichinter') {
2268 $newclassname = 'Intervention';
2269 }
2270
2271 print '<tr><td>'.$langs->trans($newclassname).'</td><td>'.$objectsrc->getNomUrl(1).'</td></tr>';
2272 print '<tr><td>'.$langs->trans('AmountHT').'</td><td>'.price($objectsrc->total_ht, 0, $langs, 1, -1, -1, $conf->currency).'</td></tr>';
2273 print '<tr><td>'.$langs->trans('AmountVAT').'</td><td>'.price($objectsrc->total_tva, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2274 if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
2275 print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2276 }
2277
2278 if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
2279 print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2280 }
2281 print '<tr><td>'.$langs->trans('AmountTTC').'</td><td>'.price($objectsrc->total_ttc, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2282
2283 if (isModEnabled("multicurrency")) {
2284 print '<tr><td>'.$langs->trans('MulticurrencyAmountHT').'</td><td>'.price($objectsrc->multicurrency_total_ht).'</td></tr>';
2285 print '<tr><td>'.$langs->trans('MulticurrencyAmountVAT').'</td><td>'.price($objectsrc->multicurrency_total_tva)."</td></tr>";
2286 print '<tr><td>'.$langs->trans('MulticurrencyAmountTTC').'</td><td>'.price($objectsrc->multicurrency_total_ttc)."</td></tr>";
2287 }
2288 }
2289
2290 print "</table>\n";
2291
2292
2293 /*
2294 * Combobox for copy function
2295 */
2296
2297 if (!getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2298 print '<input type="hidden" name="createmode" value="empty">';
2299 }
2300
2301 if (getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2302 print '<br><table>';
2303
2304 // For backward compatibility
2305 print '<tr>';
2306 print '<td><input type="radio" name="createmode" value="copy"></td>';
2307 print '<td>'.$langs->trans("CopyPropalFrom").' </td>';
2308 print '<td>';
2309 $liste_propal = array();
2310 $liste_propal [0] = '';
2311
2312 $sql = "SELECT p.rowid as id, p.ref, s.nom";
2313 $sql .= " FROM ".MAIN_DB_PREFIX."propal p";
2314 $sql .= ", ".MAIN_DB_PREFIX."societe s";
2315 $sql .= " WHERE s.rowid = p.fk_soc";
2316 $sql .= " AND p.entity IN (".getEntity('propal').")";
2317 $sql .= " AND p.fk_statut <> 0";
2318 $sql .= " ORDER BY Id";
2319
2320 $resql = $db->query($sql);
2321 if ($resql) {
2322 $num = $db->num_rows($resql);
2323 $i = 0;
2324 while ($i < $num) {
2325 $row = $db->fetch_row($resql);
2326 $propalRefAndSocName = $row[1]." - ".$row[2];
2327 $liste_propal[$row[0]] = $propalRefAndSocName;
2328 $i++;
2329 }
2330 print $form->selectarray("copie_propal", $liste_propal, 0);
2331 } else {
2332 dol_print_error($db);
2333 }
2334 print '</td></tr>';
2335
2336 print '<tr><td class="tdtop"><input type="radio" name="createmode" value="empty" checked></td>';
2337 print '<td valign="top" colspan="2">'.$langs->trans("CreateEmptyPropal").'</td></tr>';
2338 print '</table>';
2339 }
2340 }
2341
2342 print dol_get_fiche_end();
2343
2344 $langs->load("bills");
2345
2346 print $form->buttonsSaveCancel("CreateDraft");
2347
2348 print "</form>";
2349
2350
2351 // Show origin lines
2352 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2353 print '<br>';
2354
2355 $title = $langs->trans('ProductsAndServices');
2356 print load_fiche_titre($title);
2357
2358 print '<div class="div-table-responsive-no-min">';
2359 print '<table class="noborder centpercent">';
2360
2361 $objectsrc->printOriginLinesList();
2362
2363 print '</table>';
2364 print '</div>';
2365 }
2366} elseif ($object->id > 0) {
2367 /*
2368 * Show object in view mode
2369 */
2370 $object->fetch_thirdparty();
2371 if ($object->thirdparty) {
2372 $soc = $object->thirdparty;
2373 } else {
2374 $soc = new Societe($db);
2375 }
2376
2378 print dol_get_fiche_head($head, 'comm', $langs->trans('Proposal'), -1, 'propal', 0, '', '', 0, '', 1);
2379
2380 $formconfirm = '';
2381
2382 // Clone confirmation
2383 if ($action == 'clone') {
2384 // Create an array for form
2385 $filter = '(s.client:IN:1,2,3)';
2386 $formquestion = array(
2387 // 'text' => $langs->trans("ConfirmClone"),
2388 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
2389 array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOSTINT('socid'), 'socid', $filter, '', 0, 0, array(), 0, 'maxwidth300')),
2390 array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => 0),
2391 array('type' => 'checkbox', 'name' => 'update_desc', 'label' => $langs->trans('PuttingDescUpToDate'), 'value' => 0),
2392 );
2393 if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY') && !empty($object->delivery_date)) {
2394 $formquestion[] = array('type' => 'date', 'name' => 'date_delivery', 'label' => $langs->trans("DeliveryDate"), 'value' => $object->delivery_date);
2395 }
2396 // Incomplete payment. We ask if reason = discount or other
2397 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmClonePropal', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 250, 600);
2398 }
2399
2400 if ($action == 'closeas') {
2401 //Form to close proposal (signed or not)
2402 $formquestion = array();
2403 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
2404 $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)));
2405 }
2406 $formquestion[] = array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"), 'value' => ''); // Field to complete private note (not replace)
2407
2408 if (getDolGlobalInt('PROPOSAL_SUGGEST_DOWN_PAYMENT_INVOICE_CREATION')) {
2409 // This is a hidden option:
2410 // Suggestion to create invoice during proposal signature is not enabled by default.
2411 // Such choice should be managed by the workflow module and trigger. This option generates conflicts with some setup.
2412 // It may also break step of creating an order when invoicing must be done from orders and not from proposal
2413 $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
2414
2415 if (!empty($deposit_percent_from_payment_terms) && isModEnabled('invoice') && $user->hasRight('facture', 'creer')) {
2416 require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
2417
2418 $object->fetchObjectLinked();
2419
2420 $eligibleForDepositGeneration = true;
2421
2422 if (array_key_exists('facture', $object->linkedObjects)) {
2423 foreach ($object->linkedObjects['facture'] as $invoice) {
2424 '@phan-var-force Facture $invoice';
2425 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2426 $eligibleForDepositGeneration = false;
2427 break;
2428 }
2429 }
2430 }
2431
2432 if ($eligibleForDepositGeneration && array_key_exists('commande', $object->linkedObjects)) {
2433 foreach ($object->linkedObjects['commande'] as $order) {
2434 $order->fetchObjectLinked();
2435
2436 if (array_key_exists('facture', $order->linkedObjects)) {
2437 foreach ($order->linkedObjects['facture'] as $invoice) {
2438 '@phan-var-force Facture $invoice';
2439 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2440 $eligibleForDepositGeneration = false;
2441 break 2;
2442 }
2443 }
2444 }
2445 }
2446 }
2447
2448
2449 if ($eligibleForDepositGeneration) {
2450 $formquestion[] = array(
2451 'type' => 'checkbox',
2452 'tdclass' => 'showonlyifsigned',
2453 'name' => 'generate_deposit',
2454 'morecss' => 'margintoponly marginbottomonly',
2455 'label' => $form->textwithpicto($langs->trans('GenerateDeposit', $object->deposit_percent), $langs->trans('DepositGenerationPermittedByThePaymentTermsSelected'))
2456 );
2457
2458 $formquestion[] = array(
2459 'type' => 'date',
2460 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2461 'name' => 'datef',
2462 'label' => $langs->trans('DateInvoice'),
2463 'value' => dol_now(),
2464 'datenow' => true
2465 );
2466
2467 if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
2468 $formquestion[] = array(
2469 'type' => 'date',
2470 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2471 'name' => 'date_pointoftax',
2472 'label' => $langs->trans('DatePointOfTax'),
2473 'value' => dol_now(),
2474 'datenow' => true
2475 );
2476 }
2477
2478 $paymentTermsSelect = $form->getSelectConditionsPaiements(0, 'cond_reglement_id', -1, 0, 1, 'minwidth200');
2479
2480 $formquestion[] = array(
2481 'type' => 'other',
2482 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2483 'name' => 'cond_reglement_id',
2484 'label' => $langs->trans('PaymentTerm'),
2485 'value' => $paymentTermsSelect
2486 );
2487
2488 $formquestion[] = array(
2489 'type' => 'checkbox',
2490 'tdclass' => 'showonlyifgeneratedeposit',
2491 'name' => 'validate_generated_deposit',
2492 'morecss' => 'margintoponly marginbottomonly',
2493 'label' => $langs->trans('ValidateGeneratedDeposit')
2494 );
2495
2496 $formquestion[] = array(
2497 'type' => 'onecolumn',
2498 'value' => '
2499 <script>
2500 let signedValue = ' . $object::STATUS_SIGNED . ';
2501
2502 $(document).ready(function() {
2503 $("[name=generate_deposit]").change(function () {
2504 let $self = $(this);
2505 let $target = $(".showonlyifgeneratedeposit").parent(".tagtr");
2506
2507 if (! $self.parents(".tagtr").is(":hidden") && $self.is(":checked")) {
2508 $target.show();
2509 } else {
2510 $target.hide();
2511 }
2512
2513 return true;
2514 });
2515
2516 $("#statut").change(function() {
2517 let $target = $(".showonlyifsigned").parent(".tagtr");
2518
2519 if ($(this).val() == signedValue) {
2520 $target.show();
2521 } else {
2522 $target.hide();
2523 }
2524
2525 $("[name=generate_deposit]").trigger("change");
2526
2527 return true;
2528 });
2529
2530 $("#statut").trigger("change");
2531 });
2532 </script>
2533 '
2534 );
2535 }
2536 }
2537 }
2538
2539 if (isModEnabled('notification')) {
2540 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2541 $notify = new Notify($db);
2542 $formquestion = array_merge($formquestion, array(
2543 array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PROPAL_CLOSE_SIGNED', $object->socid, $object)),
2544 ));
2545 }
2546
2547 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
2548 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetAcceptedRefused'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2549 } else {
2550 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?statut=3&id=' . $object->id, $langs->trans('Close'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2551 }
2552 } elseif ($action == 'cancel') {
2553 // Confirm cancel
2554 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans("CancelPropal"), $langs->trans('ConfirmCancelPropal', $object->ref), 'confirm_cancel', '', 0, 1);
2555 } elseif ($action == 'delete') {
2556 // Confirm delete
2557 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteProp'), $langs->trans('ConfirmDeleteProp', $object->ref), 'confirm_delete', '', 0, 1);
2558 } elseif ($action == 'reopen') {
2559 // Confirm reopen
2560 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenProp', $object->ref), 'confirm_reopen', '', 0, 1);
2561 } elseif ($action == 'ask_deleteline') {
2562 // Confirmation delete product/service line
2563 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 0, 1);
2564 } elseif ($action == 'validate') {
2565 // Confirm validate proposal
2566 $error = 0;
2567
2568 // We verify whether the object is provisionally numbering
2569 $ref = substr($object->ref, 1, 4);
2570 if ($ref == 'PROV' || $ref == '') {
2571 $numref = $object->getNextNumRef($soc);
2572 if (empty($numref)) {
2573 $error++;
2574 setEventMessages($object->error, $object->errors, 'errors');
2575 }
2576 } else {
2577 $numref = $object->ref;
2578 }
2579
2580 $text = $langs->trans('ConfirmValidateProp', $numref);
2581 if (isModEnabled('notification')) {
2582 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2583 $notify = new Notify($db);
2584 $text .= '<br>';
2585 $text .= $notify->confirmMessage('PROPAL_VALIDATE', $object->socid, $object);
2586 }
2587
2588 // mandatoryPeriod
2589 $nbMandated = 0;
2590 foreach ($object->lines as $line) {
2591 $res = $line->fetch_product();
2592 if ($res > 0) {
2593 if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end))) {
2594 $nbMandated++;
2595 break;
2596 }
2597 }
2598 }
2599 if ($nbMandated > 0) {
2600 if (getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
2601 setEventMessages($langs->trans("mandatoryPeriodNeedTobeSetMsgValidate"), null, 'errors');
2602 $error++;
2603 } else {
2604 $text .= '<div><span class="clearboth nowraponall warning">'.img_warning().$langs->trans("mandatoryPeriodNeedTobeSetMsgValidate").'</span></div>';
2605 }
2606 }
2607
2608 if (!$error) {
2609 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateProp'), $text, 'confirm_validate', '', 0, 1, 240);
2610 }
2611 }
2612
2613 // Call Hook formConfirm
2614 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
2615 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2616 if (empty($reshook)) {
2617 $formconfirm .= $hookmanager->resPrint;
2618 } elseif ($reshook > 0) {
2619 $formconfirm = $hookmanager->resPrint;
2620 }
2621
2622 // Print form confirm
2623 print $formconfirm;
2624
2625
2626 // Proposal card
2627
2628 $linkback = '<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
2629
2630 $morehtmlref = '<div class="refidno">';
2631 // Ref customer
2632 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
2633 $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);
2634 // Thirdparty
2635 $morehtmlref .= '<br>'.$soc->getNomUrl(1, 'customer');
2636 if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $soc->id > 0) {
2637 $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?socid='.$soc->id.'&search_societe='.urlencode($soc->name).'">'.$langs->trans("OtherProposals").'</a>)';
2638 }
2639 // Project
2640 if (isModEnabled('project')) {
2641 $langs->load("projects");
2642 $morehtmlref .= '<br>';
2643 if ($usercancreate) {
2644 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
2645 if ($action != 'classify') {
2646 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
2647 }
2648 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
2649 } else {
2650 if (!empty($object->fk_project)) {
2651 $proj = new Project($db);
2652 $proj->fetch($object->fk_project);
2653 $morehtmlref .= $proj->getNomUrl(1);
2654 if ($proj->title) {
2655 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
2656 }
2657 }
2658 }
2659 }
2660 $morehtmlref .= '</div>';
2661
2662
2663 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
2664
2665 // Call Hook tabContentViewProposal
2666 $parameters = array();
2667 // Note that $action and $object may be modified by hook
2668 $reshook = $hookmanager->executeHooks('tabContentViewProposal', $parameters, $object, $action);
2669 if (empty($reshook)) {
2670 print '<div class="fichecenter">';
2671 print '<div class="fichehalfleft">';
2672 print '<div class="underbanner clearboth"></div>';
2673
2674 print '<table class="border tableforfield centpercent">';
2675
2676 // Link for thirdparty discounts
2677 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
2678 $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
2679 $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
2680 } else {
2681 $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
2682 $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
2683 }
2684
2685 print '<tr><td class="titlefieldmax45">'.$langs->trans('Discounts').'</td><td>';
2686
2687 $absolute_discount = $soc->getAvailableDiscounts(null, $filterabsolutediscount);
2688 $absolute_creditnote = $soc->getAvailableDiscounts(null, $filtercreditnote);
2689 $absolute_discount = price2num($absolute_discount, 'MT');
2690 $absolute_creditnote = price2num($absolute_creditnote, 'MT');
2691
2692 $caneditfield = ($object->status != Propal::STATUS_SIGNED && $object->status != Propal::STATUS_BILLED);
2693
2694 $thirdparty = $soc;
2695 $discount_type = 0;
2696 $backtopage = $_SERVER["PHP_SELF"].'?id='.$object->id;
2697 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
2698
2699 print '</td></tr>';
2700
2701 // Date of proposal
2702 print '<tr>';
2703 print '<td>';
2704 // print '<table class="nobordernopadding" width="100%"><tr><td>';
2705 // print $langs->trans('DatePropal');
2706 // print '</td>';
2707 // if ($action != 'editdate' && $usercancreate && $caneditfield) {
2708 // 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>';
2709 // }
2710
2711 // print '</tr></table>';
2712 $editenable = $usercancreate && $caneditfield && $object->status == Propal::STATUS_DRAFT;
2713 print $form->editfieldkey("DatePropal", 'date', '', $object, $editenable);
2714 print '</td><td class="valuefield">';
2715 if ($action == 'editdate' && $usercancreate && $caneditfield) {
2716 print '<form name="editdate" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2717 print '<input type="hidden" name="token" value="'.newToken().'">';
2718 print '<input type="hidden" name="action" value="setdate">';
2719 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2720 print $form->selectDate($object->date, 're', 0, 0, 0, "editdate");
2721 print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
2722 print '</form>';
2723 } else {
2724 if ($object->date) {
2725 print dol_print_date($object->date, 'day');
2726 } else {
2727 print '&nbsp;';
2728 }
2729 }
2730 print '</td>';
2731
2732 // Date end proposal
2733 print '<tr>';
2734 print '<td>';
2735 print '<table class="nobordernopadding centpercent"><tr><td>';
2736 print $langs->trans('DateEndPropal');
2737 print '</td>';
2738 if ($action != 'editecheance' && $usercancreate && $caneditfield) {
2739 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>';
2740 }
2741 print '</tr></table>';
2742 print '</td><td class="valuefield">';
2743 if ($action == 'editecheance' && $usercancreate && $caneditfield) {
2744 print '<form name="editecheance" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2745 print '<input type="hidden" name="token" value="'.newToken().'">';
2746 print '<input type="hidden" name="action" value="setecheance">';
2747 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2748 print $form->selectDate($object->fin_validite, 'ech', 0, 0, 0, "editecheance");
2749 print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
2750 print '</form>';
2751 } else {
2752 if (!empty($object->fin_validite)) {
2753 print dol_print_date($object->fin_validite, 'day');
2754 if ($object->status == Propal::STATUS_VALIDATED && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) {
2755 print img_warning($langs->trans("Late"));
2756 }
2757 } else {
2758 print '&nbsp;';
2759 }
2760 }
2761 print '</td>';
2762 print '</tr>';
2763
2764 // Payment term
2765 print '<tr><td>';
2766 print '<table class="nobordernopadding centpercent"><tr><td>';
2767 print $langs->trans('PaymentConditionsShort');
2768 print '</td>';
2769 if ($action != 'editconditions' && $usercancreate && $caneditfield) {
2770 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>';
2771 }
2772 print '</tr></table>';
2773 print '</td><td class="valuefield">';
2774 if ($action == 'editconditions' && $usercancreate && $caneditfield) {
2775 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 0, '', 1, $object->deposit_percent);
2776 } else {
2777 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none', 0, '', 1, $object->deposit_percent);
2778 }
2779 print '</td>';
2780 print '</tr>';
2781
2782 // Payment mode
2783 print '<tr class="field_mode_reglement_id">';
2784 print '<td>';
2785 print '<table class="nobordernopadding centpercent"><tr><td>';
2786 print $langs->trans('PaymentMode');
2787 print '</td>';
2788 if ($action != 'editmode' && $usercancreate && $caneditfield) {
2789 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>';
2790 }
2791 print '</tr></table>';
2792 print '</td><td class="valuefieldcreate">';
2793 if ($action == 'editmode' && $usercancreate && $caneditfield) {
2794 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
2795 } else {
2796 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'none');
2797 }
2798 print '</td></tr>';
2799
2800 // Delivery date
2801 $langs->load('deliveries');
2802 print '<tr><td>';
2803 print $form->editfieldkey($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
2804 print '</td><td class="valuefieldedit">';
2805 print $form->editfieldval($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
2806 print '</td>';
2807 print '</tr>';
2808
2809 // Delivery delay
2810 print '<tr class="fielddeliverydelay"><td>';
2811 print '<table class="nobordernopadding centpercent"><tr><td>';
2812 if (isModEnabled('order')) {
2813 print $form->textwithpicto($langs->trans('AvailabilityPeriod'), $langs->trans('AvailabilityPeriod').' ('.$langs->trans('AfterOrder').')');
2814 } else {
2815 print $langs->trans('AvailabilityPeriod');
2816 }
2817 print '</td>';
2818 if ($action != 'editavailability' && $usercancreate && $caneditfield) {
2819 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>';
2820 }
2821 print '</tr></table>';
2822 print '</td><td class="valuefield">';
2823 if ($action == 'editavailability' && $usercancreate && $caneditfield) {
2824 $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'availability_id', 1);
2825 } else {
2826 $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'none', 1);
2827 }
2828
2829 print '</td>';
2830 print '</tr>';
2831
2832 // Shipping Method
2833 if (isModEnabled("shipping")) {
2834 print '<tr><td>';
2835 print '<table class="nobordernopadding centpercent"><tr><td>';
2836 print $langs->trans('SendingMethod');
2837 print '</td>';
2838 if ($action != 'editshippingmethod' && $usercancreate && $caneditfield) {
2839 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>';
2840 }
2841 print '</tr></table>';
2842 print '</td><td class="valuefield">';
2843 if ($action == 'editshippingmethod' && $usercancreate && $caneditfield) {
2844 $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'shipping_method_id', 1);
2845 } else {
2846 $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'none');
2847 }
2848 print '</td>';
2849 print '</tr>';
2850 }
2851
2852 // Warehouse
2853 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
2854 $langs->load('stocks');
2855 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
2856 $formproduct = new FormProduct($db);
2857 print '<tr class="field_warehouse_id"><td>';
2858 $editenable = $usercancreate;
2859 print $form->editfieldkey("Warehouse", 'warehouse', '', $object, $editenable);
2860 print '</td><td class="valuefieldcreate">';
2861 if ($action == 'editwarehouse') {
2862 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'warehouse_id', 1);
2863 } else {
2864 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'none');
2865 }
2866 print '</td>';
2867 print '</tr>';
2868 }
2869
2870 // Origin of demand
2871 print '<tr><td>';
2872 print '<table class="nobordernopadding centpercent"><tr><td>';
2873 print $langs->trans('Source');
2874 print '</td>';
2875 if ($action != 'editdemandreason' && $usercancreate) {
2876 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>';
2877 }
2878 print '</tr></table>';
2879 print '</td><td class="valuefield">';
2880 if ($action == 'editdemandreason' && $usercancreate) {
2881 $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'demand_reason_id', 1);
2882 } else {
2883 $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'none');
2884 }
2885 print '</td>';
2886 print '</tr>';
2887
2888 if ($soc->outstanding_limit) {
2889 // Outstanding Bill
2890 print '<tr><td>';
2891 print $langs->trans('OutstandingBill');
2892 print '</td><td class="valuefield">';
2893 $arrayoutstandingbills = $soc->getOutstandingBills();
2894 print($arrayoutstandingbills['opened'] > $soc->outstanding_limit ? img_warning() : '');
2895 print price($arrayoutstandingbills['opened']).' / ';
2896 print price($soc->outstanding_limit, 0, $langs, 1, - 1, - 1, $conf->currency);
2897 print '</td>';
2898 print '</tr>';
2899 }
2900
2901 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
2902 // Bank Account
2903 print '<tr><td>';
2904 print '<table width="100%" class="nobordernopadding"><tr><td>';
2905 print $langs->trans('BankAccount');
2906 print '</td>';
2907 if ($action != 'editbankaccount' && $usercancreate) {
2908 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>';
2909 }
2910 print '</tr></table>';
2911 print '</td><td class="valuefield">';
2912 if ($action == 'editbankaccount') {
2913 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1);
2914 } else {
2915 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none');
2916 }
2917 print '</td>';
2918 print '</tr>';
2919 }
2920
2921 if (!getDolGlobalString('PROPOSAL_HIDE_CALCULATED_WEIGHT_VOLUME')) {
2922 $tmparray = $object->getTotalWeightVolume();
2923 $totalWeight = isset($tmparray['weight']) ? $tmparray['weight'] : 0;
2924 $totalVolume = isset($tmparray['volume']) ? $tmparray['volume'] : 0;
2925 if ($totalWeight) {
2926 print '<tr><td>'.$langs->trans("CalculatedWeight").'</td>';
2927 print '<td class="valuefield">';
2928 print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, getDolGlobalInt('MAIN_WEIGHT_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_WEIGHT_DEFAULT_UNIT', 'no'), 1);
2929 print '</td></tr>';
2930 }
2931 if ($totalVolume) {
2932 print '<tr><td>'.$langs->trans("CalculatedVolume").'</td>';
2933 print '<td class="valuefield">';
2934 print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'), 1);
2935 print '</td></tr>';
2936 }
2937 }
2938
2939 // Incoterms
2940 if (isModEnabled('incoterm')) {
2941 print '<tr><td>';
2942 print '<table width="100%" class="nobordernopadding"><tr><td>';
2943 print $langs->trans('IncotermLabel');
2944 print '<td><td class="right">';
2945 if ($action != 'editincoterm' && $usercancreate && $caneditfield) {
2946 print '<a class="editfielda" href="'.DOL_URL_ROOT.'/comm/propal/card.php?id='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
2947 } else {
2948 print '&nbsp;';
2949 }
2950 print '</td></tr></table>';
2951 print '</td>';
2952 print '<td class="valuefield">';
2953 if ($action == 'editincoterm' && $usercancreate && $caneditfield) {
2954 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
2955 } else {
2956 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
2957 }
2958 print '</td></tr>';
2959 }
2960
2961 // Other attributes
2962 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
2963
2964 print '</table>';
2965
2966 print '</div>';
2967 print '<div class="fichehalfright">';
2968 print '<div class="underbanner clearboth"></div>';
2969
2970 print '<table class="border tableforfield centpercent">';
2971
2972 include DOL_DOCUMENT_ROOT.'/core/tpl/object_currency_amount.tpl.php';
2973
2974 print '<tr>';
2975 print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
2976 print '<td class="nowrap amountcard right">' . price($object->total_ht, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
2977 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2978 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ht, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2979 }
2980 print '</tr>';
2981
2982 print '<tr>';
2983 print '<td>' . $langs->trans('AmountVAT') . '</td>';
2984 print '<td class="nowrap amountcard right">' . price($object->total_tva, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
2985 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2986 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_tva, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2987 }
2988 print '</tr>';
2989
2990 if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
2991 print '<tr>';
2992 print '<td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
2993 print '<td class="nowrap amountcard right">' . price($object->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
2994 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2995 $object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
2996
2997 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax1, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2998 }
2999 print '</tr>';
3000 }
3001
3002 if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
3003 print '<tr>';
3004 print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
3005 print '<td class="nowrap amountcard right">' . price($object->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3006 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3007 $object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
3008
3009 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax2, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3010 }
3011 print '</tr>';
3012 }
3013
3014 print '<tr>';
3015 print '<td>' . $langs->trans('AmountTTC') . '</td>';
3016 print '<td class="nowrap amountcard right">' . price($object->total_ttc, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3017 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3018 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ttc, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3019 }
3020 print '</tr>';
3021
3022 print '</table>';
3023
3024 // Margin Infos
3025 if (isModEnabled('margin')) {
3026 $formmargin->displayMarginInfos($object);
3027 }
3028
3029 print '</div>';
3030 print '</div>';
3031
3032 print '<div class="clearboth"></div><br>';
3033
3034 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
3035 $blocname = 'contacts';
3036 $title = $langs->trans('ContactsAddresses');
3037 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
3038 }
3039
3040 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
3041 $blocname = 'notes';
3042 $title = $langs->trans('Notes');
3043 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
3044 }
3045
3046 /*
3047 * Lines
3048 */
3049
3050 // Get object lines
3051 $result = $object->getLinesArray();
3052
3053 // Add products/services form
3054 //$forceall = 1;
3055 global $inputalsopricewithtax;
3056 $inputalsopricewithtax = 1;
3057
3058 print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">
3059 <input type="hidden" name="token" value="' . newToken().'">
3060 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
3061 <input type="hidden" name="mode" value="">
3062 <input type="hidden" name="page_y" value="">
3063 <input type="hidden" name="backtopage" value="'.$backtopage.'">
3064 <input type="hidden" name="id" value="' . $object->id.'">
3065 ';
3066
3067 if (!empty($conf->use_javascript_ajax) && $object->status == Propal::STATUS_DRAFT) {
3068 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
3069 }
3070
3071 print '<div class="div-table-responsive-no-min">';
3072 if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
3073 print '<table id="tablelines" class="noborder noshadow centpercent">';
3074 }
3075
3076 if (!empty($object->lines)) {
3077 $object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 1);
3078 }
3079
3080 // Form to add new line
3081 if ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines') {
3082 if ($action != 'editline') {
3083 $parameters = array();
3084 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3085 if ($reshook < 0) {
3086 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3087 }
3088 if (empty($reshook)) {
3089 $object->formAddObjectLine(1, $mysoc, $soc);
3090 }
3091 } else {
3092 $parameters = array();
3093 $reshook = $hookmanager->executeHooks('formEditObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3094 }
3095 }
3096
3097 if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
3098 print '</table>';
3099 }
3100 print '</div>';
3101
3102 print "</form>\n";
3103 }
3104
3105 print dol_get_fiche_end();
3106
3107
3108 /*
3109 * Button Actions
3110 */
3111
3112 if ($action != 'presend') {
3113 $numlines = count($object->lines);
3114 print '<div class="tabsAction">';
3115
3116 $parameters = array();
3117 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
3118 // modified by hook
3119 if (empty($reshook)) {
3120 if ($action != 'editline') {
3121 // Validate
3122 if (($object->status == Propal::STATUS_DRAFT && $object->total_ttc >= 0 && count($object->lines) > 0)
3123 || ($object->status == Propal::STATUS_DRAFT && getDolGlobalString('PROPAL_ENABLE_NEGATIVE') && count($object->lines) > 0)) {
3124 if ($usercanvalidate) {
3125 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>';
3126 } else {
3127 print '<a class="butActionRefused classfortooltip" href="#">'.$langs->trans('Validate').'</a>';
3128 }
3129 }
3130 // Create event
3131 /*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.
3132 {
3133 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>';
3134 }*/
3135 // Edit
3136 if ($object->status == Propal::STATUS_VALIDATED && $usercancreate) {
3137 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=modif&token='.newToken().'">'.$langs->trans('Modify').'</a>';
3138 }
3139
3140 // ReOpen
3141 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) {
3142 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken().(!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#reopen').'"';
3143 print '>'.$langs->trans('ReOpen').'</a>';
3144 }
3145
3146 // Send
3147 if (empty($user->socid)) {
3148 if ($object->status == Propal::STATUS_VALIDATED || $object->status == Propal::STATUS_SIGNED || getDolGlobalString('PROPOSAL_SENDBYEMAIL_FOR_ALL_STATUS')) {
3149 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?action=presend&token='.newToken().'&id='.$object->id.'&mode=init#formmailbeforetitle', '', $usercansend);
3150 }
3151 }
3152
3153 $arrayforbutaction = array();
3154
3155 // Create a sale order
3156 $arrayforbutaction[] = array(
3157 'lang' => 'orders',
3158 'enabled' => (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED),
3159 'perm' => $usercancreateorder,
3160 'label' => 'AddOrder',
3161 'url' => '/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3162 );
3163 /*if (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED) {
3164 if ($usercancreateorder) {
3165 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>';
3166 }
3167 }*/
3168
3169 // Create a purchase order
3170 if (getDolGlobalString('WORKFLOW_CAN_CREATE_PURCHASE_ORDER_FROM_PROPOSAL')) {
3171 $arrayforbutaction[] = array(
3172 'lang' => 'orders',
3173 'enabled' => ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")),
3174 'perm' => $usercancreatepurchaseorder,
3175 'label' => 'AddPurchaseOrder',
3176 'url' => '/fourn/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3177 );
3178 /*if ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")) {
3179 if ($usercancreatepurchaseorder) {
3180 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>';
3181 }
3182 }*/
3183 }
3184
3185 // Create an intervention
3186 $arrayforbutaction[] = array(
3187 'lang' => 'interventions',
3188 'enabled' => (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED),
3189 'perm' => $usercancreateintervention,
3190 'label' => 'AddIntervention',
3191 'url' => '/fichinter/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3192 );
3193 /*if (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED) {
3194 if ($usercancreateintervention) {
3195 $langs->load("interventions");
3196 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>';
3197 }
3198 }*/
3199
3200 // Create contract
3201 $arrayforbutaction[] = array(
3202 'lang' => 'contracts',
3203 'enabled' => (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED),
3204 'perm' => $usercancreatecontract,
3205 'label' => 'AddContract',
3206 'url' => '/contrat/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3207 );
3208 /*if (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED) {
3209 $langs->load("contracts");
3210
3211 if ($usercancreatecontract) {
3212 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>';
3213 }
3214 }*/
3215
3216 // Create an invoice and classify billed
3217 if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
3218 $arrayforbutaction[] = [
3219 'lang' => 'invoice',
3220 'enabled' => isModEnabled('invoice'),
3221 'perm' => $usercancreateinvoice,
3222 'label' => 'CreateBill',
3223 'url' => '/compta/facture/card.php?action=create&origin='.urlencode($object->element).'&originid='.((int) $object->id).'&socid='.((int) $object->socid),
3224 ];
3225 /*if (isModEnabled('invoice') && $usercancreateinvoice) {
3226 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>';
3227 }*/
3228 }
3229
3230 $actionButtonsParameters = [
3231 "areDropdownButtons" => !getDolGlobalInt("MAIN_REMOVE_DROPDOWN_CREATE_BUTTONS_ON_ORDER"),
3232 "backtopage" => $_SERVER["PHP_SELF"] . "?id=" . ((int) $id)
3233 ];
3234
3235 if ($numlines > 0) {
3236 print dolGetButtonAction('', $langs->trans("Create"), 'default', $arrayforbutaction, $object->id, 1, $actionButtonsParameters);
3237 } else {
3238 print dolGetButtonAction($langs->trans("ErrorObjectMustHaveLinesToBeValidated", $object->ref), $langs->trans("Create"), 'default', $arrayforbutaction, $object->id, 0, $actionButtonsParameters);
3239 }
3240
3241 if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
3242 $arrayofinvoiceforpropal = $object->getInvoiceArrayList();
3243 if ((is_array($arrayofinvoiceforpropal) && count($arrayofinvoiceforpropal) > 0) || !getDolGlobalString('WORKFLOW_PROPAL_NEED_INVOICE_TO_BE_CLASSIFIED_BILLED')) {
3244 if ($usercanclose) {
3245 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=classifybilled&token='.newToken().'&socid='.$object->socid.'">'.$langs->trans("ClassifyBilled").'</a>';
3246 } else {
3247 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("ClassifyBilled").'</a>';
3248 }
3249 }
3250 }
3251
3252 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
3253 // Close as accepted/refused
3254 if ($object->status == Propal::STATUS_VALIDATED) {
3255 if ($usercanclose) {
3256 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=closeas&token='.newToken().(!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close').'"';
3257 print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3258 } else {
3259 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'"';
3260 print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3261 }
3262 }
3263 } else {
3264 // Set not signed (close)
3265 if ($object->status == Propal::STATUS_DRAFT && $usercanclose) {
3266 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&token='.newToken().'&action=closeas&token='.newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close') . '"';
3267 print '>' . $langs->trans('SetRefusedAndClose') . '</a>';
3268 }
3269 }
3270
3271 // Cancel propal
3272 if ($object->status > Propal::STATUS_DRAFT && $usercanclose) {
3273 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=cancel&token='.newToken().'">'.$langs->trans("CancelPropal").'</a>';
3274 }
3275
3276 // Clone
3277 if ($usercancreate) {
3278 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>';
3279 }
3280
3281 // Delete
3282 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $usercandelete);
3283 }
3284 }
3285
3286 print '</div>';
3287 }
3288
3289 //Select mail models is same action as presend
3290 if (GETPOST('modelselected')) {
3291 $action = 'presend';
3292 }
3293
3294 if ($action != 'presend') {
3295 print '<div class="fichecenter"><div class="fichehalfleft">';
3296 print '<a name="builddoc"></a>'; // ancre
3297 /*
3298 * Generated documents
3299 */
3300 $objref = dol_sanitizeFileName($object->ref);
3301 $filedir = $conf->propal->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref);
3302 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
3303 $genallowed = $usercanread;
3304 $delallowed = $usercancreate;
3305
3306 print $formfile->showdocuments('propal', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', 0, '', $soc->default_lang, '', $object);
3307
3308 // Show links to link elements
3309 $tmparray = $form->showLinkToObjectBlock($object, array(), array('propal'), 1);
3310 $linktoelem = $tmparray['linktoelem'];
3311 $htmltoenteralink = $tmparray['htmltoenteralink'];
3312 print $htmltoenteralink;
3313
3314 $compatibleImportElementsList = false;
3315 if ($user->hasRight('propal', 'creer') && $object->status == Propal::STATUS_DRAFT) {
3316 $compatibleImportElementsList = array('commande', 'propal', 'facture'); // import from linked elements
3317 }
3318 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
3319
3320 // Show online signature link
3321 $useonlinesignature = getDolGlobalInt('PROPOSAL_ALLOW_ONLINESIGN');
3322
3323 if ($object->status != Propal::STATUS_DRAFT && $useonlinesignature) {
3324 print '<br><!-- Link to sign -->';
3325 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
3326 print showOnlineSignatureUrl('proposal', $object->ref, $object).'<br>';
3327 }
3328
3329 print '</div><div class="fichehalfright">';
3330
3331 $MAXEVENT = 10;
3332
3333 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/comm/propal/agenda.php?id='.$object->id);
3334
3335 // List of actions on element
3336 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
3337 $formactions = new FormActions($db);
3338 $somethingshown = $formactions->showactions($object, 'propal', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
3339
3340 print '</div></div>';
3341 }
3342
3343 // Presend form
3344 $modelmail = 'propal_send';
3345 $defaulttopic = 'SendPropalRef';
3346 $diroutput = $conf->propal->multidir_output[$object->entity];
3347 $trackid = 'pro'.$object->id;
3348
3349 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
3350}
3351
3352// End of page
3353llxFooter();
3354$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_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
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_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
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.