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