dolibarr  17.0.4
card.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
5  * Copyright (C) 2005-2015 Regis Houssin <regis.houssin@capnetworks.com>
6  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
7  * Copyright (C) 2006 Auguria SARL <info@auguria.org>
8  * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
9  * Copyright (C) 2013-2016 Marcos García <marcosgdf@gmail.com>
10  * Copyright (C) 2012-2013 Cédric Salvador <csalvador@gpcsolutions.fr>
11  * Copyright (C) 2011-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
12  * Copyright (C) 2014 Cédric Gross <c.gross@kreiz-it.fr>
13  * Copyright (C) 2014-2015 Ferran Marcet <fmarcet@2byte.es>
14  * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
15  * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
16  * Copyright (C) 2016-2022 Charlene Benke <charlene@patas-monkey.com>
17  * Copyright (C) 2016 Meziane Sof <virtualsof@yahoo.fr>
18  * Copyright (C) 2017 Josep Lluís Amador <joseplluis@lliuretic.cat>
19  * Copyright (C) 2019-2022 Frédéric France <frederic.france@netlogic.fr>
20  * Copyright (C) 2019-2020 Thibault FOUCART <support@ptibogxiv.net>
21  * Copyright (C) 2020 Pierre Ardoin <mapiolca@me.com>
22  * Copyright (C) 2022 Vincent de Grandpré <vincent@de-grandpre.quebec>
23  *
24  * This program is free software; you can redistribute it and/or modify
25  * it under the terms of the GNU General Public License as published by
26  * the Free Software Foundation; either version 3 of the License, or
27  * (at your option) any later version.
28  *
29  * This program is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32  * GNU General Public License for more details.
33  *
34  * You should have received a copy of the GNU General Public License
35  * along with this program. If not, see <https://www.gnu.org/licenses/>.
36  */
37 
45 // Load Dolibarr environment
46 require '../main.inc.php';
47 require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
48 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
49 require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php';
50 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
51 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
52 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
53 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
54 require_once DOL_DOCUMENT_ROOT.'/core/modules/product/modules_product.class.php';
55 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
56 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
57 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
58 require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
59 
60 if (isModEnabled('propal')) {
61  require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
62 }
63 if (isModEnabled('facture')) {
64  require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
65 }
66 if (isModEnabled('commande')) {
67  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
68 }
69 if (isModEnabled('accounting')) {
70  require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
71  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
72  require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
73 }
74 if (isModEnabled('bom')) {
75  require_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
76 }
77 
78 // Load translation files required by the page
79 $langs->loadLangs(array('products', 'other'));
80 if (isModEnabled('stock')) {
81  $langs->load("stocks");
82 }
83 if (isModEnabled('facture')) {
84  $langs->load("bills");
85 }
86 if (isModEnabled('productbatch')) {
87  $langs->load("productbatch");
88 }
89 
90 $mesg = ''; $error = 0; $errors = array();
91 
92 $refalreadyexists = 0;
93 
94 // Get parameters
95 $id = GETPOST('id', 'int');
96 $ref = (GETPOSTISSET('ref') ? GETPOST('ref', 'alpha') : null);
97 $type = (GETPOSTISSET('type') ? GETPOST('type', 'int') : Product::TYPE_PRODUCT);
98 $action = (GETPOST('action', 'alpha') ? GETPOST('action', 'alpha') : 'view');
99 $cancel = GETPOST('cancel', 'alpha');
100 $backtopage = GETPOST('backtopage', 'alpha');
101 $confirm = GETPOST('confirm', 'alpha');
102 $socid = GETPOST('socid', 'int');
103 $duration_value = GETPOST('duration_value', 'int');
104 $duration_unit = GETPOST('duration_unit', 'alpha');
105 
106 $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
107 $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
108 $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
109 $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
110 $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
111 $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
112 
113 $checkmandatory = GETPOST('accountancy_code_buy_export', 'alpha');
114 
115 // by default 'alphanohtml' (better security); hidden conf MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML allows basic html
116 $label_security_check = empty($conf->global->MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML) ? 'alphanohtml' : 'restricthtml';
117 
118 if (!empty($user->socid)) {
119  $socid = $user->socid;
120 }
121 
122 // Load object modCodeProduct
123 $module = (!empty($conf->global->PRODUCT_CODEPRODUCT_ADDON) ? $conf->global->PRODUCT_CODEPRODUCT_ADDON : 'mod_codeproduct_leopard');
124 if (substr($module, 0, 16) == 'mod_codeproduct_' && substr($module, -3) == 'php') {
125  $module = substr($module, 0, dol_strlen($module) - 4);
126 }
127 $result = dol_include_once('/core/modules/product/'.$module.'.php');
128 if ($result > 0) {
129  $modCodeProduct = new $module();
130 }
131 
132 $object = new Product($db);
133 $object->type = $type; // so test later to fill $usercancxxx is correct
134 $extrafields = new ExtraFields($db);
135 
136 // fetch optionals attributes and labels
137 $extrafields->fetch_name_optionals_label($object->table_element);
138 
139 if ($id > 0 || !empty($ref)) {
140  $result = $object->fetch($id, $ref);
141  if ($result < 0) {
142  dol_print_error($db, $object->error, $object->errors);
143  }
144  $entity = (!empty($object->entity) ? $object->entity : $conf->entity);
145  if (isModEnabled("product")) {
146  $upload_dir = $conf->product->multidir_output[$entity].'/'.get_exdir(0, 0, 0, 0, $object, 'product').dol_sanitizeFileName($object->ref);
147  } elseif (isModEnabled("service")) {
148  $upload_dir = $conf->service->multidir_output[$entity].'/'.get_exdir(0, 0, 0, 0, $object, 'product').dol_sanitizeFileName($object->ref);
149  }
150 
151  if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) { // For backward compatiblity, we scan also old dirs
152  if (isModEnabled("product")) {
153  $upload_dirold = $conf->product->multidir_output[$entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos";
154  } else {
155  $upload_dirold = $conf->service->multidir_output[$entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos";
156  }
157  }
158 }
159 
160 $modulepart = 'product';
161 
162 // Get object canvas (By default, this is not defined, so standard usage of dolibarr)
163 $canvas = !empty($object->canvas) ? $object->canvas : GETPOST("canvas");
164 $objcanvas = null;
165 if (!empty($canvas)) {
166  require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
167  $objcanvas = new Canvas($db, $action);
168  $objcanvas->getCanvas('product', 'card', $canvas);
169 }
170 
171 // Security check
172 $fieldvalue = (!empty($id) ? $id : (!empty($ref) ? $ref : ''));
173 $fieldtype = (!empty($id) ? 'rowid' : 'ref');
174 
175 if ($object->id > 0) {
176  if ($object->type == $object::TYPE_PRODUCT) {
177  restrictedArea($user, 'produit', $object->id, 'product&product', '', '');
178  }
179  if ($object->type == $object::TYPE_SERVICE) {
180  restrictedArea($user, 'service', $object->id, 'product&product', '', '');
181  }
182 } else {
183  restrictedArea($user, 'produit|service', 0, 'product&product', '', '', $fieldtype);
184 }
185 
186 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
187 $hookmanager->initHooks(array('productcard', 'globalcard'));
188 
189 // Permissions
190 $usercanread = (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->lire) || ($object->type == Product::TYPE_SERVICE && $user->rights->service->lire));
191 $usercancreate = (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->creer) || ($object->type == Product::TYPE_SERVICE && $user->rights->service->creer));
192 $usercandelete = (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->supprimer) || ($object->type == Product::TYPE_SERVICE && $user->rights->service->supprimer));
193 
194 
195 /*
196  * Actions
197  */
198 
199 if ($cancel) {
200  $action = '';
201 }
202 
203 $createbarcode = empty($conf->barcode->enabled) ? 0 : 1;
204 if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->creer_advance)) {
205  $createbarcode = 0;
206 }
207 
208 $parameters = array('id'=>$id, 'ref'=>$ref, 'objcanvas'=>$objcanvas);
209 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
210 if ($reshook < 0) {
211  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
212 }
213 
214 if (empty($reshook)) {
215  $backurlforlist = DOL_URL_ROOT.'/product/list.php?type='.$type;
216 
217  if (empty($backtopage) || ($cancel && empty($id))) {
218  if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
219  if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
220  $backtopage = $backurlforlist;
221  } else {
222  $backtopage = DOL_URL_ROOT.'/product/card.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
223  }
224  }
225  }
226 
227  if ($cancel) {
228  if (!empty($backtopageforcancel)) {
229  header("Location: ".$backtopageforcancel);
230  exit;
231  } elseif (!empty($backtopage)) {
232  header("Location: ".$backtopage);
233  exit;
234  }
235  $action = '';
236  }
237  // merge products
238  if ($action == 'confirm_merge' && $confirm == 'yes' && $user->rights->societe->creer) {
239  $error = 0;
240  $productOriginId = GETPOST('product_origin', 'int');
241  $productOrigin = new Product($db);
242 
243  if ($productOriginId <= 0) {
244  $langs->load('errors');
245  setEventMessages($langs->trans('ErrorProductIdIsMandatory', $langs->transnoentitiesnoconv('MergeOriginProduct')), null, 'errors');
246  } else {
247  if (!$error && $productOrigin->fetch($productOriginId) < 1) {
248  setEventMessages($langs->trans('ErrorRecordNotFound'), null, 'errors');
249  $error++;
250  }
251 
252  if (!$error) {
253  // TODO Move the merge function into class of object.
254  $db->begin();
255 
256  // Recopy some data
257  $listofproperties = array(
258  'ref',
259  'ref_ext',
260  'label',
261  'description',
262  'url',
263  'barcode',
264  'fk_barcode_type',
265  'import_key',
266  'mandatory_period',
267  'accountancy_code_buy',
268  'accountancy_code_buy_intra',
269  'accountancy_code_buy_export',
270  'accountancy_code_sell',
271  'accountancy_code_sell_intra',
272  'accountancy_code_sell_export'
273  );
274  foreach ($listofproperties as $property) {
275  if (empty($object->$property)) {
276  $object->$property = $productOrigin->$property;
277  }
278  }
279  // Concat some data
280  $listofproperties = array(
281  'note_public', 'note_private'
282  );
283  foreach ($listofproperties as $property) {
284  $object->$property = dol_concatdesc($object->$property, $productOrigin->$property);
285  }
286 
287  // Merge extrafields
288  if (is_array($productOrigin->array_options)) {
289  foreach ($productOrigin->array_options as $key => $val) {
290  if (empty($object->array_options[$key])) {
291  $object->array_options[$key] = $val;
292  }
293  }
294  }
295 
296  // Merge categories
297  $static_cat = new Categorie($db);
298  $custcats_ori = $static_cat->containing($productOrigin->id, 'product', 'id');
299  $custcats = $static_cat->containing($object->id, 'product', 'id');
300  $custcats = array_merge($custcats, $custcats_ori);
301  $object->setCategories($custcats);
302 
303  // If product has a new code that is same than origin, we clean origin code to avoid duplicate key from database unique keys.
304  if ($productOrigin->barcode == $object->barcode) {
305  dol_syslog("We clean customer and supplier code so we will be able to make the update of target");
306  $productOrigin->barcode = '';
307  //$productOrigin->update($productOrigin->id, $user, 0, 'merge');
308  }
309 
310  // Update
311  $result = $object->update($object->id, $user, 0, 'merge');
312  if ($result <= 0) {
313  setEventMessages($object->error, $object->errors, 'errors');
314  $error++;
315  }
316 
317  // Move links
318  if (!$error) {
319  // TODO add this functionality into the api_products.class.php
320  // TODO Mutualise the list into object product.class.php
321  $objects = array(
322  'ActionComm' => '/comm/action/class/actioncomm.class.php',
323  'Bom' => '/bom/class/bom.class.php',
324  // do not use Categorie, it cause foreign key error, merge is done before
325  //'Categorie' => '/categories/class/categorie.class.php',
326  'Commande' => '/commande/class/commande.class.php',
327  'CommandeFournisseur' => '/fourn/class/fournisseur.commande.class.php',
328  'Contrat' => '/contrat/class/contrat.class.php',
329  'Delivery' => '/delivery/class/delivery.class.php',
330  'Facture' => '/compta/facture/class/facture.class.php',
331  'FactureFournisseur' => '/fourn/class/fournisseur.facture.class.php',
332  'FactureRec' => '/compta/facture/class/facture-rec.class.php',
333  'FichinterRec' => '/fichinter/class/fichinterrec.class.php',
334  'ProductFournisseur' => '/fourn/class/fournisseur.product.class.php',
335  'Propal' => '/comm/propal/class/propal.class.php',
336  'Reception' => '/reception/class/reception.class.php',
337  'SupplierProposal' => '/supplier_proposal/class/supplier_proposal.class.php',
338  );
339 
340  //First, all core objects must update their tables
341  foreach ($objects as $object_name => $object_file) {
342  require_once DOL_DOCUMENT_ROOT.$object_file;
343 
344  if (!$error && !$object_name::replaceProduct($db, $productOrigin->id, $object->id)) {
345  $error++;
346  setEventMessages($db->lasterror(), null, 'errors');
347  break;
348  }
349  }
350  }
351 
352  // External modules should update their ones too
353  if (!$error) {
354  $reshook = $hookmanager->executeHooks(
355  'replaceProduct',
356  array(
357  'soc_origin' => $productOrigin->id,
358  'soc_dest' => $object->id,
359  ),
360  $object,
361  $action
362  );
363 
364  if ($reshook < 0) {
365  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
366  $error++;
367  }
368  }
369 
370 
371  if (!$error) {
372  $object->context = array(
373  'merge' => 1,
374  'mergefromid' => $productOrigin->id,
375  );
376 
377  // Call trigger
378  $result = $object->call_trigger('PRODUCT_MODIFY', $user);
379  if ($result < 0) {
380  setEventMessages($object->error, $object->errors, 'errors');
381  $error++;
382  }
383  // End call triggers
384  }
385 
386  if (!$error) {
387  // We finally remove the old product
388  // TODO merge attached files from old product into new one before delete
389  if ($productOrigin->delete($user) < 1) {
390  $error++;
391  }
392  }
393 
394  if (!$error) {
395  setEventMessages($langs->trans('ProductsMergeSuccess'), null, 'mesgs');
396  $db->commit();
397  } else {
398  $langs->load("errors");
399  setEventMessages($langs->trans('ErrorsProductsMerge'), null, 'errors');
400  $db->rollback();
401  }
402  }
403  }
404  }
405 
406  // Type
407  if ($action == 'setfk_product_type' && $usercancreate) {
408  $result = $object->setValueFrom('fk_product_type', GETPOST('fk_product_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
409  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
410  exit;
411  }
412 
413  // Actions to build doc
414  $upload_dir = $conf->product->dir_output;
415  $permissiontoadd = $usercancreate;
416  include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
417 
418  include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
419 
420  // Barcode type
421  if ($action == 'setfk_barcode_type' && $createbarcode) {
422  $result = $object->setValueFrom('fk_barcode_type', GETPOST('fk_barcode_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
423  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
424  exit;
425  }
426 
427  // Barcode value
428  if ($action == 'setbarcode' && $createbarcode) {
429  $result = $object->check_barcode(GETPOST('barcode'), GETPOST('barcode_type_code'));
430 
431  if ($result >= 0) {
432  $result = $object->setValueFrom('barcode', GETPOST('barcode'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
433  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
434  exit;
435  } else {
436  $langs->load("errors");
437  if ($result == -1) {
438  $errors[] = 'ErrorBadBarCodeSyntax';
439  } elseif ($result == -2) {
440  $errors[] = 'ErrorBarCodeRequired';
441  } elseif ($result == -3) {
442  $errors[] = 'ErrorBarCodeAlreadyUsed';
443  } else {
444  $errors[] = 'FailedToValidateBarCode';
445  }
446 
447  $error++;
448  setEventMessages($errors, null, 'errors');
449  }
450  }
451 
452  // Quick edit for extrafields
453  if ($action == 'update_extras') {
454  $object->oldcopy = dol_clone($object);
455 
456  // Fill array 'array_options' with data from update form
457  $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
458  if ($ret < 0) {
459  $error++;
460  }
461 
462  if (!$error) {
463  // Actions on extra fields
464  $result = $object->insertExtraFields('PRODUCT_MODIFY');
465  if ($result < 0) {
466  setEventMessages($object->error, $object->errors, 'errors');
467  $error++;
468  }
469  }
470 
471  if ($error) {
472  $action = 'edit_extras';
473  }
474  }
475 
476  // Add a product or service
477  if ($action == 'add' && $usercancreate) {
478  $error = 0;
479 
480  if (!GETPOST('label', $label_security_check)) {
481  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Label')), null, 'errors');
482  $action = "create";
483  $error++;
484  }
485  if (empty($ref)) {
486  if (empty($conf->global->PRODUCT_GENERATE_REF_AFTER_FORM)) {
487  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Ref')), null, 'errors');
488  $action = "create";
489  $error++;
490  }
491  }
492  if (!empty($duration_value) && empty($duration_unit)) {
493  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Unit')), null, 'errors');
494  $action = "create";
495  $error++;
496  }
497 
498  if (!$error) {
499  $units = GETPOST('units', 'int');
500 
501  $object->entity = $conf->entity;
502  $object->ref = $ref;
503  $object->label = GETPOST('label', $label_security_check);
504  $object->price_base_type = GETPOST('price_base_type', 'aZ09');
505  $object->mandatory_period = !empty(GETPOST("mandatoryperiod", 'alpha')) ? 1 : 0;
506  if ($object->price_base_type == 'TTC') {
507  $object->price_ttc = GETPOST('price');
508  } else {
509  $object->price = GETPOST('price');
510  }
511  if ($object->price_base_type == 'TTC') {
512  $object->price_min_ttc = GETPOST('price_min');
513  } else {
514  $object->price_min = GETPOST('price_min');
515  }
516 
517  $tva_tx_txt = GETPOST('tva_tx', 'alpha'); // tva_tx can be '8.5' or '8.5*' or '8.5 (XXX)' or '8.5* (XXX)'
518 
519  // We must define tva_tx, npr and local taxes
520  $vatratecode = '';
521  $tva_tx = preg_replace('/[^0-9\.].*$/', '', $tva_tx_txt); // keep remove all after the numbers and dot
522  $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
523  $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0';
524  // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes
525  $reg = array();
526  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
527  // We look into database using code (we can't use get_localtax() because it depends on buyer that is not known). Same in update price.
528  $vatratecode = $reg[1];
529  // Get record from code
530  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
531  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
532  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
533  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
534  $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
535  $resql = $db->query($sql);
536  if ($resql) {
537  $obj = $db->fetch_object($resql);
538  $npr = $obj->recuperableonly;
539  $localtax1 = $obj->localtax1;
540  $localtax2 = $obj->localtax2;
541  $localtax1_type = $obj->localtax1_type;
542  $localtax2_type = $obj->localtax2_type;
543  }
544  }
545 
546  $object->default_vat_code = $vatratecode;
547  $object->tva_tx = $tva_tx;
548  $object->tva_npr = $npr;
549  $object->localtax1_tx = $localtax1;
550  $object->localtax2_tx = $localtax2;
551  $object->localtax1_type = $localtax1_type;
552  $object->localtax2_type = $localtax2_type;
553 
554  $object->type = $type;
555  $object->status = GETPOST('statut');
556  $object->status_buy = GETPOST('statut_buy');
557  $object->status_batch = GETPOST('status_batch');
558  $object->batch_mask = GETPOST('batch_mask');
559 
560  $object->barcode_type = GETPOST('fk_barcode_type');
561  $object->barcode = GETPOST('barcode');
562  // Set barcode_type_xxx from barcode_type id
563  $stdobject = new GenericObject($db);
564  $stdobject->element = 'product';
565  $stdobject->barcode_type = GETPOST('fk_barcode_type');
566  $result = $stdobject->fetch_barcode();
567  if ($result < 0) {
568  $error++;
569  $mesg = 'Failed to get bar code type information ';
570  setEventMessages($mesg.$stdobject->error, $stdobject->errors, 'errors');
571  }
572  $object->barcode_type_code = $stdobject->barcode_type_code;
573  $object->barcode_type_coder = $stdobject->barcode_type_coder;
574  $object->barcode_type_label = $stdobject->barcode_type_label;
575 
576  $object->description = dol_htmlcleanlastbr(GETPOST('desc', 'restricthtml'));
577  $object->url = GETPOST('url');
578  $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private', 'restricthtml'));
579  $object->note = $object->note_private; // deprecated
580  $object->customcode = GETPOST('customcode', 'alphanohtml');
581  $object->country_id = GETPOST('country_id', 'int');
582  $object->state_id = GETPOST('state_id', 'int');
583  $object->lifetime = GETPOST('lifetime', 'int');
584  $object->qc_frequency = GETPOST('qc_frequency', 'int');
585  $object->duration_value = $duration_value;
586  $object->duration_unit = $duration_unit;
587  $object->fk_default_warehouse = GETPOST('fk_default_warehouse');
588  $object->fk_default_workstation = GETPOST('fk_default_workstation');
589  $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte') ?GETPOST('seuil_stock_alerte') : 0;
590  $object->desiredstock = GETPOST('desiredstock') ?GETPOST('desiredstock') : 0;
591  $object->canvas = GETPOST('canvas');
592  $object->net_measure = GETPOST('net_measure');
593  $object->net_measure_units = GETPOST('net_measure_units'); // This is not the fk_unit but the power of unit
594  $object->weight = GETPOST('weight');
595  $object->weight_units = GETPOST('weight_units'); // This is not the fk_unit but the power of unit
596  $object->length = GETPOST('size');
597  $object->length_units = GETPOST('size_units'); // This is not the fk_unit but the power of unit
598  $object->width = GETPOST('sizewidth');
599  $object->height = GETPOST('sizeheight');
600  $object->surface = GETPOST('surface');
601  $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit
602  $object->volume = GETPOST('volume');
603  $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit
604  $finished = GETPOST('finished', 'int');
605  if ($finished >= 0) {
606  $object->finished = $finished;
607  } else {
608  $object->finished = null;
609  }
610 
611  $units = GETPOST('units', 'int');
612  if ($units > 0) {
613  $object->fk_unit = $units;
614  } else {
615  $object->fk_unit = null;
616  }
617 
618  $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
619  $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
620  $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
621  $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
622  $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
623  $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
624 
625  if (empty($accountancy_code_sell) || $accountancy_code_sell == '-1') {
626  $object->accountancy_code_sell = '';
627  } else {
628  $object->accountancy_code_sell = $accountancy_code_sell;
629  }
630  if (empty($accountancy_code_sell_intra) || $accountancy_code_sell_intra == '-1') {
631  $object->accountancy_code_sell_intra = '';
632  } else {
633  $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
634  }
635  if (empty($accountancy_code_sell_export) || $accountancy_code_sell_export == '-1') {
636  $object->accountancy_code_sell_export = '';
637  } else {
638  $object->accountancy_code_sell_export = $accountancy_code_sell_export;
639  }
640  if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') {
641  $object->accountancy_code_buy = '';
642  } else {
643  $object->accountancy_code_buy = $accountancy_code_buy;
644  }
645  if (empty($accountancy_code_buy_intra) || $accountancy_code_buy_intra == '-1') {
646  $object->accountancy_code_buy_intra = '';
647  } else {
648  $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
649  }
650  if (empty($accountancy_code_buy_export) || $accountancy_code_buy_export == '-1') {
651  $object->accountancy_code_buy_export = '';
652  } else {
653  $object->accountancy_code_buy_export = $accountancy_code_buy_export;
654  }
655 
656  // MultiPrix
657  if (!empty($conf->global->PRODUIT_MULTIPRICES)) {
658  for ($i = 2; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
659  if (GETPOSTISSET("price_".$i)) {
660  $object->multiprices["$i"] = price2num(GETPOST("price_".$i), 'MU');
661  $object->multiprices_base_type["$i"] = GETPOST("multiprices_base_type_".$i);
662  } else {
663  $object->multiprices["$i"] = "";
664  }
665  }
666  }
667 
668  // Fill array 'array_options' with data from add form
669  $ret = $extrafields->setOptionalsFromPost(null, $object);
670  if ($ret < 0) {
671  $error++;
672  }
673 
674  if (!$ref && !empty($conf->global->PRODUCT_GENERATE_REF_AFTER_FORM)) {
675  // Generate ref...
676  $ref = $modCodeProduct->getNextValue($object, $type);
677  }
678 
679  if (!$error) {
680  $id = $object->create($user);
681  }
682 
683  if ($id > 0) {
684  // Category association
685  $categories = GETPOST('categories', 'array');
686  $object->setCategories($categories);
687 
688  if (!empty($backtopage)) {
689  $backtopage = preg_replace('/__ID__/', $object->id, $backtopage); // New method to autoselect project after a New on another form object creation
690  if (preg_match('/\?/', $backtopage)) {
691  $backtopage .= '&socid='.$object->id; // Old method
692  }
693  header("Location: ".$backtopage);
694  exit;
695  } else {
696  header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
697  exit;
698  }
699  } else {
700  if (count($object->errors)) {
701  setEventMessages($object->error, $object->errors, 'errors');
702  } else {
703  if ($object->error == 'ErrorProductAlreadyExists') {
704  // allow to hook on ErrorProductAlreadyExists in any module
705  $reshook = $hookmanager->executeHooks('onProductAlreadyExists', $parameters, $object, $action);
706  if ($reshook < 0) {
707  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
708  }
709  if ($object->error) {
710  // check again to prevent translation issue,
711  // as error may have been cleared in hook function
712  setEventMessages($langs->trans($object->error), null, 'errors');
713  }
714  } else {
715  setEventMessages($langs->trans($object->error), null, 'errors');
716  }
717  }
718  $action = "create";
719  }
720  }
721  }
722 
723  // Update a product or service
724  if ($action == 'update' && $usercancreate) {
725  if (GETPOST('cancel', 'alpha')) {
726  $action = '';
727  } else {
728  if ($object->id > 0) {
729  $object->oldcopy = clone $object;
730 
731  if (empty($conf->global->PRODUCT_GENERATE_REF_AFTER_FORM)) {
732  $object->ref = $ref;
733  }
734  $object->label = GETPOST('label', $label_security_check);
735 
736  $desc = dol_htmlcleanlastbr(preg_replace('/&nbsp;$/', '', GETPOST('desc', 'restricthtml')));
737  $object->description = $desc;
738 
739  $object->url = GETPOST('url');
740  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
741  $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private', 'restricthtml'));
742  $object->note = $object->note_private;
743  }
744  $object->customcode = GETPOST('customcode', 'alpha');
745  $object->country_id = GETPOST('country_id', 'int');
746  $object->state_id = GETPOST('state_id', 'int');
747  $object->lifetime = GETPOST('lifetime', 'int');
748  $object->qc_frequency = GETPOST('qc_frequency', 'int');
749  $object->status = GETPOST('statut', 'int');
750  $object->status_buy = GETPOST('statut_buy', 'int');
751  $object->status_batch = GETPOST('status_batch', 'aZ09');
752  $object->batch_mask = GETPOST('batch_mask', 'alpha');
753  $object->fk_default_warehouse = GETPOST('fk_default_warehouse');
754  $object->fk_default_workstation = GETPOST('fk_default_workstation');
755  // removed from update view so GETPOST always empty
756  /*
757  $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte');
758  $object->desiredstock = GETPOST('desiredstock');
759  */
760  $object->duration_value = GETPOST('duration_value', 'int');
761  $object->duration_unit = GETPOST('duration_unit', 'alpha');
762 
763  $object->canvas = GETPOST('canvas');
764  $object->net_measure = GETPOST('net_measure');
765  $object->net_measure_units = GETPOST('net_measure_units'); // This is not the fk_unit but the power of unit
766  $object->weight = GETPOST('weight');
767  $object->weight_units = GETPOST('weight_units'); // This is not the fk_unit but the power of unit
768  $object->length = GETPOST('size');
769  $object->length_units = GETPOST('size_units'); // This is not the fk_unit but the power of unit
770  $object->width = GETPOST('sizewidth');
771  $object->height = GETPOST('sizeheight');
772 
773  $object->surface = GETPOST('surface');
774  $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit
775  $object->volume = GETPOST('volume');
776  $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit
777 
778  $finished = GETPOST('finished', 'int');
779  if ($finished >= 0) {
780  $object->finished = $finished;
781  } else {
782  $object->finished = null;
783  }
784 
785  $fk_default_bom = GETPOST('fk_default_bom', 'int');
786  if ($fk_default_bom >= 0) {
787  $object->fk_default_bom = $fk_default_bom;
788  } else {
789  $object->fk_default_bom = null;
790  }
791 
792  $units = GETPOST('units', 'int');
793  if ($units > 0) {
794  $object->fk_unit = $units;
795  } else {
796  $object->fk_unit = null;
797  }
798 
799  $object->barcode_type = GETPOST('fk_barcode_type');
800  $object->barcode = GETPOST('barcode');
801  // Set barcode_type_xxx from barcode_type id
802  $stdobject = new GenericObject($db);
803  $stdobject->element = 'product';
804  $stdobject->barcode_type = GETPOST('fk_barcode_type');
805  $result = $stdobject->fetch_barcode();
806  if ($result < 0) {
807  $error++;
808  $mesg = 'Failed to get bar code type information ';
809  setEventMessages($mesg.$stdobject->error, $stdobject->errors, 'errors');
810  }
811  $object->barcode_type_code = $stdobject->barcode_type_code;
812  $object->barcode_type_coder = $stdobject->barcode_type_coder;
813  $object->barcode_type_label = $stdobject->barcode_type_label;
814 
815  $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
816  $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
817  $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
818  $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
819  $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
820  $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
821  $checkmandatory = GETPOST('mandatoryperiod', 'alpha');
822  if (empty($accountancy_code_sell) || $accountancy_code_sell == '-1') {
823  $object->accountancy_code_sell = '';
824  } else {
825  $object->accountancy_code_sell = $accountancy_code_sell;
826  }
827  if (empty($accountancy_code_sell_intra) || $accountancy_code_sell_intra == '-1') {
828  $object->accountancy_code_sell_intra = '';
829  } else {
830  $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
831  }
832  if (empty($accountancy_code_sell_export) || $accountancy_code_sell_export == '-1') {
833  $object->accountancy_code_sell_export = '';
834  } else {
835  $object->accountancy_code_sell_export = $accountancy_code_sell_export;
836  }
837  if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') {
838  $object->accountancy_code_buy = '';
839  } else {
840  $object->accountancy_code_buy = $accountancy_code_buy;
841  }
842  if (empty($accountancy_code_buy_intra) || $accountancy_code_buy_intra == '-1') {
843  $object->accountancy_code_buy_intra = '';
844  } else {
845  $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
846  }
847  if (empty($accountancy_code_buy_export) || $accountancy_code_buy_export == '-1') {
848  $object->accountancy_code_buy_export = '';
849  } else {
850  $object->accountancy_code_buy_export = $accountancy_code_buy_export;
851  }
852  if ($object->isService()) {
853  $object->mandatory_period = (!empty($checkmandatory)) ? 1 : 0 ;
854  }
855 
856 
857 
858  // Fill array 'array_options' with data from add form
859  $ret = $extrafields->setOptionalsFromPost(null, $object, '@GETPOSTISSET');
860  if ($ret < 0) {
861  $error++;
862  }
863 
864  if (!$error && $object->check()) {
865  if ($object->update($object->id, $user) > 0) {
866  // Category association
867  $categories = GETPOST('categories', 'array');
868  $object->setCategories($categories);
869 
870  $action = 'view';
871  } else {
872  if (count($object->errors)) {
873  setEventMessages($object->error, $object->errors, 'errors');
874  } else {
875  setEventMessages($langs->trans($object->error), null, 'errors');
876  }
877  $action = 'edit';
878  }
879  } else {
880  if (count($object->errors)) {
881  setEventMessages($object->error, $object->errors, 'errors');
882  } else {
883  setEventMessages($langs->trans("ErrorProductBadRefOrLabel"), null, 'errors');
884  }
885  $action = 'edit';
886  }
887  }
888  }
889  }
890 
891  // Action clone object
892  if ($action == 'confirm_clone' && $confirm != 'yes') {
893  $action = '';
894  }
895  if ($action == 'confirm_clone' && $confirm == 'yes' && $usercancreate) {
896  if (!GETPOST('clone_content') && !GETPOST('clone_prices')) {
897  setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors');
898  } else {
899  $db->begin();
900 
901  $originalId = $id;
902  if ($object->id > 0) {
903  $object->ref = GETPOST('clone_ref', 'alphanohtml');
904  $object->status = 0;
905  $object->status_buy = 0;
906  $object->id = null;
907  $object->barcode = -1;
908 
909  if ($object->check()) {
910  $object->context['createfromclone'] = 'createfromclone';
911  $id = $object->create($user);
912  if ($id > 0) {
913  if (GETPOST('clone_composition')) {
914  $result = $object->clone_associations($originalId, $id);
915 
916  if ($result < 1) {
917  $db->rollback();
918  setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
919  header("Location: ".$_SERVER["PHP_SELF"]."?id=".$originalId);
920  exit;
921  }
922  }
923 
924  if (GETPOST('clone_categories')) {
925  $result = $object->cloneCategories($originalId, $id);
926 
927  if ($result < 1) {
928  $db->rollback();
929  setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
930  header("Location: ".$_SERVER["PHP_SELF"]."?id=".$originalId);
931  exit;
932  }
933  }
934 
935  if (GETPOST('clone_prices')) {
936  $result = $object->clone_price($originalId, $id);
937 
938  if ($result < 1) {
939  $db->rollback();
940  setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
941  header('Location: '.$_SERVER['PHP_SELF'].'?id='.$originalId);
942  exit();
943  }
944  }
945 
946  // $object->clone_fournisseurs($originalId, $id);
947 
948  $db->commit();
949  $db->close();
950 
951  header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
952  exit;
953  } else {
954  $id = $originalId;
955 
956  if ($object->error == 'ErrorProductAlreadyExists') {
957  $db->rollback();
958 
959  $refalreadyexists++;
960  $action = "";
961 
962  $mesg = $langs->trans("ErrorProductAlreadyExists", $object->ref);
963  $mesg .= ' <a href="'.$_SERVER["PHP_SELF"].'?ref='.$object->ref.'">'.$langs->trans("ShowCardHere").'</a>.';
964  setEventMessages($mesg, null, 'errors');
965  $object->fetch($id);
966  } else {
967  $db->rollback();
968  if (count($object->errors)) {
969  setEventMessages($object->error, $object->errors, 'errors');
970  dol_print_error($db, $object->errors);
971  } else {
972  setEventMessages($langs->trans($object->error), null, 'errors');
973  dol_print_error($db, $object->error);
974  }
975  }
976  }
977 
978  unset($object->context['createfromclone']);
979  }
980  } else {
981  $db->rollback();
982  dol_print_error($db, $object->error);
983  }
984  }
985  }
986 
987  // Delete a product
988  if ($action == 'confirm_delete' && $confirm != 'yes') {
989  $action = '';
990  }
991  if ($action == 'confirm_delete' && $confirm == 'yes' && $usercandelete) {
992  $result = $object->delete($user);
993 
994  if ($result > 0) {
995  header('Location: '.DOL_URL_ROOT.'/product/list.php?type='.$object->type.'&delprod='.urlencode($object->ref));
996  exit;
997  } else {
998  setEventMessages($langs->trans($object->error), null, 'errors');
999  $reload = 0;
1000  $action = '';
1001  }
1002  }
1003 
1004 
1005  // Add product into object
1006  if ($object->id > 0 && $action == 'addin') {
1007  $thirpdartyid = 0;
1008  if (GETPOST('propalid') > 0) {
1009  $propal = new Propal($db);
1010  $result = $propal->fetch(GETPOST('propalid'));
1011  if ($result <= 0) {
1012  dol_print_error($db, $propal->error);
1013  exit;
1014  }
1015  $thirpdartyid = $propal->socid;
1016  } elseif (GETPOST('commandeid') > 0) {
1017  $commande = new Commande($db);
1018  $result = $commande->fetch(GETPOST('commandeid'));
1019  if ($result <= 0) {
1020  dol_print_error($db, $commande->error);
1021  exit;
1022  }
1023  $thirpdartyid = $commande->socid;
1024  } elseif (GETPOST('factureid') > 0) {
1025  $facture = new Facture($db);
1026  $result = $facture->fetch(GETPOST('factureid'));
1027  if ($result <= 0) {
1028  dol_print_error($db, $facture->error);
1029  exit;
1030  }
1031  $thirpdartyid = $facture->socid;
1032  }
1033 
1034  if ($thirpdartyid > 0) {
1035  $soc = new Societe($db);
1036  $result = $soc->fetch($thirpdartyid);
1037  if ($result <= 0) {
1038  dol_print_error($db, $soc->error);
1039  exit;
1040  }
1041 
1042  $desc = $object->description;
1043 
1044  $tva_tx = get_default_tva($mysoc, $soc, $object->id);
1045  $tva_npr = get_default_npr($mysoc, $soc, $object->id);
1046  if (empty($tva_tx)) {
1047  $tva_npr = 0;
1048  }
1049  $localtax1_tx = get_localtax($tva_tx, 1, $soc, $mysoc, $tva_npr);
1050  $localtax2_tx = get_localtax($tva_tx, 2, $soc, $mysoc, $tva_npr);
1051 
1052  $pu_ht = $object->price;
1053  $pu_ttc = $object->price_ttc;
1054  $price_base_type = $object->price_base_type;
1055 
1056  // If multiprice
1057  if ($conf->global->PRODUIT_MULTIPRICES && $soc->price_level) {
1058  $pu_ht = $object->multiprices[$soc->price_level];
1059  $pu_ttc = $object->multiprices_ttc[$soc->price_level];
1060  $price_base_type = $object->multiprices_base_type[$soc->price_level];
1061  } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
1062  require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
1063 
1064  $prodcustprice = new Productcustomerprice($db);
1065 
1066  $filter = array('t.fk_product' => $object->id, 't.fk_soc' => $soc->id);
1067 
1068  $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
1069  if ($result) {
1070  if (count($prodcustprice->lines) > 0) {
1071  $pu_ht = price($prodcustprice->lines [0]->price);
1072  $pu_ttc = price($prodcustprice->lines [0]->price_ttc);
1073  $price_base_type = $prodcustprice->lines [0]->price_base_type;
1074  $tva_tx = $prodcustprice->lines [0]->tva_tx;
1075  }
1076  }
1077  }
1078 
1079  $tmpvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
1080  $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $prod->tva_tx));
1081 
1082  // On reevalue prix selon taux tva car taux tva transaction peut etre different
1083  // de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur).
1084  if ($tmpvat != $tmpprodvat) {
1085  if ($price_base_type != 'HT') {
1086  $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
1087  } else {
1088  $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
1089  }
1090  }
1091 
1092  if (GETPOST('propalid') > 0) {
1093  // Define cost price for margin calculation
1094  $buyprice = 0;
1095  if (($result = $propal->defineBuyPrice($pu_ht, price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
1096  dol_syslog($langs->trans('FailedToGetCostPrice'));
1097  setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
1098  } else {
1099  $buyprice = $result;
1100  }
1101 
1102  $result = $propal->addline(
1103  $desc,
1104  $pu_ht,
1105  price2num(GETPOST('qty'), 'MS'),
1106  $tva_tx,
1107  $localtax1_tx, // localtax1
1108  $localtax2_tx, // localtax2
1109  $object->id,
1110  price2num(GETPOST('remise_percent'), '', 2),
1111  $price_base_type,
1112  $pu_ttc,
1113  0,
1114  0,
1115  -1,
1116  0,
1117  0,
1118  0,
1119  $buyprice,
1120  '',
1121  '',
1122  '',
1123  0,
1124  $object->fk_unit
1125  );
1126  if ($result > 0) {
1127  header("Location: ".DOL_URL_ROOT."/comm/propal/card.php?id=".$propal->id);
1128  return;
1129  }
1130 
1131  setEventMessages($langs->trans("ErrorUnknown").": $result", null, 'errors');
1132  } elseif (GETPOST('commandeid') > 0) {
1133  // Define cost price for margin calculation
1134  $buyprice = 0;
1135  if (($result = $commande->defineBuyPrice($pu_ht, price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
1136  dol_syslog($langs->trans('FailedToGetCostPrice'));
1137  setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
1138  } else {
1139  $buyprice = $result;
1140  }
1141 
1142  $result = $commande->addline(
1143  $desc,
1144  $pu_ht,
1145  price2num(GETPOST('qty'), 'MS'),
1146  $tva_tx,
1147  $localtax1_tx, // localtax1
1148  $localtax2_tx, // localtax2
1149  $object->id,
1150  price2num(GETPOST('remise_percent'), '', 2),
1151  '',
1152  '',
1153  $price_base_type,
1154  $pu_ttc,
1155  '',
1156  '',
1157  0,
1158  -1,
1159  0,
1160  0,
1161  null,
1162  $buyprice,
1163  '',
1164  0,
1165  $object->fk_unit
1166  );
1167 
1168  if ($result > 0) {
1169  header("Location: ".DOL_URL_ROOT."/commande/card.php?id=".urlencode($commande->id));
1170  exit;
1171  }
1172  } elseif (GETPOST('factureid') > 0) {
1173  // Define cost price for margin calculation
1174  $buyprice = 0;
1175  if (($result = $facture->defineBuyPrice($pu_ht, price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
1176  dol_syslog($langs->trans('FailedToGetCostPrice'));
1177  setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
1178  } else {
1179  $buyprice = $result;
1180  }
1181 
1182  $result = $facture->addline(
1183  $desc,
1184  $pu_ht,
1185  price2num(GETPOST('qty'), 'MS'),
1186  $tva_tx,
1187  $localtax1_tx,
1188  $localtax2_tx,
1189  $object->id,
1190  price2num(GETPOST('remise_percent'), '', 2),
1191  '',
1192  '',
1193  '',
1194  '',
1195  '',
1196  $price_base_type,
1197  $pu_ttc,
1199  -1,
1200  0,
1201  '',
1202  0,
1203  0,
1204  null,
1205  $buyprice,
1206  '',
1207  0,
1208  100,
1209  '',
1210  $object->fk_unit
1211  );
1212 
1213  if ($result > 0) {
1214  header("Location: ".DOL_URL_ROOT."/compta/facture/card.php?facid=".$facture->id);
1215  exit;
1216  }
1217  }
1218  } else {
1219  $action = "";
1220  setEventMessages($langs->trans("WarningSelectOneDocument"), null, 'warnings');
1221  }
1222  }
1223 }
1224 
1225 
1226 
1227 /*
1228  * View
1229  */
1230 
1231 $form = new Form($db);
1232 $formfile = new FormFile($db);
1233 $formproduct = new FormProduct($db);
1234 $formcompany = new FormCompany($db);
1235 if (isModEnabled('accounting')) {
1236  $formaccounting = new FormAccounting($db);
1237 }
1238 
1239 
1240 $title = $langs->trans('ProductServiceCard');
1241 
1242 $help_url = '';
1243 $shortlabel = dol_trunc($object->label, 16);
1244 if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT)) {
1245  if ($action == 'create') {
1246  $title = $langs->trans("NewProduct");
1247  } else {
1248  $title = $langs->trans('Product')." ".$shortlabel." - ".$langs->trans('Card');
1249  $help_url = 'EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos|DE:Modul_Produkte';
1250  }
1251 }
1252 if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE)) {
1253  if ($action == 'create') {
1254  $title = $langs->trans("NewService");
1255  } else {
1256  $title = $langs->trans('Service')." ".$shortlabel." - ".$langs->trans('Card');
1257  $help_url = 'EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios|DE:Modul_Leistungen';
1258  }
1259 }
1260 
1261 llxHeader('', $title, $help_url);
1262 
1263 // Load object modBarCodeProduct
1264 $res = 0;
1265 if (isModEnabled('barcode') && !empty($conf->global->BARCODE_PRODUCT_ADDON_NUM)) {
1266  $module = strtolower($conf->global->BARCODE_PRODUCT_ADDON_NUM);
1267  $dirbarcode = array_merge(array('/core/modules/barcode/'), $conf->modules_parts['barcode']);
1268  foreach ($dirbarcode as $dirroot) {
1269  $res = dol_include_once($dirroot.$module.'.php');
1270  if ($res) {
1271  break;
1272  }
1273  }
1274  if ($res > 0) {
1275  $modBarCodeProduct = new $module();
1276  }
1277 }
1278 
1279 if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
1280  // -----------------------------------------
1281  // When used with CANVAS
1282  // -----------------------------------------
1283  if (empty($object->error) && $id) {
1284  $result = $object->fetch($id);
1285  if ($result <= 0) {
1286  dol_print_error('', $object->error);
1287  }
1288  }
1289  $objcanvas->assign_values($action, $object->id, $object->ref); // Set value for templates
1290  $objcanvas->display_canvas($action); // Show template
1291 } else {
1292  // -----------------------------------------
1293  // When used in standard mode
1294  // -----------------------------------------
1295  if ($action == 'create' && $usercancreate) {
1296  //WYSIWYG Editor
1297  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1298 
1299  if (!empty($conf->use_javascript_ajax)) {
1300  print '<script type="text/javascript">';
1301  print '$(document).ready(function () {
1302  $("#selectcountry_id").change(function() {
1303  document.formprod.action.value="create";
1304  document.formprod.submit();
1305  });
1306  });';
1307  print '</script>'."\n";
1308  }
1309 
1310  // Load object modCodeProduct
1311  $module = (!empty($conf->global->PRODUCT_CODEPRODUCT_ADDON) ? $conf->global->PRODUCT_CODEPRODUCT_ADDON : 'mod_codeproduct_leopard');
1312  if (substr($module, 0, 16) == 'mod_codeproduct_' && substr($module, -3) == 'php') {
1313  $module = substr($module, 0, dol_strlen($module) - 4);
1314  }
1315  $result = dol_include_once('/core/modules/product/'.$module.'.php');
1316  if ($result > 0) {
1317  $modCodeProduct = new $module();
1318  }
1319 
1320  dol_set_focus('input[name="ref"]');
1321 
1322  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formprod">';
1323  print '<input type="hidden" name="token" value="'.newToken().'">';
1324  print '<input type="hidden" name="action" value="add">';
1325  print '<input type="hidden" name="type" value="'.$type.'">'."\n";
1326  if (!empty($modCodeProduct->code_auto)) {
1327  print '<input type="hidden" name="code_auto" value="1">';
1328  }
1329  if (!empty($modBarCodeProduct->code_auto)) {
1330  print '<input type="hidden" name="barcode_auto" value="1">';
1331  }
1332  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
1333 
1334  if ($type == 1) {
1335  $picto = 'service';
1336  $title = $langs->trans("NewService");
1337  } else {
1338  $picto = 'product';
1339  $title = $langs->trans("NewProduct");
1340  }
1341  $linkback = "";
1342  print load_fiche_titre($title, $linkback, $picto);
1343 
1344  // We set country_id, country_code and country for the selected country
1345  $object->country_id = GETPOSTISSET('country_id') ? GETPOST('country_id', 'int') : null;
1346  if ($object->country_id > 0) {
1347  $tmparray = getCountry($object->country_id, 'all');
1348  $object->country_code = $tmparray['code'];
1349  $object->country = $tmparray['label'];
1350  }
1351 
1352  print dol_get_fiche_head('');
1353 
1354  print '<table class="border centpercent">';
1355 
1356  if (empty($conf->global->PRODUCT_GENERATE_REF_AFTER_FORM)) {
1357  print '<tr>';
1358  $tmpcode = '';
1359  if (!empty($modCodeProduct->code_auto)) {
1360  $tmpcode = $modCodeProduct->getNextValue($object, $type);
1361  }
1362  print '<td class="titlefieldcreate fieldrequired">'.$langs->trans("Ref").'</td><td><input id="ref" name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag(GETPOSTISSET('ref') ? GETPOST('ref', 'alphanohtml') : $tmpcode).'">';
1363  if ($refalreadyexists) {
1364  print $langs->trans("RefAlreadyExists");
1365  }
1366  print '</td></tr>';
1367  }
1368 
1369  // Label
1370  print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td><input name="label" class="minwidth300 maxwidth400onsmartphone" maxlength="255" value="'.dol_escape_htmltag(GETPOST('label', $label_security_check)).'"></td></tr>';
1371 
1372  // On sell
1373  print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td>';
1374  $statutarray = array('1' => $langs->trans("OnSell"), '0' => $langs->trans("NotOnSell"));
1375  print $form->selectarray('statut', $statutarray, GETPOST('statut'));
1376  print '</td></tr>';
1377 
1378  // To buy
1379  print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td>';
1380  $statutarray = array('1' => $langs->trans("ProductStatusOnBuy"), '0' => $langs->trans("ProductStatusNotOnBuy"));
1381  print $form->selectarray('statut_buy', $statutarray, GETPOST('statut_buy'));
1382  print '</td></tr>';
1383 
1384  // Batch number management
1385  if (isModEnabled('productbatch')) {
1386  print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
1387  $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial"));
1388  print $form->selectarray('status_batch', $statutarray, GETPOST('status_batch'));
1389  print '</td></tr>';
1390  // Product specific batch number management
1391  $status_batch = GETPOST('status_batch');
1392  if ($status_batch !== '0') {
1393  $langs->load("admin");
1394  $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
1395  $tooltip .= '<br>'.$langs->trans("GenericMaskCodes2");
1396  $tooltip .= '<br>'.$langs->trans("GenericMaskCodes3");
1397  $tooltip .= '<br>'.$langs->trans("GenericMaskCodes4a", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
1398  $tooltip .= '<br>'.$langs->trans("GenericMaskCodes5");
1399  if ((!empty($conf->global->PRODUCTBATCH_LOT_USE_PRODUCT_MASKS) && $conf->global->PRODUCTBATCH_LOT_ADDON == 'mod_lot_advanced')
1400  || (!empty($conf->global->PRODUCTBATCH_SN_USE_PRODUCT_MASKS) && $conf->global->PRODUCTBATCH_SN_ADDON == 'mod_sn_advanced')) {
1401  print '<tr><td id="mask_option">'.$langs->trans("ManageLotMask").'</td>';
1402  $inherited_mask_lot = getDolGlobalString('LOT_ADVANCED_MASK');
1403  $inherited_mask_sn = getDolGlobalString('SN_ADVANCED_MASK');
1404  print '<td id="field_mask">';
1405  print $form->textwithpicto('<input type="text" class="flat minwidth175" name="batch_mask" id="batch_mask_input">', $tooltip, 1, 1);
1406  print '<script type="text/javascript">
1407  $(document).ready(function() {
1408  $("#field_mask, #mask_option").addClass("hideobject");
1409  $("#status_batch").on("change", function () {
1410  console.log("We change batch status");
1411  var optionSelected = $("option:selected", this);
1412  var valueSelected = this.value;
1413  $("#field_mask, #mask_option").addClass("hideobject");
1414  ';
1415  if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
1416  print '
1417  if (this.value == 1) {
1418  $("#field_mask, #mask_option").toggleClass("hideobject");
1419  $("#batch_mask_input").val("'.$inherited_mask_lot.'");
1420  }
1421  ';
1422  }
1423  if ($conf->global->PRODUCTBATCH_SN_USE_PRODUCT_MASKS && $conf->global->PRODUCTBATCH_SN_ADDON == 'mod_sn_advanced') {
1424  print '
1425  if (this.value == 2) {
1426  $("#field_mask, #mask_option").toggleClass("hideobject");
1427  $("#batch_mask_input").val("'.$inherited_mask_sn.'");
1428  }
1429  ';
1430  }
1431  print '
1432  })
1433  })
1434  </script>';
1435  print '</td></tr>';
1436  }
1437  }
1438  }
1439 
1440  $showbarcode = empty($conf->barcode->enabled) ? 0 : 1;
1441  if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
1442  $showbarcode = 0;
1443  }
1444 
1445  if ($showbarcode) {
1446  print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
1447  if (GETPOSTISSET('fk_barcode_type')) {
1448  $fk_barcode_type = GETPOST('fk_barcode_type')?GETPOST('fk_barcode_type'):0;
1449  } else {
1450  if (empty($fk_barcode_type) && !empty($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE)) {
1451  $fk_barcode_type = getDolGlobalInt("PRODUIT_DEFAULT_BARCODE_TYPE");
1452  } else {
1453  $fk_barcode_type=0;
1454  }
1455  }
1456  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
1457  $formbarcode = new FormBarCode($db);
1458  print $formbarcode->selectBarcodeType($fk_barcode_type, 'fk_barcode_type', 1);
1459  print '</td>';
1460  print '</tr><tr>';
1461  print '<td>'.$langs->trans("BarcodeValue").'</td><td>';
1462  $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
1463  if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
1464  $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
1465  }
1466  print '<input class="maxwidth100" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
1467  print '</td></tr>';
1468  }
1469 
1470  // Description (used in invoice, propal...)
1471  print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
1472  $doleditor = new DolEditor('desc', GETPOST('desc', 'restricthtml'), '', 160, 'dolibarr_details', '', false, true, getDolGlobalString('FCKEDITOR_ENABLE_DETAILS'), ROWS_4, '90%');
1473  $doleditor->Create();
1474  print "</td></tr>";
1475 
1476  if (empty($conf->global->PRODUCT_DISABLE_PUBLIC_URL)) {
1477  // Public URL
1478  print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
1479  print img_picto('', 'globe', 'class="pictofixedwidth"');
1480  print '<input type="text" name="url" class="quatrevingtpercent" value="'.GETPOST('url').'">';
1481  print '</td></tr>';
1482  }
1483 
1484  if ($type != 1 && isModEnabled('stock')) {
1485  // Default warehouse
1486  print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
1487  print img_picto($langs->trans("DefaultWarehouse"), 'stock', 'class="pictofixedwidth"');
1488  print $formproduct->selectWarehouses(GETPOST('fk_default_warehouse', 'int'), 'fk_default_warehouse', 'warehouseopen', 1, 0, 0, '', 0, 0, array(), 'minwidth300 widthcentpercentminusxx maxwidth500');
1489  print ' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create&token='.newToken().'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?&action=create&type='.GETPOST('type', 'int')).'">';
1490  print '<span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddWarehouse").'"></span>';
1491  print '</a>';
1492  print '</td>';
1493  print '</tr>';
1494 
1495  if (empty($conf->global->PRODUCT_DISABLE_STOCK_LEVELS)) {
1496  // Stock min level
1497  print '<tr><td>'.$form->textwithpicto($langs->trans("StockLimit"), $langs->trans("StockLimitDesc"), 1).'</td><td>';
1498  print '<input name="seuil_stock_alerte" class="maxwidth50" value="'.GETPOST('seuil_stock_alerte').'">';
1499  print '</td>';
1500  print '</tr>';
1501 
1502  // Stock desired level
1503  print '<tr><td>'.$form->textwithpicto($langs->trans("DesiredStock"), $langs->trans("DesiredStockDesc"), 1).'</td><td>';
1504  print '<input name="desiredstock" class="maxwidth50" value="'.GETPOST('desiredstock').'">';
1505  print '</td></tr>';
1506  }
1507  } else {
1508  if (empty($conf->global->PRODUCT_DISABLE_STOCK_LEVELS)) {
1509  print '<input name="seuil_stock_alerte" type="hidden" value="0">';
1510  print '<input name="desiredstock" type="hidden" value="0">';
1511  }
1512  }
1513 
1514  if ($type == 1 && $conf->workstation->enabled) {
1515  // Default workstation
1516  print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
1517  print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');
1518  print $formproduct->selectWorkstations($object->fk_default_workstation, 'fk_default_workstation', 1);
1519  print '</td></tr>';
1520  }
1521 
1522  // Duration
1523  if ($type == 1) {
1524  print '<tr><td>'.$langs->trans("Duration").'</td><td>';
1525  print '<input name="duration_value" size="4" value="'.GETPOST('duration_value', 'int').'">';
1526  print $formproduct->selectMeasuringUnits("duration_unit", "time", (GETPOSTISSET('duration_value') ? GETPOST('duration_value', 'alpha') : 'h'), 0, 1);
1527 
1528  // Mandatory period
1529  print ' &nbsp; &nbsp; &nbsp; ';
1530  print '<input type="checkbox" id="mandatoryperiod" name="mandatoryperiod"'.($object->mandatory_period == 1 ? ' checked="checked"' : '').'>';
1531  print '<label for="mandatoryperiod">';
1532  $htmltooltip = $langs->trans("mandatoryHelper");
1533  print $form->textwithpicto($langs->trans("mandatoryperiod"), $htmltooltip, 1, 0);
1534  print '</label>';
1535 
1536  print '</td></tr>';
1537  }
1538 
1539  if ($type != 1) { // Nature, Weight and volume only applies to products and not to services
1540  if (empty($conf->global->PRODUCT_DISABLE_NATURE)) {
1541  // Nature
1542  print '<tr><td>'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
1543  print $formproduct->selectProductNature('finished', $object->finished);
1544  print '</td></tr>';
1545  }
1546  }
1547 
1548  if ($type != 1) {
1549  if (empty($conf->global->PRODUCT_DISABLE_WEIGHT)) {
1550  // Brut Weight
1551  print '<tr><td>'.$langs->trans("Weight").'</td><td>';
1552  print '<input name="weight" size="4" value="'.GETPOST('weight').'">';
1553  print $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOSTISSET('weight_units') ?GETPOST('weight_units', 'alpha') : (empty($conf->global->MAIN_WEIGHT_DEFAULT_UNIT) ? 0 : $conf->global->MAIN_WEIGHT_DEFAULT_UNIT), 0, 2);
1554  print '</td></tr>';
1555  }
1556 
1557  // Brut Length
1558  if (empty($conf->global->PRODUCT_DISABLE_SIZE)) {
1559  print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
1560  print '<input name="size" class="width50" value="'.GETPOST('size').'"> x ';
1561  print '<input name="sizewidth" class="width50" value="'.GETPOST('sizewidth').'"> x ';
1562  print '<input name="sizeheight" class="width50" value="'.GETPOST('sizeheight').'">';
1563  print $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTISSET('size_units') ?GETPOST('size_units', 'alpha') : '0', 0, 2);
1564  print '</td></tr>';
1565  }
1566  if (empty($conf->global->PRODUCT_DISABLE_SURFACE)) {
1567  // Brut Surface
1568  print '<tr><td>'.$langs->trans("Surface").'</td><td>';
1569  print '<input name="surface" size="4" value="'.GETPOST('surface').'">';
1570  print $formproduct->selectMeasuringUnits("surface_units", "surface", GETPOSTISSET('surface_units') ?GETPOST('surface_units', 'alpha') : '0', 0, 2);
1571  print '</td></tr>';
1572  }
1573  if (empty($conf->global->PRODUCT_DISABLE_VOLUME)) {
1574  // Brut Volume
1575  print '<tr><td>'.$langs->trans("Volume").'</td><td>';
1576  print '<input name="volume" size="4" value="'.GETPOST('volume').'">';
1577  print $formproduct->selectMeasuringUnits("volume_units", "volume", GETPOSTISSET('volume_units') ?GETPOST('volume_units', 'alpha') : '0', 0, 2);
1578  print '</td></tr>';
1579  }
1580 
1581  if (!empty($conf->global->PRODUCT_ADD_NET_MEASURE)) {
1582  // Net Measure
1583  print '<tr><td>'.$langs->trans("NetMeasure").'</td><td>';
1584  print '<input name="net_measure" size="4" value="'.GETPOST('net_measure').'">';
1585  print $formproduct->selectMeasuringUnits("net_measure_units", '', GETPOSTISSET('net_measure_units') ?GETPOST('net_measure_units', 'alpha') : (empty($conf->global->MAIN_WEIGHT_DEFAULT_UNIT) ? 0 : $conf->global->MAIN_WEIGHT_DEFAULT_UNIT), 0, 0);
1586  print '</td></tr>';
1587  }
1588  }
1589 
1590  // Units
1591  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
1592  print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
1593  print '<td>';
1594  print $form->selectUnits(empty($line->fk_unit) ? $conf->global->PRODUCT_USE_UNITS : $line->fk_unit, 'units');
1595  print '</td></tr>';
1596  }
1597 
1598  // Custom code
1599  if (empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO) && empty($type)) {
1600  print '<tr><td class="wordbreak">'.$langs->trans("CustomCode").'</td><td><input name="customcode" class="maxwidth100onsmartphone" value="'.GETPOST('customcode').'"></td></tr>';
1601 
1602  // Origin country
1603  print '<tr><td>'.$langs->trans("CountryOrigin").'</td>';
1604  print '<td>';
1605  print img_picto('', 'globe-americas', 'class="paddingrightonly"');
1606  print $form->select_country((GETPOSTISSET('country_id') ? GETPOST('country_id') : $object->country_id), 'country_id', '', 0, 'minwidth300 widthcentpercentminusx maxwidth500');
1607  if ($user->admin) {
1608  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1609  }
1610  print '</td></tr>';
1611 
1612  // State
1613  if (empty($conf->global->PRODUCT_DISABLE_STATE)) {
1614  print '<tr>';
1615  if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && ($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 || $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 2)) {
1616  print '<td>'.$form->editfieldkey('RegionStateOrigin', 'state_id', '', $object, 0).'</td><td>';
1617  } else {
1618  print '<td>'.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).'</td><td>';
1619  }
1620 
1621  print img_picto('', 'state', 'class="pictofixedwidth"');
1622  print $formcompany->select_state($object->state_id, $object->country_code);
1623  print '</tr>';
1624  }
1625  }
1626 
1627  // Quality control
1628  if (!empty($conf->global->PRODUCT_LOT_ENABLE_QUALITY_CONTROL)) {
1629  print '<tr><td>'.$langs->trans("LifeTime").'</td><td><input name="lifetime" class="maxwidth50" value="'.GETPOST('lifetime').'"></td></tr>';
1630  print '<tr><td>'.$langs->trans("QCFrequency").'</td><td><input name="qc_frequency" class="maxwidth50" value="'.GETPOST('qc_frequency').'"></td></tr>';
1631  }
1632 
1633  // Other attributes
1634  $parameters = array('colspan' => ' colspan="2"', 'cols'=>2);
1635  $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1636  print $hookmanager->resPrint;
1637  if (empty($reshook)) {
1638  print $object->showOptionals($extrafields, 'create', $parameters);
1639  }
1640 
1641  // Note (private, no output on invoices, propales...)
1642  //if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) available in create mode
1643  //{
1644  print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td>';
1645 
1646  // We use dolibarr_details as type of DolEditor here, because we must not accept images as description is included into PDF and not accepted by TCPDF.
1647  $doleditor = new DolEditor('note_private', GETPOST('note_private', 'restricthtml'), '', 140, 'dolibarr_details', '', false, true, getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE'), ROWS_8, '90%');
1648  $doleditor->Create();
1649 
1650  print "</td></tr>";
1651  //}
1652 
1653  if (isModEnabled('categorie')) {
1654  // Categories
1655  print '<tr><td>'.$langs->trans("Categories").'</td><td>';
1656  $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', 'parent', 64, 0, 1);
1657  print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0);
1658  print "</td></tr>";
1659  }
1660 
1661  print '</table>';
1662 
1663  print '<hr>';
1664 
1665  if (empty($conf->global->PRODUCT_DISABLE_PRICES)) {
1666  if (!empty($conf->global->PRODUIT_MULTIPRICES)) {
1667  // We do no show price array on create when multiprices enabled.
1668  // We must set them on prices tab.
1669  print '<table class="border centpercent">';
1670  // VAT
1671  print '<tr><td class="titlefieldcreate">'.$langs->trans("VATRate").'</td><td>';
1672  $defaultva = get_default_tva($mysoc, $mysoc);
1673  print $form->load_tva("tva_tx", $defaultva, $mysoc, $mysoc, 0, 0, '', false, 1);
1674  print '</td></tr>';
1675 
1676  print '</table>';
1677 
1678  print '<br>';
1679  } else {
1680  print '<table class="border centpercent">';
1681 
1682  // Price
1683  print '<tr><td class="titlefieldcreate">'.$langs->trans("SellingPrice").'</td>';
1684  print '<td><input name="price" class="maxwidth50" value="'.$object->price.'">';
1685  print $form->selectPriceBaseType($conf->global->PRODUCT_PRICE_BASE_TYPE, "price_base_type");
1686  print '</td></tr>';
1687 
1688  // Min price
1689  print '<tr><td>'.$langs->trans("MinPrice").'</td>';
1690  print '<td><input name="price_min" class="maxwidth50" value="'.$object->price_min.'">';
1691  print '</td></tr>';
1692 
1693  // VAT
1694  print '<tr><td>'.$langs->trans("VATRate").'</td><td>';
1695  $defaultva = get_default_tva($mysoc, $mysoc);
1696  print $form->load_tva("tva_tx", $defaultva, $mysoc, $mysoc, 0, 0, '', false, 1);
1697  print '</td></tr>';
1698 
1699  print '</table>';
1700 
1701  print '<br>';
1702  }
1703  }
1704 
1705  // Accountancy codes
1706  print '<!-- accountancy codes -->'."\n";
1707  print '<table class="border centpercent">';
1708 
1709  if (empty($conf->global->PRODUCT_DISABLE_ACCOUNTING)) {
1710  if (isModEnabled('accounting')) {
1711  // Accountancy_code_sell
1712  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
1713  print '<td>';
1714  if ($type == 0) {
1715  $accountancy_code_sell = (GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_SOLD_ACCOUNT"));
1716  } else {
1717  $accountancy_code_sell = (GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_SOLD_ACCOUNT"));
1718  }
1719  print $formaccounting->select_account($accountancy_code_sell, 'accountancy_code_sell', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
1720  print '</td></tr>';
1721 
1722  // Accountancy_code_sell_intra
1723  if ($mysoc->isInEEC()) {
1724  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
1725  print '<td>';
1726  if ($type == 0) {
1727  $accountancy_code_sell_intra = (GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_SOLD_INTRA_ACCOUNT"));
1728  } else {
1729  $accountancy_code_sell_intra = (GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_SOLD_INTRA_ACCOUNT"));
1730  }
1731  print $formaccounting->select_account($accountancy_code_sell_intra, 'accountancy_code_sell_intra', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
1732  print '</td></tr>';
1733  }
1734 
1735  // Accountancy_code_sell_export
1736  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
1737  print '<td>';
1738  if ($type == 0) {
1739  $accountancy_code_sell_export = (GETPOST('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_SOLD_EXPORT_ACCOUNT"));
1740  } else {
1741  $accountancy_code_sell_export = (GETPOST('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_SOLD_EXPORT_ACCOUNT"));
1742  }
1743  print $formaccounting->select_account($accountancy_code_sell_export, 'accountancy_code_sell_export', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
1744  print '</td></tr>';
1745 
1746  // Accountancy_code_buy
1747  print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
1748  print '<td>';
1749  if ($type == 0) {
1750  $accountancy_code_buy = (GETPOST('accountancy_code_buy', 'alpha') ? (GETPOST('accountancy_code_buy', 'alpha')) : getDolGlobalString("ACCOUNTING_PRODUCT_BUY_ACCOUNT"));
1751  } else {
1752  $accountancy_code_buy = (GETPOST('accountancy_code_buy', 'alpha') ? (GETPOST('accountancy_code_buy', 'alpha')) : getDolGlobalString("ACCOUNTING_SERVICE_BUY_ACCOUNT"));
1753  }
1754  print $formaccounting->select_account($accountancy_code_buy, 'accountancy_code_buy', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
1755  print '</td></tr>';
1756 
1757  // Accountancy_code_buy_intra
1758  if ($mysoc->isInEEC()) {
1759  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
1760  print '<td>';
1761  if ($type == 0) {
1762  $accountancy_code_buy_intra = (GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_BUY_INTRA_ACCOUNT"));
1763  } else {
1764  $accountancy_code_buy_intra = (GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_BUY_INTRA_ACCOUNT"));
1765  }
1766  print $formaccounting->select_account($accountancy_code_buy_intra, 'accountancy_code_buy_intra', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
1767  print '</td></tr>';
1768  }
1769 
1770  // Accountancy_code_buy_export
1771  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
1772  print '<td>';
1773  if ($type == 0) {
1774  $accountancy_code_buy_export = (GETPOST('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_BUY_EXPORT_ACCOUNT"));
1775  } else {
1776  $accountancy_code_buy_export = (GETPOST('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_BUY_EXPORT_ACCOUNT"));
1777  }
1778  print $formaccounting->select_account($accountancy_code_buy_export, 'accountancy_code_buy_export', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
1779  print '</td></tr>';
1780  } else {// For external software
1781  if (!empty($accountancy_code_sell)) {
1782  $object->accountancy_code_sell = $accountancy_code_sell;
1783  }
1784  if (!empty($accountancy_code_sell_intra)) {
1785  $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
1786  }
1787  if (!empty($accountancy_code_sell_export)) {
1788  $object->accountancy_code_sell_export = $accountancy_code_sell_export;
1789  }
1790  if (!empty($accountancy_code_buy)) {
1791  $object->accountancy_code_buy = $accountancy_code_buy;
1792  }
1793  if (!empty($accountancy_code_buy_intra)) {
1794  $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
1795  }
1796  if (!empty($accountancy_code_buy_export)) {
1797  $object->accountancy_code_buy_export = $accountancy_code_buy_export;
1798  }
1799 
1800  // Accountancy_code_sell
1801  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
1802  print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell" value="'.$object->accountancy_code_sell.'">';
1803  print '</td></tr>';
1804 
1805  // Accountancy_code_sell_intra
1806  if ($mysoc->isInEEC()) {
1807  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
1808  print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell_intra" value="'.$object->accountancy_code_sell_intra.'">';
1809  print '</td></tr>';
1810  }
1811 
1812  // Accountancy_code_sell_export
1813  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
1814  print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell_export" value="'.$object->accountancy_code_sell_export.'">';
1815  print '</td></tr>';
1816 
1817  // Accountancy_code_buy
1818  print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
1819  print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy" value="'.$object->accountancy_code_buy.'">';
1820  print '</td></tr>';
1821 
1822  // Accountancy_code_buy_intra
1823  if ($mysoc->isInEEC()) {
1824  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
1825  print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy_intra" value="'.$object->accountancy_code_buy_intra.'">';
1826  print '</td></tr>';
1827  }
1828 
1829  // Accountancy_code_buy_export
1830  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
1831  print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy_export" value="'.$object->accountancy_code_buy_export.'">';
1832  print '</td></tr>';
1833  }
1834  }
1835  print '</table>';
1836 
1837  print dol_get_fiche_end();
1838 
1839  print $form->buttonsSaveCancel("Create");
1840 
1841  print '</form>';
1842  } elseif ($object->id > 0) {
1843  /*
1844  * Product card
1845  */
1846 
1847  // Fiche en mode edition
1848  if ($action == 'edit' && $usercancreate) {
1849  //WYSIWYG Editor
1850  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1851 
1852  if (!empty($conf->use_javascript_ajax)) {
1853  print '<script type="text/javascript">';
1854  print '$(document).ready(function () {
1855  $("#selectcountry_id").change(function () {
1856  document.formprod.action.value="edit";
1857  document.formprod.submit();
1858  });
1859  });';
1860  print '</script>'."\n";
1861  }
1862 
1863  // We set country_id, country_code and country for the selected country
1864  $object->country_id = GETPOST('country_id') ? GETPOST('country_id') : $object->country_id;
1865  if ($object->country_id) {
1866  $tmparray = getCountry($object->country_id, 'all');
1867  $object->country_code = $tmparray['code'];
1868  $object->country = $tmparray['label'];
1869  }
1870 
1871  $type = $langs->trans('Product');
1872  if ($object->isService()) {
1873  $type = $langs->trans('Service');
1874  }
1875  // print load_fiche_titre($langs->trans('Modify').' '.$type.' : '.(is_object($object->oldcopy)?$object->oldcopy->ref:$object->ref), "");
1876 
1877  // Main official, simple, and not duplicated code
1878  print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'" method="POST" name="formprod">'."\n";
1879  print '<input type="hidden" name="token" value="'.newToken().'">';
1880  print '<input type="hidden" name="action" value="update">';
1881  print '<input type="hidden" name="id" value="'.$object->id.'">';
1882  print '<input type="hidden" name="canvas" value="'.$object->canvas.'">';
1883 
1884  $head = product_prepare_head($object);
1885  $titre = $langs->trans("CardProduct".$object->type);
1886  $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
1887  print dol_get_fiche_head($head, 'card', $titre, 0, $picto);
1888 
1889 
1890  print '<table class="border allwidth">';
1891 
1892  // Ref
1893  if (empty($conf->global->MAIN_PRODUCT_REF_NOT_EDITABLE)) {
1894  print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Ref").'</td><td colspan="3"><input name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag(GETPOSTISSET('ref') ? GETPOST('ref') : $object->ref).'"></td></tr>';
1895  } else {
1896  print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Ref").'</td><td colspan="3"><input name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag($object->ref).'" readonly="true"></td></tr>';
1897  }
1898 
1899  // Label
1900  print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td colspan="3"><input name="label" class="minwidth300 maxwidth400onsmartphone" maxlength="255" value="'.dol_escape_htmltag(GETPOSTISSET('label') ? GETPOST('label') : $object->label).'"></td></tr>';
1901 
1902  // Status To sell
1903  print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td colspan="3">';
1904  print '<select class="flat" name="statut">';
1905  if ((GETPOSTISSET('statut') && GETPOST('statut')) || (!GETPOSTISSET('statut') && $object->status)) {
1906  print '<option value="1" selected>'.$langs->trans("OnSell").'</option>';
1907  print '<option value="0">'.$langs->trans("NotOnSell").'</option>';
1908  } else {
1909  print '<option value="1">'.$langs->trans("OnSell").'</option>';
1910  print '<option value="0" selected>'.$langs->trans("NotOnSell").'</option>';
1911  }
1912  print '</select>';
1913  print '</td></tr>';
1914 
1915  // Status To Buy
1916  print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td colspan="3">';
1917  print '<select class="flat" name="statut_buy">';
1918  if ((GETPOSTISSET('statut_buy') && GETPOST('statut_buy')) || (!GETPOSTISSET('statut_buy') && $object->status_buy)) {
1919  print '<option value="1" selected>'.$langs->trans("ProductStatusOnBuy").'</option>';
1920  print '<option value="0">'.$langs->trans("ProductStatusNotOnBuy").'</option>';
1921  } else {
1922  print '<option value="1">'.$langs->trans("ProductStatusOnBuy").'</option>';
1923  print '<option value="0" selected>'.$langs->trans("ProductStatusNotOnBuy").'</option>';
1924  }
1925  print '</select>';
1926  print '</td></tr>';
1927 
1928  // Batch number managment
1929  if (isModEnabled('productbatch')) {
1930  if ($object->isProduct() || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1931  print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
1932  $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial"));
1933  print $form->selectarray('status_batch', $statutarray, (GETPOSTISSET('status_batch') ? GETPOST('status_batch') : $object->status_batch));
1934  print '</td></tr>';
1935  if (!empty($object->status_batch) || !empty($conf->use_javascript_ajax)) {
1936  $langs->load("admin");
1937  $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
1938  $tooltip .= '<br>'.$langs->trans("GenericMaskCodes2");
1939  $tooltip .= '<br>'.$langs->trans("GenericMaskCodes3");
1940  $tooltip .= '<br>'.$langs->trans("GenericMaskCodes4a", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
1941  $tooltip .= '<br>'.$langs->trans("GenericMaskCodes5");
1942  print '<tr><td id="mask_option">'.$langs->trans("ManageLotMask").'</td>';
1943  if ($object->status_batch == '1' && getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
1944  $mask = !empty($object->batch_mask) ? $object->batch_mask : getDolGlobalString('LOT_ADVANCED_MASK');
1945  }
1946  if ($object->status_batch == '2' && getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
1947  $mask = !empty($object->batch_mask) ? $object->batch_mask : getDolGlobalString('SN_ADVANCED_MASK');
1948  }
1949  $inherited_mask_lot = getDolGlobalString('LOT_ADVANCED_MASK');
1950  $inherited_mask_sn = getDolGlobalString('SN_ADVANCED_MASK');
1951  print '<td id="field_mask">';
1952  print $form->textwithpicto('<input type="text" class="flat minwidth175" name="batch_mask" id="batch_mask_input" value="'.$mask.'">', $tooltip, 1, 1);
1953  // Add javascript to sho/hide field for custom mask
1954  if (!empty($conf->use_javascript_ajax)) {
1955  print '<script type="text/javascript">
1956  $(document).ready(function() {
1957  $("#field_mask").parent().addClass("hideobject");
1958  var preselect = document.getElementById("status_batch");';
1959  if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS')) {
1960  print 'if (preselect.value == "2") {
1961  $("#field_mask").parent().removeClass("hideobject");
1962  }';
1963  }
1964  if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS')) {
1965  print 'if (preselect.value == "1") {
1966  $("#field_mask").parent().removeClass("hideobject");
1967  }';
1968  }
1969  print '$("#status_batch").on("change", function () {
1970  var optionSelected = $("option:selected", this);
1971  var valueSelected = this.value;
1972  $("#field_mask").parent().addClass("hideobject");
1973  ';
1974  if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
1975  print '
1976  if (this.value == 1) {
1977  $("#field_mask").parent().removeClass("hideobject");
1978  $("#batch_mask_input").val("'.$inherited_mask_lot.'");
1979  }
1980  ';
1981  }
1982  if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
1983  print '
1984  if (this.value == 2) {
1985  $("#field_mask").parent().removeClass("hideobject");
1986  $("#batch_mask_input").val("'.$inherited_mask_sn.'");
1987  }
1988  ';
1989  }
1990  print '
1991  })
1992  })
1993  </script>';
1994  }
1995  print '</td></tr>';
1996  }
1997  }
1998  }
1999 
2000  // Barcode
2001  $showbarcode = empty($conf->barcode->enabled) ? 0 : 1;
2002  if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
2003  $showbarcode = 0;
2004  }
2005 
2006  if ($showbarcode) {
2007  print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
2008  if (GETPOSTISSET('fk_barcode_type')) {
2009  $fk_barcode_type = GETPOST('fk_barcode_type');
2010  } else {
2011  $fk_barcode_type = $object->barcode_type;
2012  if (empty($fk_barcode_type) && !empty($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE)) {
2013  $fk_barcode_type = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
2014  }
2015  }
2016  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
2017  $formbarcode = new FormBarCode($db);
2018  print $formbarcode->selectBarcodeType($fk_barcode_type, 'fk_barcode_type', 1);
2019  print '</td></tr>';
2020  print '<tr><td>'.$langs->trans("BarcodeValue").'</td><td>';
2021  $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
2022  if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
2023  $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
2024  }
2025  print '<input class="maxwidth150 maxwidthonsmartphone" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
2026  print '</td></tr>';
2027  }
2028 
2029  // Description (used in invoice, propal...)
2030  print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
2031 
2032  // We use dolibarr_details as type of DolEditor here, because we must not accept images as description is included into PDF and not accepted by TCPDF.
2033  $doleditor = new DolEditor('desc', GETPOSTISSET('desc') ? GETPOST('desc', 'restricthtml') : $object->description, '', 160, 'dolibarr_details', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_DETAILS'), ROWS_4, '90%');
2034  $doleditor->Create();
2035 
2036  print "</td></tr>";
2037  print "\n";
2038 
2039  // Public Url
2040  if (empty($conf->global->PRODUCT_DISABLE_PUBLIC_URL)) {
2041  print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
2042  print img_picto('', 'globe', 'class="pictofixedwidth"');
2043  print '<input type="text" name="url" class="quatrevingtpercent" value="'.(GETPOSTISSET('url') ? GETPOST('url') : $object->url).'">';
2044  print '</td></tr>';
2045  }
2046 
2047  // Stock
2048  if ($object->isProduct() && isModEnabled('stock')) {
2049  // Default warehouse
2050  print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
2051  print img_picto($langs->trans("DefaultWarehouse"), 'stock', 'class="pictofixedwidth"');
2052  print $formproduct->selectWarehouses((GETPOSTISSET('fk_default_warehouse') ? GETPOST('fk_default_warehouse') : $object->fk_default_warehouse), 'fk_default_warehouse', 'warehouseopen', 1);
2053  print ' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create&amp;backtopage='.urlencode($_SERVER['PHP_SELF'].'?action=edit&id='.((int) $object->id)).'">';
2054  print '<span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddWarehouse").'"></span></a>';
2055  print '</td></tr>';
2056  /*
2057  print "<tr>".'<td>'.$langs->trans("StockLimit").'</td><td>';
2058  print '<input name="seuil_stock_alerte" size="4" value="'.$object->seuil_stock_alerte.'">';
2059  print '</td>';
2060 
2061  print '<td>'.$langs->trans("DesiredStock").'</td><td>';
2062  print '<input name="desiredstock" size="4" value="'.$object->desiredstock.'">';
2063  print '</td></tr>';
2064  */
2065  }
2066 
2067  if ($object->isService() && $conf->workstation->enabled) {
2068  // Default workstation
2069  print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
2070  print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');
2071  print $formproduct->selectWorkstations($object->fk_default_workstation, 'fk_default_workstation', 1);
2072  print '</td></tr>';
2073  }
2074 
2075  /*
2076  else
2077  {
2078  print '<input name="seuil_stock_alerte" type="hidden" value="'.$object->seuil_stock_alerte.'">';
2079  print '<input name="desiredstock" type="hidden" value="'.$object->desiredstock.'">';
2080  }*/
2081 
2082  if ($object->isService()) {
2083  // Duration
2084  print '<tr><td>'.$langs->trans("Duration").'</td><td>';
2085  print '<input name="duration_value" size="5" value="'.$object->duration_value.'"> ';
2086  print $formproduct->selectMeasuringUnits("duration_unit", "time", $object->duration_unit, 0, 1);
2087 
2088  // Mandatory period
2089  print ' &nbsp; &nbsp; &nbsp; ';
2090  print '<input type="checkbox" id="mandatoryperiod" name="mandatoryperiod"'.($object->mandatory_period == 1 ? ' checked="checked"' : '').'>';
2091  print '<label for="mandatoryperiod">';
2092  $htmltooltip = $langs->trans("mandatoryHelper");
2093  print $form->textwithpicto($langs->trans("mandatoryperiod"), $htmltooltip, 1, 0);
2094  print '</label>';
2095 
2096  print '</td></tr>';
2097  } else {
2098  if (empty($conf->global->PRODUCT_DISABLE_NATURE)) {
2099  // Nature
2100  print '<tr><td>'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
2101  print $formproduct->selectProductNature('finished', (GETPOSTISSET('finished') ? GETPOST('finished') : $object->finished));
2102  print '</td></tr>';
2103  }
2104  }
2105 
2106  if (!$object->isService() && isModEnabled('bom')) {
2107  print '<tr><td>'.$form->textwithpicto($langs->trans("DefaultBOM"), $langs->trans("DefaultBOMDesc", $langs->transnoentitiesnoconv("Finished"))).'</td><td>';
2108  $bomkey = "Bom:bom/class/bom.class.php:0:(t.status:=:1) AND (t.fk_product:=:".((int) $object->id).')';
2109  print $form->selectForForms($bomkey, 'fk_default_bom', (GETPOSTISSET('fk_default_bom') ? GETPOST('fk_default_bom') : $object->fk_default_bom), 1);
2110  print '</td></tr>';
2111  }
2112 
2113  if (!$object->isService()) {
2114  if (empty($conf->global->PRODUCT_DISABLE_WEIGHT)) {
2115  // Brut Weight
2116  print '<tr><td>'.$langs->trans("Weight").'</td><td>';
2117  print '<input name="weight" size="5" value="'.(GETPOSTISSET('weight') ? GETPOST('weight') : $object->weight).'"> ';
2118  print $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOSTISSET('weight_units') ? GETPOST('weight_units') : $object->weight_units, 0, 2);
2119  print '</td></tr>';
2120  }
2121 
2122  if (empty($conf->global->PRODUCT_DISABLE_SIZE)) {
2123  // Brut Length
2124  print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
2125  print '<input name="size" size="5" value="'.(GETPOSTISSET('size') ? GETPOST('size') : $object->length).'">x';
2126  print '<input name="sizewidth" size="5" value="'.(GETPOSTISSET('sizewidth') ? GETPOST('sizewidth') : $object->width).'">x';
2127  print '<input name="sizeheight" size="5" value="'.(GETPOSTISSET('sizeheight') ? GETPOST('sizeheight') : $object->height).'"> ';
2128  print $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTISSET('size_units') ? GETPOST('size_units') : $object->length_units, 0, 2);
2129  print '</td></tr>';
2130  }
2131  if (empty($conf->global->PRODUCT_DISABLE_SURFACE)) {
2132  // Brut Surface
2133  print '<tr><td>'.$langs->trans("Surface").'</td><td>';
2134  print '<input name="surface" size="5" value="'.(GETPOSTISSET('surface') ? GETPOST('surface') : $object->surface).'"> ';
2135  print $formproduct->selectMeasuringUnits("surface_units", "surface", GETPOSTISSET('surface_units') ? GETPOST('surface_units') : $object->surface_units, 0, 2);
2136  print '</td></tr>';
2137  }
2138  if (empty($conf->global->PRODUCT_DISABLE_VOLUME)) {
2139  // Brut Volume
2140  print '<tr><td>'.$langs->trans("Volume").'</td><td>';
2141  print '<input name="volume" size="5" value="'.(GETPOSTISSET('volume') ? GETPOST('volume') : $object->volume).'"> ';
2142  print $formproduct->selectMeasuringUnits("volume_units", "volume", GETPOSTISSET('volume_units') ? GETPOST('volume_units') : $object->volume_units, 0, 2);
2143  print '</td></tr>';
2144  }
2145 
2146  if (!empty($conf->global->PRODUCT_ADD_NET_MEASURE)) {
2147  // Net Measure
2148  print '<tr><td>'.$langs->trans("NetMeasure").'</td><td>';
2149  print '<input name="net_measure" size="5" value="'.(GETPOSTISSET('net_measure') ? GETPOST('net_measure') : $object->net_measure).'"> ';
2150  print $formproduct->selectMeasuringUnits("net_measure_units", "", GETPOSTISSET('net_measure_units') ? GETPOST('net_measure_units') : $object->net_measure_units, 0, 0);
2151  print '</td></tr>';
2152  }
2153  }
2154  // Units
2155  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2156  print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
2157  print '<td>';
2158  print $form->selectUnits($object->fk_unit, 'units');
2159  print '</td></tr>';
2160  }
2161 
2162  // Custom code
2163  if (!$object->isService() && empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO)) {
2164  print '<tr><td class="wordbreak">'.$langs->trans("CustomCode").'</td><td><input name="customcode" class="maxwidth100onsmartphone" value="'.(GETPOSTISSET('customcode') ? GETPOST('customcode') : $object->customcode).'"></td></tr>';
2165  // Origin country
2166  print '<tr><td>'.$langs->trans("CountryOrigin").'</td>';
2167  print '<td>';
2168  print img_picto('', 'globe-americas', 'class="paddingrightonly"');
2169  print $form->select_country(GETPOSTISSET('country_id') ? GETPOST('country_id', 'int') : $object->country_id, 'country_id', '', 0, 'minwidth100 maxwidthonsmartphone');
2170  if ($user->admin) {
2171  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
2172  }
2173  print '</td></tr>';
2174 
2175  // State
2176  if (empty($conf->global->PRODUCT_DISABLE_STATE)) {
2177  print '<tr>';
2178  if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && ($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 || $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 2)) {
2179  print '<td>'.$form->editfieldkey('RegionStateOrigin', 'state_id', '', $object, 0).'</td><td>';
2180  } else {
2181  print '<td>'.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).'</td><td>';
2182  }
2183 
2184  print img_picto('', 'state', 'class="pictofixedwidth"');
2185  print $formcompany->select_state(GETPOSTISSET('state_id') ? GETPOST('state_id', 'int') : $object->state_id, $object->country_code);
2186  print '</td>';
2187  print '</tr>';
2188  }
2189  }
2190 
2191  // Quality control
2192  if (!empty($conf->global->PRODUCT_LOT_ENABLE_QUALITY_CONTROL)) {
2193  print '<tr><td>'.$langs->trans("LifeTime").'</td><td><input name="lifetime" class="maxwidth100onsmartphone" value="'.$object->lifetime.'"></td></tr>';
2194  print '<tr><td>'.$langs->trans("QCFrequency").'</td><td><input name="qc_frequency" class="maxwidth100onsmartphone" value="'.$object->qc_frequency.'"></td></tr>';
2195  }
2196 
2197  // Other attributes
2198  $parameters = array('colspan' => ' colspan="2"', 'cols' => 2);
2199  $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2200  print $hookmanager->resPrint;
2201  if (empty($reshook)) {
2202  print $object->showOptionals($extrafields, 'edit', $parameters);
2203  }
2204 
2205  // Tags-Categories
2206  if (isModEnabled('categorie')) {
2207  print '<tr><td>'.$langs->trans("Categories").'</td><td>';
2208  $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', 'parent', 64, 0, 1);
2209  $c = new Categorie($db);
2210  $cats = $c->containing($object->id, Categorie::TYPE_PRODUCT);
2211  $arrayselected = array();
2212  if (is_array($cats)) {
2213  foreach ($cats as $cat) {
2214  $arrayselected[] = $cat->id;
2215  }
2216  }
2217  if (GETPOSTISSET('categories', 'array')) {
2218  foreach (GETPOST('categories', 'array') as $cat) {
2219  $arrayselected[] = $cat;
2220  }
2221  }
2222  print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0);
2223  print "</td></tr>";
2224  }
2225 
2226  // Note private
2227  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
2228  print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td>';
2229 
2230  $doleditor = new DolEditor('note_private', $object->note_private, '', 140, 'dolibarr_notes', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_NOTE_PRIVATE'), ROWS_4, '90%');
2231  $doleditor->Create();
2232 
2233  print "</td></tr>";
2234  }
2235 
2236  print '</table>';
2237 
2238  print '<br>';
2239 
2240  print '<table class="border centpercent">';
2241 
2242  if (empty($conf->global->PRODUCT_DISABLE_ACCOUNTING)) {
2243  if (isModEnabled('accounting')) {
2244  // Accountancy_code_sell
2245  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
2246  print '<td>';
2247  print $formaccounting->select_account((GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell') : $object->accountancy_code_sell), 'accountancy_code_sell', 1, '', 1, 1, 'minwidth150 maxwidth300');
2248  print '</td></tr>';
2249 
2250  // Accountancy_code_sell_intra
2251  if ($mysoc->isInEEC()) {
2252  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
2253  print '<td>';
2254  print $formaccounting->select_account((GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra') : $object->accountancy_code_sell_intra), 'accountancy_code_sell_intra', 1, '', 1, 1, 'minwidth150 maxwidth300');
2255  print '</td></tr>';
2256  }
2257 
2258  // Accountancy_code_sell_export
2259  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
2260  print '<td>';
2261  print $formaccounting->select_account((GETPOSTISSET('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export') : $object->accountancy_code_sell_export), 'accountancy_code_sell_export', 1, '', 1, 1, 'minwidth150 maxwidth300');
2262  print '</td></tr>';
2263 
2264  // Accountancy_code_buy
2265  print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
2266  print '<td>';
2267  print $formaccounting->select_account((GETPOSTISSET('accountancy_code_buy') ? GETPOST('accountancy_code_buy') : $object->accountancy_code_buy), 'accountancy_code_buy', 1, '', 1, 1, 'minwidth150 maxwidth300');
2268  print '</td></tr>';
2269 
2270  // Accountancy_code_buy_intra
2271  if ($mysoc->isInEEC()) {
2272  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
2273  print '<td>';
2274  print $formaccounting->select_account((GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra') : $object->accountancy_code_buy_intra), 'accountancy_code_buy_intra', 1, '', 1, 1, 'minwidth150 maxwidth300');
2275  print '</td></tr>';
2276  }
2277 
2278  // Accountancy_code_buy_export
2279  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
2280  print '<td>';
2281  print $formaccounting->select_account((GETPOSTISSET('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export') : $object->accountancy_code_buy_export), 'accountancy_code_buy_export', 1, '', 1, 1, 'minwidth150 maxwidth300');
2282  print '</td></tr>';
2283  } else {
2284  // For external software
2285  // Accountancy_code_sell
2286  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
2287  print '<td><input name="accountancy_code_sell" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell') : $object->accountancy_code_sell).'">';
2288  print '</td></tr>';
2289 
2290  // Accountancy_code_sell_intra
2291  if ($mysoc->isInEEC()) {
2292  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
2293  print '<td><input name="accountancy_code_sell_intra" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra') : $object->accountancy_code_sell_intra).'">';
2294  print '</td></tr>';
2295  }
2296 
2297  // Accountancy_code_sell_export
2298  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
2299  print '<td><input name="accountancy_code_sell_export" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export') : $object->accountancy_code_sell_export).'">';
2300  print '</td></tr>';
2301 
2302  // Accountancy_code_buy
2303  print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
2304  print '<td><input name="accountancy_code_buy" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_buy') ? GETPOST('accountancy_code_buy') : $object->accountancy_code_buy).'">';
2305  print '</td></tr>';
2306 
2307  // Accountancy_code_buy_intra
2308  if ($mysoc->isInEEC()) {
2309  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
2310  print '<td><input name="accountancy_code_buy_intra" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra') : $object->accountancy_code_buy_intra).'">';
2311  print '</td></tr>';
2312  }
2313 
2314  // Accountancy_code_buy_export
2315  print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
2316  print '<td><input name="accountancy_code_buy_export" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export') : $object->accountancy_code_buy_export).'">';
2317  print '</td></tr>';
2318  }
2319  }
2320  print '</table>';
2321 
2322  print dol_get_fiche_end();
2323 
2324  print $form->buttonsSaveCancel();
2325 
2326  print '</form>';
2327  } else {
2328  // Fiche en mode visu
2329 
2330  $showbarcode = empty($conf->barcode->enabled) ? 0 : 1;
2331  if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
2332  $showbarcode = 0;
2333  }
2334 
2335  $head = product_prepare_head($object);
2336  $titre = $langs->trans("CardProduct".$object->type);
2337  $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
2338 
2339  print dol_get_fiche_head($head, 'card', $titre, -1, $picto);
2340 
2341  $linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?restore_lastsearch_values=1&type='.$object->type.'">'.$langs->trans("BackToList").'</a>';
2342  $object->next_prev_filter = " fk_product_type = ".$object->type;
2343 
2344  $shownav = 1;
2345  if ($user->socid && !in_array('product', explode(',', $conf->global->MAIN_MODULES_FOR_EXTERNAL))) {
2346  $shownav = 0;
2347  }
2348 
2349  dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref');
2350 
2351 
2352  print '<div class="fichecenter">';
2353  print '<div class="fichehalfleft">';
2354 
2355  print '<div class="underbanner clearboth"></div>';
2356  print '<table class="border tableforfield centpercent">';
2357 
2358  // Type
2359  if (isModEnabled("product") && isModEnabled("service")) {
2360  $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
2361  print '<tr><td class="titlefield">';
2362  print (empty($conf->global->PRODUCT_DENY_CHANGE_PRODUCT_TYPE)) ? $form->editfieldkey("Type", 'fk_product_type', $object->type, $object, $usercancreate, $typeformat) : $langs->trans('Type');
2363  print '</td><td>';
2364  print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, $usercancreate, $typeformat);
2365  print '</td></tr>';
2366  }
2367 
2368  if ($showbarcode) {
2369  // Barcode type
2370  print '<tr><td class="nowrap">';
2371  print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
2372  print $langs->trans("BarcodeType");
2373  print '</td>';
2374  if (($action != 'editbarcodetype') && $usercancreate && $createbarcode) {
2375  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editbarcodetype&id='.$object->id.'&token='.newToken().'">'.img_edit($langs->trans('Edit'), 1).'</a></td>';
2376  }
2377  print '</tr></table>';
2378  print '</td><td>';
2379  if ($action == 'editbarcodetype' || $action == 'editbarcode') {
2380  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
2381  $formbarcode = new FormBarCode($db);
2382  }
2383 
2384  $fk_barcode_type = '';
2385  if ($action == 'editbarcodetype') {
2386  print $formbarcode->formBarcodeType($_SERVER['PHP_SELF'].'?id='.$object->id, $object->barcode_type, 'fk_barcode_type');
2387  $fk_barcode_type = $object->barcode_type;
2388  } else {
2389  $object->fetch_barcode();
2390  $fk_barcode_type = $object->barcode_type;
2391  print $object->barcode_type_label ? $object->barcode_type_label : ($object->barcode ? '<div class="warning">'.$langs->trans("SetDefaultBarcodeType").'<div>' : '');
2392  }
2393  print '</td></tr>'."\n";
2394 
2395  // Barcode value
2396  print '<tr><td class="nowrap">';
2397  print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
2398  print $langs->trans("BarcodeValue");
2399  print '</td>';
2400  if (($action != 'editbarcode') && $usercancreate && $createbarcode) {
2401  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editbarcode&id='.$object->id.'&token='.newToken().'">'.img_edit($langs->trans('Edit'), 1).'</a></td>';
2402  }
2403  print '</tr></table>';
2404  print '</td><td>';
2405  if ($action == 'editbarcode') {
2406  $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
2407  if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
2408  $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
2409  }
2410 
2411  print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
2412  print '<input type="hidden" name="token" value="'.newToken().'">';
2413  print '<input type="hidden" name="action" value="setbarcode">';
2414  print '<input type="hidden" name="barcode_type_code" value="'.$object->barcode_type_code.'">';
2415  print '<input size="40" class="maxwidthonsmartphone" type="text" name="barcode" value="'.$tmpcode.'">';
2416  print '&nbsp;<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
2417  print '</form>';
2418  } else {
2419  print showValueWithClipboardCPButton($object->barcode);
2420  }
2421  print '</td></tr>'."\n";
2422  }
2423 
2424  // Batch number management (to batch)
2425  if (isModEnabled('productbatch')) {
2426  if ($object->isProduct() || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
2427  print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
2428  print $object->getLibStatut(0, 2);
2429  print '</td></tr>';
2430  if ((($object->status_batch == '1' && !empty($conf->global->PRODUCTBATCH_LOT_USE_PRODUCT_MASKS) && $conf->global->PRODUCTBATCH_LOT_ADDON == 'mod_lot_advanced')
2431  || ($object->status_batch == '2' && $conf->global->PRODUCTBATCH_SN_ADDON == 'mod_sn_advanced' && !empty($conf->global->PRODUCTBATCH_SN_USE_PRODUCT_MASKS)))) {
2432  print '<tr><td>'.$langs->trans("ManageLotMask").'</td><td>';
2433  print $object->batch_mask;
2434  print '</td></tr>';
2435  }
2436  }
2437  }
2438 
2439  if (empty($conf->global->PRODUCT_DISABLE_ACCOUNTING)) {
2440  // Accountancy sell code
2441  print '<tr><td class="nowrap">';
2442  print $langs->trans("ProductAccountancySellCode");
2443  print '</td><td>';
2444  if (isModEnabled('accounting')) {
2445  if (!empty($object->accountancy_code_sell)) {
2446  $accountingaccount = new AccountingAccount($db);
2447  $accountingaccount->fetch('', $object->accountancy_code_sell, 1);
2448 
2449  print $accountingaccount->getNomUrl(0, 1, 1, '', 1);
2450  }
2451  } else {
2452  print $object->accountancy_code_sell;
2453  }
2454  print '</td></tr>';
2455 
2456  // Accountancy sell code intra-community
2457  if ($mysoc->isInEEC()) {
2458  print '<tr><td class="nowrap">';
2459  print $langs->trans("ProductAccountancySellIntraCode");
2460  print '</td><td>';
2461  if (isModEnabled('accounting')) {
2462  if (!empty($object->accountancy_code_sell_intra)) {
2463  $accountingaccount2 = new AccountingAccount($db);
2464  $accountingaccount2->fetch('', $object->accountancy_code_sell_intra, 1);
2465 
2466  print $accountingaccount2->getNomUrl(0, 1, 1, '', 1);
2467  }
2468  } else {
2469  print $object->accountancy_code_sell_intra;
2470  }
2471  print '</td></tr>';
2472  }
2473 
2474  // Accountancy sell code export
2475  print '<tr><td class="nowrap">';
2476  print $langs->trans("ProductAccountancySellExportCode");
2477  print '</td><td>';
2478  if (isModEnabled('accounting')) {
2479  if (!empty($object->accountancy_code_sell_export)) {
2480  $accountingaccount3 = new AccountingAccount($db);
2481  $accountingaccount3->fetch('', $object->accountancy_code_sell_export, 1);
2482 
2483  print $accountingaccount3->getNomUrl(0, 1, 1, '', 1);
2484  }
2485  } else {
2486  print $object->accountancy_code_sell_export;
2487  }
2488  print '</td></tr>';
2489 
2490  // Accountancy buy code
2491  print '<tr><td class="nowrap">';
2492  print $langs->trans("ProductAccountancyBuyCode");
2493  print '</td><td>';
2494  if (isModEnabled('accounting')) {
2495  if (!empty($object->accountancy_code_buy)) {
2496  $accountingaccount4 = new AccountingAccount($db);
2497  $accountingaccount4->fetch('', $object->accountancy_code_buy, 1);
2498 
2499  print $accountingaccount4->getNomUrl(0, 1, 1, '', 1);
2500  }
2501  } else {
2502  print $object->accountancy_code_buy;
2503  }
2504  print '</td></tr>';
2505 
2506  // Accountancy buy code intra-community
2507  if ($mysoc->isInEEC()) {
2508  print '<tr><td class="nowrap">';
2509  print $langs->trans("ProductAccountancyBuyIntraCode");
2510  print '</td><td>';
2511  if (isModEnabled('accounting')) {
2512  if (!empty($object->accountancy_code_buy_intra)) {
2513  $accountingaccount5 = new AccountingAccount($db);
2514  $accountingaccount5->fetch('', $object->accountancy_code_buy_intra, 1);
2515 
2516  print $accountingaccount5->getNomUrl(0, 1, 1, '', 1);
2517  }
2518  } else {
2519  print $object->accountancy_code_buy_intra;
2520  }
2521  print '</td></tr>';
2522  }
2523 
2524  // Accountancy buy code export
2525  print '<tr><td class="nowrap">';
2526  print $langs->trans("ProductAccountancyBuyExportCode");
2527  print '</td><td>';
2528  if (isModEnabled('accounting')) {
2529  if (!empty($object->accountancy_code_buy_export)) {
2530  $accountingaccount6 = new AccountingAccount($db);
2531  $accountingaccount6->fetch('', $object->accountancy_code_buy_export, 1);
2532 
2533  print $accountingaccount6->getNomUrl(0, 1, 1, '', 1);
2534  }
2535  } else {
2536  print $object->accountancy_code_buy_export;
2537  }
2538  print '</td></tr>';
2539  }
2540 
2541  // Description
2542  print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>'.(dol_textishtml($object->description) ? $object->description : dol_nl2br($object->description, 1, true)).'</td></tr>';
2543 
2544  // Public URL
2545  if (empty($conf->global->PRODUCT_DISABLE_PUBLIC_URL)) {
2546  print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
2547  print dol_print_url($object->url, '_blank', 128);
2548  print '</td></tr>';
2549  }
2550 
2551  // Default warehouse
2552  if ($object->isProduct() && isModEnabled('stock')) {
2553  $warehouse = new Entrepot($db);
2554  $warehouse->fetch($object->fk_default_warehouse);
2555 
2556  print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
2557  print (!empty($warehouse->id) ? $warehouse->getNomUrl(1) : '');
2558  print '</td>';
2559  }
2560 
2561  if ($object->isService() && isModEnabled('workstation')) {
2562  $workstation = new Workstation($db);
2563  $res = $workstation->fetch($object->fk_default_workstation);
2564 
2565  print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
2566  print (!empty($workstation->id) ? $workstation->getNomUrl(1) : '');
2567  print '</td>';
2568  }
2569 
2570  // Parent product.
2571  if (isModEnabled('variants') && ($object->isProduct() || $object->isService())) {
2572  $combination = new ProductCombination($db);
2573 
2574  if ($combination->fetchByFkProductChild($object->id) > 0) {
2575  $prodstatic = new Product($db);
2576  $prodstatic->fetch($combination->fk_product_parent);
2577 
2578  // Parent product
2579  print '<tr><td>'.$langs->trans("ParentProduct").'</td><td>';
2580  print $prodstatic->getNomUrl(1);
2581  print '</td></tr>';
2582  }
2583  }
2584 
2585  print '</table>';
2586  print '</div>';
2587  print '<div class="fichehalfright">';
2588 
2589  print '<div class="underbanner clearboth"></div>';
2590  print '<table class="border tableforfield centpercent">';
2591 
2592  if ($object->isService()) {
2593  // Duration
2594  print '<tr><td class="titlefield">'.$langs->trans("Duration").'</td><td>';
2595  print $object->duration_value;
2596  if ($object->duration_value > 1) {
2597  $dur = array("i"=>$langs->trans("Minute"), "h"=>$langs->trans("Hours"), "d"=>$langs->trans("Days"), "w"=>$langs->trans("Weeks"), "m"=>$langs->trans("Months"), "y"=>$langs->trans("Years"));
2598  } elseif ($object->duration_value > 0) {
2599  $dur = array("i"=>$langs->trans("Minute"), "h"=>$langs->trans("Hour"), "d"=>$langs->trans("Day"), "w"=>$langs->trans("Week"), "m"=>$langs->trans("Month"), "y"=>$langs->trans("Year"));
2600  }
2601  print (!empty($object->duration_unit) && isset($dur[$object->duration_unit]) ? "&nbsp;".$langs->trans($dur[$object->duration_unit])."&nbsp;" : '');
2602 
2603  // Mandatory period
2604  if ($object->duration_value > 0) {
2605  print ' &nbsp; &nbsp; &nbsp; ';
2606  }
2607  $htmltooltip = $langs->trans("mandatoryHelper");
2608  print '<input type="checkbox" class="" name="mandatoryperiod"'.($object->mandatory_period == 1 ? ' checked="checked"' : '').' disabled>';
2609  print $form->textwithpicto($langs->trans("mandatoryperiod"), $htmltooltip, 1, 0);
2610 
2611  print '</td></tr>';
2612  } else {
2613  if (empty($conf->global->PRODUCT_DISABLE_NATURE)) {
2614  // Nature
2615  print '<tr><td class="titlefield">'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
2616  print $object->getLibFinished();
2617  print '</td></tr>';
2618  }
2619  }
2620 
2621  if (!$object->isService() && isModEnabled('bom') && $object->finished) {
2622  print '<tr><td class="titlefield">'.$form->textwithpicto($langs->trans("DefaultBOM"), $langs->trans("DefaultBOMDesc", $langs->transnoentitiesnoconv("Finished"))).'</td><td>';
2623  if ($object->fk_default_bom) {
2624  $bom_static = new BOM($db);
2625  $bom_static->fetch($object->fk_default_bom);
2626  print $bom_static->getNomUrl(1);
2627  }
2628  print '</td></tr>';
2629  }
2630 
2631  if (!$object->isService()) {
2632  // Brut Weight
2633  if (empty($conf->global->PRODUCT_DISABLE_WEIGHT)) {
2634  print '<tr><td class="titlefield">'.$langs->trans("Weight").'</td><td>';
2635  if ($object->weight != '') {
2636  print $object->weight." ".measuringUnitString(0, "weight", $object->weight_units);
2637  } else {
2638  print '&nbsp;';
2639  }
2640  print "</td></tr>\n";
2641  }
2642 
2643  if (empty($conf->global->PRODUCT_DISABLE_SIZE)) {
2644  // Brut Length
2645  print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
2646  if ($object->length != '' || $object->width != '' || $object->height != '') {
2647  print $object->length;
2648  if ($object->width) {
2649  print " x ".$object->width;
2650  }
2651  if ($object->height) {
2652  print " x ".$object->height;
2653  }
2654  print ' '.measuringUnitString(0, "size", $object->length_units);
2655  } else {
2656  print '&nbsp;';
2657  }
2658  print "</td></tr>\n";
2659  }
2660  if (empty($conf->global->PRODUCT_DISABLE_SURFACE)) {
2661  // Brut Surface
2662  print '<tr><td>'.$langs->trans("Surface").'</td><td>';
2663  if ($object->surface != '') {
2664  print $object->surface." ".measuringUnitString(0, "surface", $object->surface_units);
2665  } else {
2666  print '&nbsp;';
2667  }
2668  print "</td></tr>\n";
2669  }
2670  if (empty($conf->global->PRODUCT_DISABLE_VOLUME)) {
2671  // Brut Volume
2672  print '<tr><td>'.$langs->trans("Volume").'</td><td>';
2673  if ($object->volume != '') {
2674  print $object->volume." ".measuringUnitString(0, "volume", $object->volume_units);
2675  } else {
2676  print '&nbsp;';
2677  }
2678  print "</td></tr>\n";
2679  }
2680 
2681  if (!empty($conf->global->PRODUCT_ADD_NET_MEASURE)) {
2682  // Net Measure
2683  print '<tr><td class="titlefield">'.$langs->trans("NetMeasure").'</td><td>';
2684  if ($object->net_measure != '') {
2685  print $object->net_measure." ".measuringUnitString($object->net_measure_units);
2686  } else {
2687  print '&nbsp;';
2688  }
2689  print '</td></tr>';
2690  }
2691  }
2692 
2693  // Unit
2694  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2695  $unit = $object->getLabelOfUnit();
2696 
2697  print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td><td>';
2698  if ($unit !== '') {
2699  print $langs->trans($unit);
2700  }
2701  print '</td></tr>';
2702  }
2703 
2704  // Custom code
2705  if (!$object->isService() && empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO)) {
2706  print '<tr><td>'.$langs->trans("CustomCode").'</td><td>'.$object->customcode.'</td></tr>';
2707 
2708  // Origin country code
2709  print '<tr><td>'.$langs->trans("Origin").'</td><td>'.getCountry($object->country_id, 0, $db);
2710  if (!empty($object->state_id)) {
2711  print ' - '.getState($object->state_id, 0, $db);
2712  }
2713  print '</td></tr>';
2714  }
2715 
2716  // Quality Control
2717  if (!empty($conf->global->PRODUCT_LOT_ENABLE_QUALITY_CONTROL)) {
2718  print '<tr><td>'.$langs->trans("LifeTime").'</td><td>'.$object->lifetime.'</td></tr>';
2719  print '<tr><td>'.$langs->trans("QCFrequency").'</td><td>'.$object->qc_frequency.'</td></tr>';
2720  }
2721 
2722  // Other attributes
2723  $parameters = array();
2724  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
2725 
2726  // Categories
2727  if (isModEnabled('categorie')) {
2728  print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
2729  print $form->showCategories($object->id, Categorie::TYPE_PRODUCT, 1);
2730  print "</td></tr>";
2731  }
2732 
2733  // Note private
2734  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
2735  print '<!-- show Note --> '."\n";
2736  print '<tr><td class="tdtop">'.$langs->trans("NotePrivate").'</td><td>'.(dol_textishtml($object->note_private) ? $object->note_private : dol_nl2br($object->note_private, 1, true)).'</td></tr>'."\n";
2737  print '<!-- End show Note --> '."\n";
2738  }
2739 
2740  print "</table>\n";
2741  print '</div>';
2742 
2743  print '</div>';
2744  print '<div style="clear:both"></div>';
2745 
2746  print dol_get_fiche_end();
2747  }
2748  } elseif ($action != 'create') {
2749  exit;
2750  }
2751 }
2752 
2753 $tmpcode = '';
2754 if (!empty($modCodeProduct->code_auto)) {
2755  $tmpcode = $modCodeProduct->getNextValue($object, $object->type);
2756 }
2757 
2758 $formconfirm = '';
2759 
2760 // Confirm delete product
2761 if (($action == 'delete' && (empty($conf->use_javascript_ajax) || !empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
2762  || (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) { // Always output when not jmobile nor js
2763  $formconfirm = $form->formconfirm("card.php?id=".$object->id, $langs->trans("DeleteProduct"), $langs->trans("ConfirmDeleteProduct"), "confirm_delete", '', 0, "action-delete");
2764 }
2765 if ($action == 'merge') {
2766  $formquestion = array(
2767  array(
2768  'name' => 'product_origin',
2769  'label' => $langs->trans('MergeOriginProduct'),
2770  'type' => 'other',
2771  'value' => $form->select_produits('', 'product_origin', '', 0, 0, 1, 2, '', 1, array(), 0, 1, 0, 'minwidth200', 0, '', null, 1),
2772  )
2773  );
2774  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("MergeProducts"), $langs->trans("ConfirmMergeProducts"), "confirm_merge", $formquestion, 'no', 1, 250);
2775 }
2776 
2777 // Clone confirmation
2778 if (($action == 'clone' && (empty($conf->use_javascript_ajax) || !empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
2779  || (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) { // Always output when not jmobile nor js
2780  // Define confirmation messages
2781  $formquestionclone = array(
2782  'text' => $langs->trans("ConfirmClone"),
2783  array('type' => 'text', 'name' => 'clone_ref', 'label' => $langs->trans("NewRefForClone"), 'value' => empty($tmpcode) ? $langs->trans("CopyOf").' '.$object->ref : $tmpcode, 'morecss'=>'width150'),
2784  array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneContentProduct"), 'value' => 1),
2785  array('type' => 'checkbox', 'name' => 'clone_categories', 'label' => $langs->trans("CloneCategoriesProduct"), 'value' => 1),
2786  );
2787  if (!empty($conf->global->PRODUIT_MULTIPRICES)) {
2788  $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_prices', 'label' => $langs->trans("ClonePricesProduct").' ('.$langs->trans("CustomerPrices").')', 'value' => 0);
2789  }
2790  if (!empty($conf->global->PRODUIT_SOUSPRODUITS)) {
2791  $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_composition', 'label' => $langs->trans('CloneCompositionProduct'), 'value' => 1);
2792  }
2793 
2794  $formconfirm .= $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneProduct', $object->ref), 'confirm_clone', $formquestionclone, 'yes', 'action-clone', 350, 600);
2795 }
2796 
2797 // Call Hook formConfirm
2798 $parameters = array('formConfirm' => $formconfirm, 'object' => $object);
2799 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2800 if (empty($reshook)) {
2801  $formconfirm .= $hookmanager->resPrint;
2802 } elseif ($reshook > 0) {
2803  $formconfirm = $hookmanager->resPrint;
2804 }
2805 
2806 // Print form confirm
2807 print $formconfirm;
2808 
2809 /*
2810  * Action bar
2811  */
2812 if ($action != 'create' && $action != 'edit') {
2813  $cloneProductUrl = $_SERVER["PHP_SELF"].'?action=clone&token='.newToken();
2814  $cloneButtonId = 'action-clone-no-ajax';
2815 
2816  print "\n".'<div class="tabsAction">'."\n";
2817 
2818  $parameters = array();
2819  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2820  if (empty($reshook)) {
2821  if ($usercancreate) {
2822  if (!isset($object->no_button_edit) || $object->no_button_edit <> 1) {
2823  print dolGetButtonAction('', $langs->trans('Modify'), 'default', $_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'&id='.$object->id, '', $usercancreate);
2824  }
2825 
2826  if (!isset($object->no_button_copy) || $object->no_button_copy <> 1) {
2827  if (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile)) {
2828  $cloneProductUrl = '';
2829  $cloneButtonId = 'action-clone';
2830  }
2831  print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $cloneProductUrl, $cloneButtonId, $usercancreate);
2832  }
2833  }
2834  $object_is_used = $object->isObjectUsed($object->id);
2835 
2836  if ($usercandelete) {
2837  if (empty($object_is_used) && (!isset($object->no_button_delete) || $object->no_button_delete <> 1)) {
2838  if (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile)) {
2839  print dolGetButtonAction($langs->trans('Delete'), '', 'delete', '#', 'action-delete', true);
2840  } else {
2841  print dolGetButtonAction('', $langs->trans('Delete'), 'delete', $_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id, '');
2842  }
2843  } else {
2844  print dolGetButtonAction($langs->trans("ProductIsUsed"), $langs->trans('Delete'), 'delete', '#', '', false);
2845  }
2846  if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 1) {
2847  print '<a class="butActionDelete" href="card.php?action=merge&id='.$object->id.'" title="'.dol_escape_htmltag($langs->trans("MergeProducts")).'">'.$langs->trans('Merge').'</a>'."\n";
2848  }
2849  } else {
2850  print dolGetButtonAction($langs->trans("NotEnoughPermissions"), $langs->trans('Delete'), 'delete', '#', '', false);
2851  }
2852  }
2853 
2854  print "\n</div>\n";
2855 }
2856 
2857 
2858 /*
2859  * All the "Add to" areas if PRODUCT_ADD_FORM_ADD_TO is set
2860  */
2861 
2862 if (!empty($conf->global->PRODUCT_ADD_FORM_ADD_TO) && $object->id && ($action == '' || $action == 'view') && $object->status) {
2863  //Variable used to check if any text is going to be printed
2864  $html = '';
2865  //print '<div class="fichecenter"><div class="fichehalfleft">';
2866 
2867  // Propals
2868  if (isModEnabled("propal") && $user->rights->propal->creer) {
2869  $propal = new Propal($db);
2870 
2871  $langs->load("propal");
2872 
2873  $otherprop = $propal->liste_array(2, 1, 0);
2874 
2875  if (is_array($otherprop) && count($otherprop)) {
2876  $html .= '<tr><td style="width: 200px;">';
2877  $html .= $langs->trans("AddToDraftProposals").'</td><td>';
2878  $html .= $form->selectarray("propalid", $otherprop, 0, 1);
2879  $html .= '</td></tr>';
2880  } else {
2881  $html .= '<tr><td style="width: 200px;">';
2882  $html .= $langs->trans("AddToDraftProposals").'</td><td>';
2883  $html .= $langs->trans("NoDraftProposals");
2884  $html .= '</td></tr>';
2885  }
2886  }
2887 
2888  // Commande
2889  if (isModEnabled('commande') && $user->rights->commande->creer) {
2890  $commande = new Commande($db);
2891 
2892  $langs->load("orders");
2893 
2894  $othercom = $commande->liste_array(2, 1, null);
2895  if (is_array($othercom) && count($othercom)) {
2896  $html .= '<tr><td style="width: 200px;">';
2897  $html .= $langs->trans("AddToDraftOrders").'</td><td>';
2898  $html .= $form->selectarray("commandeid", $othercom, 0, 1);
2899  $html .= '</td></tr>';
2900  } else {
2901  $html .= '<tr><td style="width: 200px;">';
2902  $html .= $langs->trans("AddToDraftOrders").'</td><td>';
2903  $html .= $langs->trans("NoDraftOrders");
2904  $html .= '</td></tr>';
2905  }
2906  }
2907 
2908  // Factures
2909  if (isModEnabled('facture') && $user->rights->facture->creer) {
2910  $invoice = new Facture($db);
2911 
2912  $langs->load("bills");
2913 
2914  $otherinvoice = $invoice->liste_array(2, 1, null);
2915  if (is_array($otherinvoice) && count($otherinvoice)) {
2916  $html .= '<tr><td style="width: 200px;">';
2917  $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
2918  $html .= $form->selectarray("factureid", $otherinvoice, 0, 1);
2919  $html .= '</td></tr>';
2920  } else {
2921  $html .= '<tr><td style="width: 200px;">';
2922  $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
2923  $html .= $langs->trans("NoDraftInvoices");
2924  $html .= '</td></tr>';
2925  }
2926  }
2927 
2928  //If any text is going to be printed, then we show the table
2929  if (!empty($html)) {
2930  print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
2931  print '<input type="hidden" name="token" value="'.newToken().'">';
2932  print '<input type="hidden" name="action" value="addin">';
2933 
2934  print load_fiche_titre($langs->trans("AddToDraft"), '', '');
2935 
2936  print dol_get_fiche_head('');
2937 
2938  $html .= '<tr><td class="nowrap">'.$langs->trans("Quantity").' ';
2939  $html .= '<input type="text" class="flat" name="qty" size="1" value="1"></td>';
2940  $html .= '<td class="nowrap">'.$langs->trans("ReductionShort").'(%) ';
2941  $html .= '<input type="text" class="flat" name="remise_percent" size="1" value="0">';
2942  $html .= '</td></tr>';
2943 
2944  print '<table width="100%" class="border">';
2945  print $html;
2946  print '</table>';
2947 
2948  print '<div class="center">';
2949  print '<input type="submit" class="button button-add" value="'.$langs->trans("Add").'">';
2950  print '</div>';
2951 
2952  print dol_get_fiche_end();
2953 
2954  print '</form>';
2955  }
2956 }
2957 
2958 
2959 /*
2960  * Generated documents
2961  */
2962 
2963 if ($action != 'create' && $action != 'edit' && $action != 'delete') {
2964  print '<div class="fichecenter"><div class="fichehalfleft">';
2965  print '<a name="builddoc"></a>'; // ancre
2966 
2967  // Documents
2968  $objectref = dol_sanitizeFileName($object->ref);
2969  if (!empty($conf->product->multidir_output[$object->entity])) {
2970  $filedir = $conf->product->multidir_output[$object->entity].'/'.$objectref; //Check repertories of current entities
2971  } else {
2972  $filedir = $conf->product->dir_output.'/'.$objectref;
2973  }
2974  $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
2975  $genallowed = $usercanread;
2976  $delallowed = $usercancreate;
2977 
2978  print $formfile->showdocuments($modulepart, $object->ref, $filedir, $urlsource, $genallowed, $delallowed, '', 0, 0, 0, 28, 0, '', 0, '', $langs->getDefaultLang(), '', $object);
2979  $somethingshown = $formfile->numoffiles;
2980 
2981  print '</div><div class="fichehalfright">';
2982 
2983  $MAXEVENT = 10;
2984 
2985  $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/product/agenda.php?id='.$object->id);
2986 
2987  // List of actions on element
2988  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
2989  $formactions = new FormActions($db);
2990  $somethingshown = $formactions->showactions($object, 'product', 0, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for product
2991 
2992  print '</div></div>';
2993 }
2994 
2995 // End of page
2996 llxFooter();
2997 $db->close();
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save" &&empty($cancel)) $help_url
View.
Definition: agenda.php:118
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action=='set') elseif($action=='specimen') elseif($action=='setmodel') elseif($action=='del') elseif($action=='setdoc') $formactions
View.
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
Class to manage accounting accounts.
Class for BOM.
Definition: bom.class.php:37
Class to manage canvas.
Class to manage categories.
Class to manage customers orders.
Class to manage a WYSIWYG editor.
Class to manage warehouses.
Class to manage standard extra fields.
Class to manage invoices.
const TYPE_STANDARD
Standard invoice.
Class to manage generation of HTML components for accounting management.
Class to manage building of HTML components.
Class to manage barcode HTML.
Class to build HTML component for third parties management Only common components are here.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class of a generic business object.
Class ProductCombination Used to represent a product combination.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
File of class to manage predefined price products or services by customer.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
Class for Workstation.
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
$parameters
Actions.
Definition: card.php:79
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:745
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tabs of a record.
showValueWithClipboardCPButton($valuetocopy, $showonlyonhover=1, $texttoshow='')
Create a button to copy $valuetocopy in the clipboard (for copy and paste feature).
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
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.
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_set_focus($selector)
Set focus onto field with selector (similar behaviour of 'autofocus' HTML5 tag)
dol_print_url($url, $target='_blank', $max=32, $withpicto=0)
Show Url link.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Fonction qui renvoie si tva doit etre tva percue recuperable.
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...
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
if(!function_exists('utf8_encode')) if(!function_exists('utf8_decode')) getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
$formconfirm
if ($action == 'delbookkeepingyear') {
product_prepare_head($object)
Prepare array with list of tabs.
Definition: product.lib.php:35
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
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.