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