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