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