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