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