card.php 106 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629
  1. <?php
  2. /* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
  5. * Copyright (C) 2005-2015 Regis Houssin <regis.houssin@capnetworks.com>
  6. * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
  7. * Copyright (C) 2006 Auguria SARL <info@auguria.org>
  8. * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
  9. * Copyright (C) 2013-2016 Marcos García <marcosgdf@gmail.com>
  10. * Copyright (C) 2012-2013 Cédric Salvador <csalvador@gpcsolutions.fr>
  11. * Copyright (C) 2011-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
  12. * Copyright (C) 2014 Cédric Gross <c.gross@kreiz-it.fr>
  13. * Copyright (C) 2014-2015 Ferran Marcet <fmarcet@2byte.es>
  14. * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
  15. * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
  16. * Copyright (C) 2016 Charlie Benke <charlie@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-2021 Frédéric France <frederic.france@netlogic.fr>
  20. * Copyright (C) 2019-2020 Thibault FOUCART <support@ptibogxiv.net>
  21. * Copyright (C) 2020 Pierre Ardoin <mapiolca@me.com>
  22. *
  23. * This program is free software; you can redistribute it and/or modify
  24. * it under the terms of the GNU General Public License as published by
  25. * the Free Software Foundation; either version 3 of the License, or
  26. * (at your option) any later version.
  27. *
  28. * This program is distributed in the hope that it will be useful,
  29. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  31. * GNU General Public License for more details.
  32. *
  33. * You should have received a copy of the GNU General Public License
  34. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  35. */
  36. /**
  37. * \file htdocs/product/card.php
  38. * \ingroup product
  39. * \brief Page to show product
  40. */
  41. require '../main.inc.php';
  42. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
  43. require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
  44. require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
  45. require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
  46. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
  47. require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
  48. require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php';
  49. require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
  50. require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
  51. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  52. require_once DOL_DOCUMENT_ROOT.'/core/modules/product/modules_product.class.php';
  53. if (!empty($conf->propal->enabled)) {
  54. require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
  55. }
  56. if (!empty($conf->facture->enabled)) {
  57. require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
  58. }
  59. if (!empty($conf->commande->enabled)) {
  60. require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
  61. }
  62. if (!empty($conf->accounting->enabled)) {
  63. require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
  64. }
  65. if (!empty($conf->accounting->enabled)) {
  66. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
  67. }
  68. if (!empty($conf->accounting->enabled)) {
  69. require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
  70. }
  71. // Load translation files required by the page
  72. $langs->loadLangs(array('products', 'other'));
  73. if (!empty($conf->stock->enabled)) {
  74. $langs->load("stocks");
  75. }
  76. if (!empty($conf->facture->enabled)) {
  77. $langs->load("bills");
  78. }
  79. if (!empty($conf->productbatch->enabled)) {
  80. $langs->load("productbatch");
  81. }
  82. $mesg = ''; $error = 0; $errors = array();
  83. $refalreadyexists = 0;
  84. $id = GETPOST('id', 'int');
  85. $ref = GETPOST('ref', 'alpha');
  86. $type = (GETPOST('type', 'int') !== '') ? GETPOST('type', 'int') : Product::TYPE_PRODUCT;
  87. $action = (GETPOST('action', 'alpha') ? GETPOST('action', 'alpha') : 'view');
  88. $cancel = GETPOST('cancel', 'alpha');
  89. $backtopage = GETPOST('backtopage', 'alpha');
  90. $confirm = GETPOST('confirm', 'alpha');
  91. $socid = GETPOST('socid', 'int');
  92. $duration_value = GETPOST('duration_value', 'int');
  93. $duration_unit = GETPOST('duration_unit', 'alpha');
  94. $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
  95. $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
  96. $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
  97. $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
  98. $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
  99. $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
  100. // by default 'alphanohtml' (better security); hidden conf MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML allows basic html
  101. $label_security_check = empty($conf->global->MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML) ? 'alphanohtml' : 'restricthtml';
  102. if (!empty($user->socid)) {
  103. $socid = $user->socid;
  104. }
  105. $object = new Product($db);
  106. $object->type = $type; // so test later to fill $usercancxxx is correct
  107. $extrafields = new ExtraFields($db);
  108. // fetch optionals attributes and labels
  109. $extrafields->fetch_name_optionals_label($object->table_element);
  110. if ($id > 0 || !empty($ref)) {
  111. $result = $object->fetch($id, $ref);
  112. if (!empty($conf->product->enabled)) {
  113. $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 0, $object, 'product').dol_sanitizeFileName($object->ref);
  114. } elseif (!empty($conf->service->enabled)) {
  115. $upload_dir = $conf->service->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 0, $object, 'product').dol_sanitizeFileName($object->ref);
  116. }
  117. if (!empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) { // For backward compatiblity, we scan also old dirs
  118. if (!empty($conf->product->enabled)) {
  119. $upload_dirold = $conf->product->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos";
  120. } else {
  121. $upload_dirold = $conf->service->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos";
  122. }
  123. }
  124. }
  125. $modulepart = 'product';
  126. // Get object canvas (By default, this is not defined, so standard usage of dolibarr)
  127. $canvas = !empty($object->canvas) ? $object->canvas : GETPOST("canvas");
  128. $objcanvas = null;
  129. if (!empty($canvas)) {
  130. require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
  131. $objcanvas = new Canvas($db, $action);
  132. $objcanvas->getCanvas('product', 'card', $canvas);
  133. }
  134. // Security check
  135. $fieldvalue = (!empty($id) ? $id : (!empty($ref) ? $ref : ''));
  136. $fieldtype = (!empty($id) ? 'rowid' : 'ref');
  137. if ($object->id > 0) {
  138. if ($object->type == $object::TYPE_PRODUCT) {
  139. restrictedArea($user, 'produit', $object->id, 'product&product', '', '');
  140. }
  141. if ($object->type == $object::TYPE_SERVICE) {
  142. restrictedArea($user, 'service', $object->id, 'product&product', '', '');
  143. }
  144. } else {
  145. restrictedArea($user, 'produit|service', $fieldvalue, 'product&product', '', '', $fieldtype);
  146. }
  147. // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
  148. $hookmanager->initHooks(array('productcard', 'globalcard'));
  149. /*
  150. * Actions
  151. */
  152. if ($cancel) {
  153. $action = '';
  154. }
  155. $usercanread = (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->lire) || ($object->type == Product::TYPE_SERVICE && $user->rights->service->lire));
  156. $usercancreate = (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->creer) || ($object->type == Product::TYPE_SERVICE && $user->rights->service->creer));
  157. $usercandelete = (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->supprimer) || ($object->type == Product::TYPE_SERVICE && $user->rights->service->supprimer));
  158. $createbarcode = empty($conf->barcode->enabled) ? 0 : 1;
  159. if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->creer_advance)) {
  160. $createbarcode = 0;
  161. }
  162. $parameters = array('id'=>$id, 'ref'=>$ref, 'objcanvas'=>$objcanvas);
  163. $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  164. if ($reshook < 0) {
  165. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  166. }
  167. if (empty($reshook)) {
  168. // Type
  169. if ($action == 'setfk_product_type' && $usercancreate) {
  170. $result = $object->setValueFrom('fk_product_type', GETPOST('fk_product_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
  171. header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
  172. exit;
  173. }
  174. // Actions to build doc
  175. $upload_dir = $conf->product->dir_output;
  176. $permissiontoadd = $usercancreate;
  177. include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
  178. include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
  179. // Barcode type
  180. if ($action == 'setfk_barcode_type' && $createbarcode) {
  181. $result = $object->setValueFrom('fk_barcode_type', GETPOST('fk_barcode_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
  182. header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
  183. exit;
  184. }
  185. // Barcode value
  186. if ($action == 'setbarcode' && $createbarcode) {
  187. $result = $object->check_barcode(GETPOST('barcode'), GETPOST('barcode_type_code'));
  188. if ($result >= 0) {
  189. $result = $object->setValueFrom('barcode', GETPOST('barcode'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
  190. header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
  191. exit;
  192. } else {
  193. $langs->load("errors");
  194. if ($result == -1) {
  195. $errors[] = 'ErrorBadBarCodeSyntax';
  196. } elseif ($result == -2) {
  197. $errors[] = 'ErrorBarCodeRequired';
  198. } elseif ($result == -3) {
  199. $errors[] = 'ErrorBarCodeAlreadyUsed';
  200. } else {
  201. $errors[] = 'FailedToValidateBarCode';
  202. }
  203. $error++;
  204. setEventMessages($errors, null, 'errors');
  205. }
  206. }
  207. // Add a product or service
  208. if ($action == 'add' && $usercancreate) {
  209. $error = 0;
  210. if (!GETPOST('label', $label_security_check)) {
  211. setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Label')), null, 'errors');
  212. $action = "create";
  213. $error++;
  214. }
  215. if (empty($ref)) {
  216. setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Ref')), null, 'errors');
  217. $action = "create";
  218. $error++;
  219. }
  220. if (!empty($duration_value) && empty($duration_unit)) {
  221. setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Unit')), null, 'errors');
  222. $action = "create";
  223. $error++;
  224. }
  225. if (!$error) {
  226. $units = GETPOST('units', 'int');
  227. $object->ref = $ref;
  228. $object->label = GETPOST('label', $label_security_check);
  229. $object->price_base_type = GETPOST('price_base_type', 'aZ09');
  230. if ($object->price_base_type == 'TTC') {
  231. $object->price_ttc = GETPOST('price');
  232. } else {
  233. $object->price = GETPOST('price');
  234. }
  235. if ($object->price_base_type == 'TTC') {
  236. $object->price_min_ttc = GETPOST('price_min');
  237. } else {
  238. $object->price_min = GETPOST('price_min');
  239. }
  240. $tva_tx_txt = GETPOST('tva_tx', 'alpha'); // tva_tx can be '8.5' or '8.5*' or '8.5 (XXX)' or '8.5* (XXX)'
  241. // We must define tva_tx, npr and local taxes
  242. $vatratecode = '';
  243. $tva_tx = preg_replace('/[^0-9\.].*$/', '', $tva_tx_txt); // keep remove all after the numbers and dot
  244. $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
  245. $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0';
  246. // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes
  247. $reg = array();
  248. if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) {
  249. // 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.
  250. $vatratecode = $reg[1];
  251. // Get record from code
  252. $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
  253. $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
  254. $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
  255. $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
  256. $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
  257. $resql = $db->query($sql);
  258. if ($resql) {
  259. $obj = $db->fetch_object($resql);
  260. $npr = $obj->recuperableonly;
  261. $localtax1 = $obj->localtax1;
  262. $localtax2 = $obj->localtax2;
  263. $localtax1_type = $obj->localtax1_type;
  264. $localtax2_type = $obj->localtax2_type;
  265. }
  266. }
  267. $object->default_vat_code = $vatratecode;
  268. $object->tva_tx = $tva_tx;
  269. $object->tva_npr = $npr;
  270. $object->localtax1_tx = $localtax1;
  271. $object->localtax2_tx = $localtax2;
  272. $object->localtax1_type = $localtax1_type;
  273. $object->localtax2_type = $localtax2_type;
  274. $object->type = $type;
  275. $object->status = GETPOST('statut');
  276. $object->status_buy = GETPOST('statut_buy');
  277. $object->status_batch = GETPOST('status_batch');
  278. $object->batch_mask = GETPOST('batch_mask');
  279. $object->barcode_type = GETPOST('fk_barcode_type');
  280. $object->barcode = GETPOST('barcode');
  281. // Set barcode_type_xxx from barcode_type id
  282. $stdobject = new GenericObject($db);
  283. $stdobject->element = 'product';
  284. $stdobject->barcode_type = GETPOST('fk_barcode_type');
  285. $result = $stdobject->fetch_barcode();
  286. if ($result < 0) {
  287. $error++;
  288. $mesg = 'Failed to get bar code type information ';
  289. setEventMessages($mesg.$stdobject->error, $mesg.$stdobject->errors, 'errors');
  290. }
  291. $object->barcode_type_code = $stdobject->barcode_type_code;
  292. $object->barcode_type_coder = $stdobject->barcode_type_coder;
  293. $object->barcode_type_label = $stdobject->barcode_type_label;
  294. $object->description = dol_htmlcleanlastbr(GETPOST('desc', 'restricthtml'));
  295. $object->url = GETPOST('url');
  296. $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private', 'restricthtml'));
  297. $object->note = $object->note_private; // deprecated
  298. $object->customcode = GETPOST('customcode', 'alphanohtml');
  299. $object->country_id = GETPOST('country_id', 'int');
  300. $object->state_id = GETPOST('state_id', 'int');
  301. $object->lifetime = GETPOST('lifetime', 'int');
  302. $object->qc_frequency = GETPOST('qc_frequency', 'int');
  303. $object->duration_value = $duration_value;
  304. $object->duration_unit = $duration_unit;
  305. $object->fk_default_warehouse = GETPOST('fk_default_warehouse');
  306. $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte') ?GETPOST('seuil_stock_alerte') : 0;
  307. $object->desiredstock = GETPOST('desiredstock') ?GETPOST('desiredstock') : 0;
  308. $object->canvas = GETPOST('canvas');
  309. $object->net_measure = GETPOST('net_measure');
  310. $object->net_measure_units = GETPOST('net_measure_units'); // This is not the fk_unit but the power of unit
  311. $object->weight = GETPOST('weight');
  312. $object->weight_units = GETPOST('weight_units'); // This is not the fk_unit but the power of unit
  313. $object->length = GETPOST('size');
  314. $object->length_units = GETPOST('size_units'); // This is not the fk_unit but the power of unit
  315. $object->width = GETPOST('sizewidth');
  316. $object->height = GETPOST('sizeheight');
  317. $object->surface = GETPOST('surface');
  318. $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit
  319. $object->volume = GETPOST('volume');
  320. $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit
  321. $finished = GETPOST('finished', 'int');
  322. if ($finished > 0) {
  323. $object->finished = $finished;
  324. } else {
  325. $object->finished = null;
  326. }
  327. $units = GETPOST('units', 'int');
  328. if ($units > 0) {
  329. $object->fk_unit = $units;
  330. } else {
  331. $object->fk_unit = null;
  332. }
  333. $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
  334. $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
  335. $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
  336. $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
  337. $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
  338. $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
  339. if (empty($accountancy_code_sell) || $accountancy_code_sell == '-1') {
  340. $object->accountancy_code_sell = '';
  341. } else {
  342. $object->accountancy_code_sell = $accountancy_code_sell;
  343. }
  344. if (empty($accountancy_code_sell_intra) || $accountancy_code_sell_intra == '-1') {
  345. $object->accountancy_code_sell_intra = '';
  346. } else {
  347. $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
  348. }
  349. if (empty($accountancy_code_sell_export) || $accountancy_code_sell_export == '-1') {
  350. $object->accountancy_code_sell_export = '';
  351. } else {
  352. $object->accountancy_code_sell_export = $accountancy_code_sell_export;
  353. }
  354. if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') {
  355. $object->accountancy_code_buy = '';
  356. } else {
  357. $object->accountancy_code_buy = $accountancy_code_buy;
  358. }
  359. if (empty($accountancy_code_buy_intra) || $accountancy_code_buy_intra == '-1') {
  360. $object->accountancy_code_buy_intra = '';
  361. } else {
  362. $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
  363. }
  364. if (empty($accountancy_code_buy_export) || $accountancy_code_buy_export == '-1') {
  365. $object->accountancy_code_buy_export = '';
  366. } else {
  367. $object->accountancy_code_buy_export = $accountancy_code_buy_export;
  368. }
  369. // MultiPrix
  370. if (!empty($conf->global->PRODUIT_MULTIPRICES)) {
  371. for ($i = 2; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
  372. if (GETPOSTISSET("price_".$i)) {
  373. $object->multiprices["$i"] = price2num(GETPOST("price_".$i), 'MU');
  374. $object->multiprices_base_type["$i"] = GETPOST("multiprices_base_type_".$i);
  375. } else {
  376. $object->multiprices["$i"] = "";
  377. }
  378. }
  379. }
  380. // Fill array 'array_options' with data from add form
  381. $ret = $extrafields->setOptionalsFromPost(null, $object);
  382. if ($ret < 0) {
  383. $error++;
  384. }
  385. if (!$error) {
  386. $id = $object->create($user);
  387. }
  388. if ($id > 0) {
  389. // Category association
  390. $categories = GETPOST('categories', 'array');
  391. $object->setCategories($categories);
  392. if (!empty($backtopage)) {
  393. $backtopage = preg_replace('/--IDFORBACKTOPAGE--/', $object->id, $backtopage); // New method to autoselect project after a New on another form object creation
  394. if (preg_match('/\?/', $backtopage)) {
  395. $backtopage .= '&socid='.$object->id; // Old method
  396. }
  397. header("Location: ".$backtopage);
  398. exit;
  399. } else {
  400. header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
  401. exit;
  402. }
  403. } else {
  404. if (count($object->errors)) {
  405. setEventMessages($object->error, $object->errors, 'errors');
  406. } else {
  407. setEventMessages($langs->trans($object->error), null, 'errors');
  408. }
  409. $action = "create";
  410. }
  411. }
  412. }
  413. // Update a product or service
  414. if ($action == 'update' && $usercancreate) {
  415. if (GETPOST('cancel', 'alpha')) {
  416. $action = '';
  417. } else {
  418. if ($object->id > 0) {
  419. $object->oldcopy = clone $object;
  420. $object->ref = $ref;
  421. $object->label = GETPOST('label', $label_security_check);
  422. $desc = dol_htmlcleanlastbr(preg_replace('/&nbsp;$/', '', GETPOST('desc', 'restricthtml')));
  423. $object->description = $desc;
  424. $object->url = GETPOST('url');
  425. if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
  426. $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private', 'restricthtml'));
  427. $object->note = $object->note_private;
  428. }
  429. $object->customcode = GETPOST('customcode', 'alpha');
  430. $object->country_id = GETPOST('country_id', 'int');
  431. $object->state_id = GETPOST('state_id', 'int');
  432. $object->lifetime = GETPOST('lifetime', 'int');
  433. $object->qc_frequency = GETPOST('qc_frequency', 'int');
  434. $object->status = GETPOST('statut', 'int');
  435. $object->status_buy = GETPOST('statut_buy', 'int');
  436. $object->status_batch = GETPOST('status_batch', 'aZ09');
  437. $object->batch_mask = GETPOST('batch_mask', 'alpha');
  438. $object->fk_default_warehouse = GETPOST('fk_default_warehouse');
  439. // removed from update view so GETPOST always empty
  440. /*
  441. $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte');
  442. $object->desiredstock = GETPOST('desiredstock');
  443. */
  444. $object->duration_value = GETPOST('duration_value', 'int');
  445. $object->duration_unit = GETPOST('duration_unit', 'alpha');
  446. $object->canvas = GETPOST('canvas');
  447. $object->net_measure = GETPOST('net_measure');
  448. $object->net_measure_units = GETPOST('net_measure_units'); // This is not the fk_unit but the power of unit
  449. $object->weight = GETPOST('weight');
  450. $object->weight_units = GETPOST('weight_units'); // This is not the fk_unit but the power of unit
  451. $object->length = GETPOST('size');
  452. $object->length_units = GETPOST('size_units'); // This is not the fk_unit but the power of unit
  453. $object->width = GETPOST('sizewidth');
  454. $object->height = GETPOST('sizeheight');
  455. $object->surface = GETPOST('surface');
  456. $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit
  457. $object->volume = GETPOST('volume');
  458. $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit
  459. $finished = GETPOST('finished', 'int');
  460. if ($finished >= 0) {
  461. $object->finished = $finished;
  462. } else {
  463. $object->finished = null;
  464. }
  465. $units = GETPOST('units', 'int');
  466. if ($units > 0) {
  467. $object->fk_unit = $units;
  468. } else {
  469. $object->fk_unit = null;
  470. }
  471. $object->barcode_type = GETPOST('fk_barcode_type');
  472. $object->barcode = GETPOST('barcode');
  473. // Set barcode_type_xxx from barcode_type id
  474. $stdobject = new GenericObject($db);
  475. $stdobject->element = 'product';
  476. $stdobject->barcode_type = GETPOST('fk_barcode_type');
  477. $result = $stdobject->fetch_barcode();
  478. if ($result < 0) {
  479. $error++;
  480. $mesg = 'Failed to get bar code type information ';
  481. setEventMessages($mesg.$stdobject->error, $mesg.$stdobject->errors, 'errors');
  482. }
  483. $object->barcode_type_code = $stdobject->barcode_type_code;
  484. $object->barcode_type_coder = $stdobject->barcode_type_coder;
  485. $object->barcode_type_label = $stdobject->barcode_type_label;
  486. $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
  487. $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
  488. $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
  489. $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
  490. $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
  491. $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
  492. if (empty($accountancy_code_sell) || $accountancy_code_sell == '-1') {
  493. $object->accountancy_code_sell = '';
  494. } else {
  495. $object->accountancy_code_sell = $accountancy_code_sell;
  496. }
  497. if (empty($accountancy_code_sell_intra) || $accountancy_code_sell_intra == '-1') {
  498. $object->accountancy_code_sell_intra = '';
  499. } else {
  500. $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
  501. }
  502. if (empty($accountancy_code_sell_export) || $accountancy_code_sell_export == '-1') {
  503. $object->accountancy_code_sell_export = '';
  504. } else {
  505. $object->accountancy_code_sell_export = $accountancy_code_sell_export;
  506. }
  507. if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') {
  508. $object->accountancy_code_buy = '';
  509. } else {
  510. $object->accountancy_code_buy = $accountancy_code_buy;
  511. }
  512. if (empty($accountancy_code_buy_intra) || $accountancy_code_buy_intra == '-1') {
  513. $object->accountancy_code_buy_intra = '';
  514. } else {
  515. $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
  516. }
  517. if (empty($accountancy_code_buy_export) || $accountancy_code_buy_export == '-1') {
  518. $object->accountancy_code_buy_export = '';
  519. } else {
  520. $object->accountancy_code_buy_export = $accountancy_code_buy_export;
  521. }
  522. // Fill array 'array_options' with data from add form
  523. $ret = $extrafields->setOptionalsFromPost(null, $object, '@GETPOSTISSET');
  524. if ($ret < 0) {
  525. $error++;
  526. }
  527. if (!$error && $object->check()) {
  528. if ($object->update($object->id, $user) > 0) {
  529. // Category association
  530. $categories = GETPOST('categories', 'array');
  531. $object->setCategories($categories);
  532. $action = 'view';
  533. } else {
  534. if (count($object->errors)) {
  535. setEventMessages($object->error, $object->errors, 'errors');
  536. } else {
  537. setEventMessages($langs->trans($object->error), null, 'errors');
  538. }
  539. $action = 'edit';
  540. }
  541. } else {
  542. if (count($object->errors)) {
  543. setEventMessages($object->error, $object->errors, 'errors');
  544. } else {
  545. setEventMessages($langs->trans("ErrorProductBadRefOrLabel"), null, 'errors');
  546. }
  547. $action = 'edit';
  548. }
  549. }
  550. }
  551. }
  552. // Action clone object
  553. if ($action == 'confirm_clone' && $confirm != 'yes') {
  554. $action = '';
  555. }
  556. if ($action == 'confirm_clone' && $confirm == 'yes' && $usercancreate) {
  557. if (!GETPOST('clone_content') && !GETPOST('clone_prices')) {
  558. setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors');
  559. } else {
  560. $db->begin();
  561. $originalId = $id;
  562. if ($object->id > 0) {
  563. $object->ref = GETPOST('clone_ref', 'alphanohtml');
  564. $object->status = 0;
  565. $object->status_buy = 0;
  566. $object->id = null;
  567. $object->barcode = -1;
  568. if ($object->check()) {
  569. $object->context['createfromclone'] = 'createfromclone';
  570. $id = $object->create($user);
  571. if ($id > 0) {
  572. if (GETPOST('clone_composition')) {
  573. $result = $object->clone_associations($originalId, $id);
  574. if ($result < 1) {
  575. $db->rollback();
  576. setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
  577. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$originalId);
  578. exit;
  579. }
  580. }
  581. if (GETPOST('clone_categories')) {
  582. $result = $object->cloneCategories($originalId, $id);
  583. if ($result < 1) {
  584. $db->rollback();
  585. setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
  586. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$originalId);
  587. exit;
  588. }
  589. }
  590. if (GETPOST('clone_prices')) {
  591. $result = $object->clone_price($originalId, $id);
  592. if ($result < 1) {
  593. $db->rollback();
  594. setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
  595. header('Location: '.$_SERVER['PHP_SELF'].'?id='.$originalId);
  596. exit();
  597. }
  598. }
  599. // $object->clone_fournisseurs($originalId, $id);
  600. $db->commit();
  601. $db->close();
  602. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  603. exit;
  604. } else {
  605. $id = $originalId;
  606. if ($object->error == 'ErrorProductAlreadyExists') {
  607. $db->rollback();
  608. $refalreadyexists++;
  609. $action = "";
  610. $mesg = $langs->trans("ErrorProductAlreadyExists", $object->ref);
  611. $mesg .= ' <a href="'.$_SERVER["PHP_SELF"].'?ref='.$object->ref.'">'.$langs->trans("ShowCardHere").'</a>.';
  612. setEventMessages($mesg, null, 'errors');
  613. $object->fetch($id);
  614. } else {
  615. $db->rollback();
  616. if (count($object->errors)) {
  617. setEventMessages($object->error, $object->errors, 'errors');
  618. dol_print_error($db, $object->errors);
  619. } else {
  620. setEventMessages($langs->trans($object->error), null, 'errors');
  621. dol_print_error($db, $object->error);
  622. }
  623. }
  624. }
  625. unset($object->context['createfromclone']);
  626. }
  627. } else {
  628. $db->rollback();
  629. dol_print_error($db, $object->error);
  630. }
  631. }
  632. }
  633. // Delete a product
  634. if ($action == 'confirm_delete' && $confirm != 'yes') {
  635. $action = '';
  636. }
  637. if ($action == 'confirm_delete' && $confirm == 'yes' && $usercandelete) {
  638. $result = $object->delete($user);
  639. if ($result > 0) {
  640. header('Location: '.DOL_URL_ROOT.'/product/list.php?type='.$object->type.'&delprod='.urlencode($object->ref));
  641. exit;
  642. } else {
  643. setEventMessages($langs->trans($object->error), null, 'errors');
  644. $reload = 0;
  645. $action = '';
  646. }
  647. }
  648. // Add product into object
  649. if ($object->id > 0 && $action == 'addin') {
  650. $thirpdartyid = 0;
  651. if (GETPOST('propalid') > 0) {
  652. $propal = new Propal($db);
  653. $result = $propal->fetch(GETPOST('propalid'));
  654. if ($result <= 0) {
  655. dol_print_error($db, $propal->error);
  656. exit;
  657. }
  658. $thirpdartyid = $propal->socid;
  659. } elseif (GETPOST('commandeid') > 0) {
  660. $commande = new Commande($db);
  661. $result = $commande->fetch(GETPOST('commandeid'));
  662. if ($result <= 0) {
  663. dol_print_error($db, $commande->error);
  664. exit;
  665. }
  666. $thirpdartyid = $commande->socid;
  667. } elseif (GETPOST('factureid') > 0) {
  668. $facture = new Facture($db);
  669. $result = $facture->fetch(GETPOST('factureid'));
  670. if ($result <= 0) {
  671. dol_print_error($db, $facture->error);
  672. exit;
  673. }
  674. $thirpdartyid = $facture->socid;
  675. }
  676. if ($thirpdartyid > 0) {
  677. $soc = new Societe($db);
  678. $result = $soc->fetch($thirpdartyid);
  679. if ($result <= 0) {
  680. dol_print_error($db, $soc->error);
  681. exit;
  682. }
  683. $desc = $object->description;
  684. $tva_tx = get_default_tva($mysoc, $soc, $object->id);
  685. $tva_npr = get_default_npr($mysoc, $soc, $object->id);
  686. if (empty($tva_tx)) {
  687. $tva_npr = 0;
  688. }
  689. $localtax1_tx = get_localtax($tva_tx, 1, $soc, $mysoc, $tva_npr);
  690. $localtax2_tx = get_localtax($tva_tx, 2, $soc, $mysoc, $tva_npr);
  691. $pu_ht = $object->price;
  692. $pu_ttc = $object->price_ttc;
  693. $price_base_type = $object->price_base_type;
  694. // If multiprice
  695. if ($conf->global->PRODUIT_MULTIPRICES && $soc->price_level) {
  696. $pu_ht = $object->multiprices[$soc->price_level];
  697. $pu_ttc = $object->multiprices_ttc[$soc->price_level];
  698. $price_base_type = $object->multiprices_base_type[$soc->price_level];
  699. } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
  700. require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
  701. $prodcustprice = new Productcustomerprice($db);
  702. $filter = array('t.fk_product' => $object->id, 't.fk_soc' => $soc->id);
  703. $result = $prodcustprice->fetch_all('', '', 0, 0, $filter);
  704. if ($result) {
  705. if (count($prodcustprice->lines) > 0) {
  706. $pu_ht = price($prodcustprice->lines [0]->price);
  707. $pu_ttc = price($prodcustprice->lines [0]->price_ttc);
  708. $price_base_type = $prodcustprice->lines [0]->price_base_type;
  709. $tva_tx = $prodcustprice->lines [0]->tva_tx;
  710. }
  711. }
  712. }
  713. $tmpvat = price2num(preg_replace('/\s*\(.*\)/', '', $tva_tx));
  714. $tmpprodvat = price2num(preg_replace('/\s*\(.*\)/', '', $prod->tva_tx));
  715. // On reevalue prix selon taux tva car taux tva transaction peut etre different
  716. // de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur).
  717. if ($tmpvat != $tmpprodvat) {
  718. if ($price_base_type != 'HT') {
  719. $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
  720. } else {
  721. $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
  722. }
  723. }
  724. if (GETPOST('propalid') > 0) {
  725. // Define cost price for margin calculation
  726. $buyprice = 0;
  727. if (($result = $propal->defineBuyPrice($pu_ht, price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
  728. dol_syslog($langs->trans('FailedToGetCostPrice'));
  729. setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
  730. } else {
  731. $buyprice = $result;
  732. }
  733. $result = $propal->addline(
  734. $desc,
  735. $pu_ht,
  736. price2num(GETPOST('qty'), 'MS'),
  737. $tva_tx,
  738. $localtax1_tx, // localtax1
  739. $localtax2_tx, // localtax2
  740. $object->id,
  741. price2num(GETPOST('remise_percent'), '', 2),
  742. $price_base_type,
  743. $pu_ttc,
  744. 0,
  745. 0,
  746. -1,
  747. 0,
  748. 0,
  749. 0,
  750. $buyprice,
  751. '',
  752. '',
  753. '',
  754. 0,
  755. $object->fk_unit
  756. );
  757. if ($result > 0) {
  758. header("Location: ".DOL_URL_ROOT."/comm/propal/card.php?id=".$propal->id);
  759. return;
  760. }
  761. setEventMessages($langs->trans("ErrorUnknown").": $result", null, 'errors');
  762. } elseif (GETPOST('commandeid') > 0) {
  763. // Define cost price for margin calculation
  764. $buyprice = 0;
  765. if (($result = $commande->defineBuyPrice($pu_ht, price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
  766. dol_syslog($langs->trans('FailedToGetCostPrice'));
  767. setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
  768. } else {
  769. $buyprice = $result;
  770. }
  771. $result = $commande->addline(
  772. $desc,
  773. $pu_ht,
  774. price2num(GETPOST('qty'), 'MS'),
  775. $tva_tx,
  776. $localtax1_tx, // localtax1
  777. $localtax2_tx, // localtax2
  778. $object->id,
  779. price2num(GETPOST('remise_percent'), '', 2),
  780. '',
  781. '',
  782. $price_base_type,
  783. $pu_ttc,
  784. '',
  785. '',
  786. 0,
  787. -1,
  788. 0,
  789. 0,
  790. null,
  791. $buyprice,
  792. '',
  793. 0,
  794. $object->fk_unit
  795. );
  796. if ($result > 0) {
  797. header("Location: ".DOL_URL_ROOT."/commande/card.php?id=".urlencode($commande->id));
  798. exit;
  799. }
  800. } elseif (GETPOST('factureid') > 0) {
  801. // Define cost price for margin calculation
  802. $buyprice = 0;
  803. if (($result = $facture->defineBuyPrice($pu_ht, price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
  804. dol_syslog($langs->trans('FailedToGetCostPrice'));
  805. setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
  806. } else {
  807. $buyprice = $result;
  808. }
  809. $result = $facture->addline(
  810. $desc,
  811. $pu_ht,
  812. price2num(GETPOST('qty'), 'MS'),
  813. $tva_tx,
  814. $localtax1_tx,
  815. $localtax2_tx,
  816. $object->id,
  817. price2num(GETPOST('remise_percent'), '', 2),
  818. '',
  819. '',
  820. '',
  821. '',
  822. '',
  823. $price_base_type,
  824. $pu_ttc,
  825. Facture::TYPE_STANDARD,
  826. -1,
  827. 0,
  828. '',
  829. 0,
  830. 0,
  831. null,
  832. $buyprice,
  833. '',
  834. 0,
  835. 100,
  836. '',
  837. $object->fk_unit
  838. );
  839. if ($result > 0) {
  840. header("Location: ".DOL_URL_ROOT."/compta/facture/card.php?facid=".$facture->id);
  841. exit;
  842. }
  843. }
  844. } else {
  845. $action = "";
  846. setEventMessages($langs->trans("WarningSelectOneDocument"), null, 'warnings');
  847. }
  848. }
  849. }
  850. /*
  851. * View
  852. */
  853. $form = new Form($db);
  854. $formfile = new FormFile($db);
  855. $formproduct = new FormProduct($db);
  856. $formcompany = new FormCompany($db);
  857. if (!empty($conf->accounting->enabled)) {
  858. $formaccounting = new FormAccounting($db);
  859. }
  860. $title = $langs->trans('ProductServiceCard');
  861. $help_url = '';
  862. $shortlabel = dol_trunc($object->label, 16);
  863. if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT)) {
  864. $title = $langs->trans('Product')." ".$shortlabel." - ".$langs->trans('Card');
  865. $help_url = 'EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos|DE:Modul_Produkte';
  866. }
  867. if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE)) {
  868. $title = $langs->trans('Service')." ".$shortlabel." - ".$langs->trans('Card');
  869. $help_url = 'EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios|DE:Modul_Leistungen';
  870. }
  871. llxHeader('', $title, $help_url);
  872. // Load object modBarCodeProduct
  873. $res = 0;
  874. if (!empty($conf->barcode->enabled) && !empty($conf->global->BARCODE_PRODUCT_ADDON_NUM)) {
  875. $module = strtolower($conf->global->BARCODE_PRODUCT_ADDON_NUM);
  876. $dirbarcode = array_merge(array('/core/modules/barcode/'), $conf->modules_parts['barcode']);
  877. foreach ($dirbarcode as $dirroot) {
  878. $res = dol_include_once($dirroot.$module.'.php');
  879. if ($res) {
  880. break;
  881. }
  882. }
  883. if ($res > 0) {
  884. $modBarCodeProduct = new $module();
  885. }
  886. }
  887. if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
  888. // -----------------------------------------
  889. // When used with CANVAS
  890. // -----------------------------------------
  891. if (empty($object->error) && $id) {
  892. $result = $object->fetch($id);
  893. if ($result <= 0) {
  894. dol_print_error('', $object->error);
  895. }
  896. }
  897. $objcanvas->assign_values($action, $object->id, $object->ref); // Set value for templates
  898. $objcanvas->display_canvas($action); // Show template
  899. } else {
  900. // -----------------------------------------
  901. // When used in standard mode
  902. // -----------------------------------------
  903. if ($action == 'create' && $usercancreate) {
  904. //WYSIWYG Editor
  905. require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  906. if (!empty($conf->use_javascript_ajax)) {
  907. print '<script type="text/javascript">';
  908. print '$(document).ready(function () {
  909. $("#selectcountry_id").change(function() {
  910. document.formprod.action.value="create";
  911. document.formprod.submit();
  912. });
  913. });';
  914. print '</script>'."\n";
  915. }
  916. // Load object modCodeProduct
  917. $module = (!empty($conf->global->PRODUCT_CODEPRODUCT_ADDON) ? $conf->global->PRODUCT_CODEPRODUCT_ADDON : 'mod_codeproduct_leopard');
  918. if (substr($module, 0, 16) == 'mod_codeproduct_' && substr($module, -3) == 'php') {
  919. $module = substr($module, 0, dol_strlen($module) - 4);
  920. }
  921. $result = dol_include_once('/core/modules/product/'.$module.'.php');
  922. if ($result > 0) {
  923. $modCodeProduct = new $module();
  924. }
  925. dol_set_focus('input[name="ref"]');
  926. print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formprod">';
  927. print '<input type="hidden" name="token" value="'.newToken().'">';
  928. print '<input type="hidden" name="action" value="add">';
  929. print '<input type="hidden" name="type" value="'.$type.'">'."\n";
  930. if (!empty($modCodeProduct->code_auto)) {
  931. print '<input type="hidden" name="code_auto" value="1">';
  932. }
  933. if (!empty($modBarCodeProduct->code_auto)) {
  934. print '<input type="hidden" name="barcode_auto" value="1">';
  935. }
  936. print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
  937. if ($type == 1) {
  938. $picto = 'service';
  939. $title = $langs->trans("NewService");
  940. } else {
  941. $picto = 'product';
  942. $title = $langs->trans("NewProduct");
  943. }
  944. $linkback = "";
  945. print load_fiche_titre($title, $linkback, $picto);
  946. // We set country_id, country_code and country for the selected country
  947. $object->country_id = GETPOSTISSET('country_id') ? GETPOST('country_id', 'int') : null;
  948. if ($object->country_id > 0) {
  949. $tmparray = getCountry($object->country_id, 'all');
  950. $object->country_code = $tmparray['code'];
  951. $object->country = $tmparray['label'];
  952. }
  953. print dol_get_fiche_head('');
  954. print '<table class="border centpercent">';
  955. print '<tr>';
  956. $tmpcode = '';
  957. if (!empty($modCodeProduct->code_auto)) {
  958. $tmpcode = $modCodeProduct->getNextValue($object, $type);
  959. }
  960. print '<td class="titlefieldcreate fieldrequired">'.$langs->trans("Ref").'</td><td><input id="ref" name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag(GETPOSTISSET('ref') ? GETPOST('ref', 'alphanohtml') : $tmpcode).'">';
  961. if ($refalreadyexists) {
  962. print $langs->trans("RefAlreadyExists");
  963. }
  964. print '</td></tr>';
  965. // Label
  966. 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>';
  967. // On sell
  968. print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td>';
  969. $statutarray = array('1' => $langs->trans("OnSell"), '0' => $langs->trans("NotOnSell"));
  970. print $form->selectarray('statut', $statutarray, GETPOST('statut'));
  971. print '</td></tr>';
  972. // To buy
  973. print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td>';
  974. $statutarray = array('1' => $langs->trans("ProductStatusOnBuy"), '0' => $langs->trans("ProductStatusNotOnBuy"));
  975. print $form->selectarray('statut_buy', $statutarray, GETPOST('statut_buy'));
  976. print '</td></tr>';
  977. // Batch number management
  978. if (!empty($conf->productbatch->enabled)) {
  979. print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
  980. $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial"));
  981. print $form->selectarray('status_batch', $statutarray, GETPOST('status_batch'));
  982. print '</td></tr>';
  983. // Product specific batch number management
  984. $status_batch = GETPOST('status_batch');
  985. if ($status_batch !== '0') {
  986. $langs->load("admin");
  987. $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
  988. $tooltip .= '<br>'.$langs->trans("GenericMaskCodes2");
  989. $tooltip .= '<br>'.$langs->trans("GenericMaskCodes3");
  990. $tooltip .= '<br>'.$langs->trans("GenericMaskCodes4a", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
  991. $tooltip .= '<br>'.$langs->trans("GenericMaskCodes5");
  992. if (($conf->global->PRODUCTBATCH_LOT_USE_PRODUCT_MASKS && $conf->global->PRODUCTBATCH_LOT_ADDON == 'mod_lot_advanced')
  993. || ($conf->global->PRODUCTBATCH_SN_USE_PRODUCT_MASKS && $conf->global->PRODUCTBATCH_SN_ADDON == 'mod_sn_advanced')) {
  994. print '<tr><td id="mask_option">'.$langs->trans("ManageLotMask").'</td>';
  995. $inherited_mask_lot = $conf->global->LOT_ADVANCED_MASK;
  996. $inherited_mask_sn = $conf->global->SN_ADVANCED_MASK;
  997. print '<td id="field_mask">';
  998. print $form->textwithpicto('<input type="text" class="flat minwidth175" name="batch_mask" id="batch_mask_input">', $tooltip, 1, 1);
  999. print '<script type="text/javascript">
  1000. $(document).ready(function() {
  1001. $("#field_mask, #mask_option").addClass("hideobject");
  1002. $("#status_batch").on("change", function () {
  1003. console.log("We change batch status");
  1004. var optionSelected = $("option:selected", this);
  1005. var valueSelected = this.value;
  1006. $("#field_mask, #mask_option").addClass("hideobject");
  1007. ';
  1008. if ($conf->global->PRODUCTBATCH_LOT_USE_PRODUCT_MASKS && $conf->global->PRODUCTBATCH_LOT_ADDON == 'mod_lot_advanced') {
  1009. print '
  1010. if (this.value == 1) {
  1011. $("#field_mask, #mask_option").toggleClass("hideobject");
  1012. $("#batch_mask_input").val("'.$inherited_mask_lot.'");
  1013. }
  1014. ';
  1015. }
  1016. if ($conf->global->PRODUCTBATCH_SN_USE_PRODUCT_MASKS && $conf->global->PRODUCTBATCH_SN_ADDON == 'mod_sn_advanced') {
  1017. print '
  1018. if (this.value == 2) {
  1019. $("#field_mask, #mask_option").toggleClass("hideobject");
  1020. $("#batch_mask_input").val("'.$inherited_mask_sn.'");
  1021. }
  1022. ';
  1023. }
  1024. print '
  1025. })
  1026. })
  1027. </script>';
  1028. print '</td></tr>';
  1029. }
  1030. }
  1031. }
  1032. $showbarcode = empty($conf->barcode->enabled) ? 0 : 1;
  1033. if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
  1034. $showbarcode = 0;
  1035. }
  1036. if ($showbarcode) {
  1037. print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
  1038. if (GETPOSTISSET('fk_barcode_type')) {
  1039. $fk_barcode_type = GETPOST('fk_barcode_type');
  1040. } else {
  1041. if (empty($fk_barcode_type) && !empty($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE)) {
  1042. $fk_barcode_type = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
  1043. }
  1044. }
  1045. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
  1046. $formbarcode = new FormBarCode($db);
  1047. print $formbarcode->selectBarcodeType($fk_barcode_type, 'fk_barcode_type', 1);
  1048. print '</td>';
  1049. print '</tr><tr>';
  1050. print '<td>'.$langs->trans("BarcodeValue").'</td><td>';
  1051. $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
  1052. if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
  1053. $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
  1054. }
  1055. print '<input class="maxwidth100" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
  1056. print '</td></tr>';
  1057. }
  1058. // Description (used in invoice, propal...)
  1059. print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
  1060. $doleditor = new DolEditor('desc', GETPOST('desc', 'restricthtml'), '', 160, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, ROWS_4, '90%');
  1061. $doleditor->Create();
  1062. print "</td></tr>";
  1063. if (empty($conf->global->PRODUCT_DISABLE_PUBLIC_URL)) {
  1064. // Public URL
  1065. print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
  1066. print img_picto('', 'globe', 'class="pictofixedwidth"');
  1067. print '<input type="text" name="url" class="quatrevingtpercent" value="'.GETPOST('url').'">';
  1068. print '</td></tr>';
  1069. }
  1070. if ($type != 1 && !empty($conf->stock->enabled)) {
  1071. // Default warehouse
  1072. print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
  1073. print img_picto($langs->trans("DefaultWarehouse"), 'stock', 'class="pictofixedwidth"');
  1074. print $formproduct->selectWarehouses(GETPOST('fk_default_warehouse', 'int'), 'fk_default_warehouse', 'warehouseopen', 1, 0, 0, '', 0, 0, array(), 'minwidth300 widthcentpercentminusxx maxwidth500');
  1075. print ' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create&amp;backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$object->id.'&action=edit').'">';
  1076. print '<span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddWarehouse").'"></span>';
  1077. print '</a>';
  1078. print '</td>';
  1079. print '</tr>';
  1080. if (empty($conf->global->PRODUCT_DISABLE_STOCK_LEVELS)) {
  1081. // Stock min level
  1082. print '<tr><td>'.$form->textwithpicto($langs->trans("StockLimit"), $langs->trans("StockLimitDesc"), 1).'</td><td>';
  1083. print '<input name="seuil_stock_alerte" class="maxwidth50" value="'.GETPOST('seuil_stock_alerte').'">';
  1084. print '</td>';
  1085. print '</tr>';
  1086. // Stock desired level
  1087. print '<tr><td>'.$form->textwithpicto($langs->trans("DesiredStock"), $langs->trans("DesiredStockDesc"), 1).'</td><td>';
  1088. print '<input name="desiredstock" class="maxwidth50" value="'.GETPOST('desiredstock').'">';
  1089. print '</td></tr>';
  1090. }
  1091. } else {
  1092. if (empty($conf->global->PRODUCT_DISABLE_STOCK_LEVELS)) {
  1093. print '<input name="seuil_stock_alerte" type="hidden" value="0">';
  1094. print '<input name="desiredstock" type="hidden" value="0">';
  1095. }
  1096. }
  1097. // Duration
  1098. if ($type == 1) {
  1099. print '<tr><td>'.$langs->trans("Duration").'</td><td>';
  1100. print '<input name="duration_value" size="4" value="'.GETPOST('duration_value', 'int').'">';
  1101. print $formproduct->selectMeasuringUnits("duration_unit", "time", (GETPOSTISSET('duration_value') ? GETPOSTISSET('duration_value', 'alpha') : 'h'), 0, 1);
  1102. print '</td></tr>';
  1103. }
  1104. if ($type != 1) { // Nature, Weight and volume only applies to products and not to services
  1105. if (empty($conf->global->PRODUCT_DISABLE_NATURE)) {
  1106. // Nature
  1107. print '<tr><td>'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
  1108. print $formproduct->selectProductNature('finished', $object->finished);
  1109. print '</td></tr>';
  1110. }
  1111. if (empty($conf->global->PRODUCT_DISABLE_WEIGHT)) {
  1112. // Brut Weight
  1113. print '<tr><td>'.$langs->trans("Weight").'</td><td>';
  1114. print '<input name="weight" size="4" value="'.GETPOST('weight').'">';
  1115. print $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOSTISSET('weight_units') ?GETPOST('weight_units', 'alpha') : (empty($conf->global->MAIN_WEIGHT_DEFAULT_UNIT) ? 0 : $conf->global->MAIN_WEIGHT_DEFAULT_UNIT), 0, 2);
  1116. print '</td></tr>';
  1117. }
  1118. // Brut Length
  1119. if (empty($conf->global->PRODUCT_DISABLE_SIZE)) {
  1120. print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
  1121. print '<input name="size" class="width50" value="'.GETPOST('size').'"> x ';
  1122. print '<input name="sizewidth" class="width50" value="'.GETPOST('sizewidth').'"> x ';
  1123. print '<input name="sizeheight" class="width50" value="'.GETPOST('sizeheight').'">';
  1124. print $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTISSET('size_units') ?GETPOST('size_units', 'alpha') : '0', 0, 2);
  1125. print '</td></tr>';
  1126. }
  1127. if (empty($conf->global->PRODUCT_DISABLE_SURFACE)) {
  1128. // Brut Surface
  1129. print '<tr><td>'.$langs->trans("Surface").'</td><td>';
  1130. print '<input name="surface" size="4" value="'.GETPOST('surface').'">';
  1131. print $formproduct->selectMeasuringUnits("surface_units", "surface", GETPOSTISSET('surface_units') ?GETPOST('surface_units', 'alpha') : '0', 0, 2);
  1132. print '</td></tr>';
  1133. }
  1134. if (empty($conf->global->PRODUCT_DISABLE_VOLUME)) {
  1135. // Brut Volume
  1136. print '<tr><td>'.$langs->trans("Volume").'</td><td>';
  1137. print '<input name="volume" size="4" value="'.GETPOST('volume').'">';
  1138. print $formproduct->selectMeasuringUnits("volume_units", "volume", GETPOSTISSET('volume_units') ?GETPOST('volume_units', 'alpha') : '0', 0, 2);
  1139. print '</td></tr>';
  1140. }
  1141. if (!empty($conf->global->PRODUCT_ADD_NET_MEASURE)) {
  1142. // Net Measure
  1143. print '<tr><td>'.$langs->trans("NetMeasure").'</td><td>';
  1144. print '<input name="net_measure" size="4" value="'.GETPOST('net_measure').'">';
  1145. print $formproduct->selectMeasuringUnits("net_measure_units", '', GETPOSTISSET('net_measure_units') ?GETPOST('net_measure_units', 'alpha') : (empty($conf->global->MAIN_WEIGHT_DEFAULT_UNIT) ? 0 : $conf->global->MAIN_WEIGHT_DEFAULT_UNIT), 0, 0);
  1146. print '</td></tr>';
  1147. }
  1148. }
  1149. // Units
  1150. if (!empty($conf->global->PRODUCT_USE_UNITS)) {
  1151. print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
  1152. print '<td>';
  1153. print $form->selectUnits(empty($line->fk_unit) ? $conf->global->PRODUCT_USE_UNITS : $line->fk_unit, 'units');
  1154. print '</td></tr>';
  1155. }
  1156. // Custom code
  1157. if (empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO) && empty($type)) {
  1158. print '<tr><td class="wordbreak">'.$langs->trans("CustomCode").'</td><td><input name="customcode" class="maxwidth100onsmartphone" value="'.GETPOST('customcode').'"></td></tr>';
  1159. // Origin country
  1160. print '<tr><td>'.$langs->trans("CountryOrigin").'</td>';
  1161. print '<td>';
  1162. print img_picto('', 'globe-americas', 'class="paddingrightonly"');
  1163. print $form->select_country((GETPOSTISSET('country_id') ? GETPOST('country_id') : $object->country_id), 'country_id', '', 0, 'minwidth300 widthcentpercentminusx maxwidth500');
  1164. if ($user->admin) {
  1165. print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
  1166. }
  1167. print '</td></tr>';
  1168. // State
  1169. if (empty($conf->global->PRODUCT_DISABLE_STATE)) {
  1170. print '<tr>';
  1171. if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && ($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 || $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 2)) {
  1172. print '<td>'.$form->editfieldkey('RegionStateOrigin', 'state_id', '', $object, 0).'</td><td>';
  1173. } else {
  1174. print '<td>'.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).'</td><td>';
  1175. }
  1176. print img_picto('', 'state', 'class="pictofixedwidth"');
  1177. print $formcompany->select_state($object->state_id, $object->country_code);
  1178. print '</tr>';
  1179. }
  1180. }
  1181. // Quality control
  1182. if (!empty($conf->global->PRODUCT_LOT_ENABLE_QUALITY_CONTROL)) {
  1183. print '<tr><td>'.$langs->trans("LifeTime").'</td><td><input name="lifetime" class="maxwidth100onsmartphone" value="'.GETPOST('lifetime').'"></td></tr>';
  1184. print '<tr><td>'.$langs->trans("QCFrequency").'</td><td><input name="qc_frequency" class="maxwidth100onsmartphone" value="'.GETPOST('qc_frequency').'"></td></tr>';
  1185. }
  1186. // Other attributes
  1187. $parameters = array('colspan' => ' colspan="2"', 'cols'=>2);
  1188. $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
  1189. print $hookmanager->resPrint;
  1190. if (empty($reshook)) {
  1191. print $object->showOptionals($extrafields, 'create', $parameters);
  1192. }
  1193. // Note (private, no output on invoices, propales...)
  1194. //if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB)) available in create mode
  1195. //{
  1196. print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td>';
  1197. // 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.
  1198. $doleditor = new DolEditor('note_private', GETPOST('note_private', 'restricthtml'), '', 140, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, ROWS_8, '90%');
  1199. $doleditor->Create();
  1200. print "</td></tr>";
  1201. //}
  1202. if ($conf->categorie->enabled) {
  1203. // Categories
  1204. print '<tr><td>'.$langs->trans("Categories").'</td><td>';
  1205. $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', 'parent', 64, 0, 1);
  1206. print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0);
  1207. print "</td></tr>";
  1208. }
  1209. print '</table>';
  1210. print '<hr>';
  1211. if (empty($conf->global->PRODUCT_DISABLE_PRICES)) {
  1212. if (!empty($conf->global->PRODUIT_MULTIPRICES)) {
  1213. // We do no show price array on create when multiprices enabled.
  1214. // We must set them on prices tab.
  1215. print '<table class="border centpercent">';
  1216. // VAT
  1217. print '<tr><td class="titlefieldcreate">'.$langs->trans("VATRate").'</td><td>';
  1218. $defaultva = get_default_tva($mysoc, $mysoc);
  1219. print $form->load_tva("tva_tx", $defaultva, $mysoc, $mysoc, 0, 0, '', false, 1);
  1220. print '</td></tr>';
  1221. print '</table>';
  1222. print '<br>';
  1223. } else {
  1224. print '<table class="border centpercent">';
  1225. // Price
  1226. print '<tr><td class="titlefieldcreate">'.$langs->trans("SellingPrice").'</td>';
  1227. print '<td><input name="price" class="maxwidth50" value="'.$object->price.'">';
  1228. print $form->selectPriceBaseType($conf->global->PRODUCT_PRICE_BASE_TYPE, "price_base_type");
  1229. print '</td></tr>';
  1230. // Min price
  1231. print '<tr><td>'.$langs->trans("MinPrice").'</td>';
  1232. print '<td><input name="price_min" class="maxwidth50" value="'.$object->price_min.'">';
  1233. print '</td></tr>';
  1234. // VAT
  1235. print '<tr><td>'.$langs->trans("VATRate").'</td><td>';
  1236. $defaultva = get_default_tva($mysoc, $mysoc);
  1237. print $form->load_tva("tva_tx", $defaultva, $mysoc, $mysoc, 0, 0, '', false, 1);
  1238. print '</td></tr>';
  1239. print '</table>';
  1240. print '<br>';
  1241. }
  1242. }
  1243. // Accountancy codes
  1244. print '<!-- accountancy codes -->'."\n";
  1245. print '<table class="border centpercent">';
  1246. if (empty($conf->global->PRODUCT_DISABLE_ACCOUNTING)) {
  1247. if (!empty($conf->accounting->enabled)) {
  1248. // Accountancy_code_sell
  1249. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
  1250. print '<td>';
  1251. if ($type == 0) {
  1252. $accountancy_code_sell = (GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell', 'alpha') : $conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT);
  1253. } else {
  1254. $accountancy_code_sell = (GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell', 'alpha') : $conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT);
  1255. }
  1256. print $formaccounting->select_account($accountancy_code_sell, 'accountancy_code_sell', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
  1257. print '</td></tr>';
  1258. // Accountancy_code_sell_intra
  1259. if ($mysoc->isInEEC()) {
  1260. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
  1261. print '<td>';
  1262. if ($type == 0) {
  1263. $accountancy_code_sell_intra = (GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra', 'alpha') : $conf->global->ACCOUNTING_PRODUCT_SOLD_INTRA_ACCOUNT);
  1264. } else {
  1265. $accountancy_code_sell_intra = (GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra', 'alpha') : $conf->global->ACCOUNTING_SERVICE_SOLD_INTRA_ACCOUNT);
  1266. }
  1267. print $formaccounting->select_account($accountancy_code_sell_intra, 'accountancy_code_sell_intra', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
  1268. print '</td></tr>';
  1269. }
  1270. // Accountancy_code_sell_export
  1271. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
  1272. print '<td>';
  1273. if ($type == 0) {
  1274. $accountancy_code_sell_export = (GETPOST('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export', 'alpha') : $conf->global->ACCOUNTING_PRODUCT_SOLD_EXPORT_ACCOUNT);
  1275. } else {
  1276. $accountancy_code_sell_export = (GETPOST('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export', 'alpha') : $conf->global->ACCOUNTING_SERVICE_SOLD_EXPORT_ACCOUNT);
  1277. }
  1278. print $formaccounting->select_account($accountancy_code_sell_export, 'accountancy_code_sell_export', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
  1279. print '</td></tr>';
  1280. // Accountancy_code_buy
  1281. print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
  1282. print '<td>';
  1283. if ($type == 0) {
  1284. $accountancy_code_buy = (GETPOST('accountancy_code_buy', 'alpha') ? (GETPOST('accountancy_code_buy', 'alpha')) : $conf->global->ACCOUNTING_PRODUCT_BUY_ACCOUNT);
  1285. } else {
  1286. $accountancy_code_buy = (GETPOST('accountancy_code_buy', 'alpha') ? (GETPOST('accountancy_code_buy', 'alpha')) : $conf->global->ACCOUNTING_SERVICE_BUY_ACCOUNT);
  1287. }
  1288. print $formaccounting->select_account($accountancy_code_buy, 'accountancy_code_buy', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
  1289. print '</td></tr>';
  1290. // Accountancy_code_buy_intra
  1291. if ($mysoc->isInEEC()) {
  1292. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
  1293. print '<td>';
  1294. if ($type == 0) {
  1295. $accountancy_code_buy_intra = (GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra', 'alpha') : $conf->global->ACCOUNTING_PRODUCT_BUY_INTRA_ACCOUNT);
  1296. } else {
  1297. $accountancy_code_buy_intra = (GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra', 'alpha') : $conf->global->ACCOUNTING_SERVICE_BUY_INTRA_ACCOUNT);
  1298. }
  1299. print $formaccounting->select_account($accountancy_code_buy_intra, 'accountancy_code_buy_intra', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
  1300. print '</td></tr>';
  1301. }
  1302. // Accountancy_code_buy_export
  1303. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
  1304. print '<td>';
  1305. if ($type == 0) {
  1306. $accountancy_code_buy_export = (GETPOST('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export', 'alpha') : $conf->global->ACCOUNTING_PRODUCT_BUY_EXPORT_ACCOUNT);
  1307. } else {
  1308. $accountancy_code_buy_export = (GETPOST('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export', 'alpha') : $conf->global->ACCOUNTING_SERVICE_BUY_EXPORT_ACCOUNT);
  1309. }
  1310. print $formaccounting->select_account($accountancy_code_buy_export, 'accountancy_code_buy_export', 1, null, 1, 1, 'minwidth150 maxwidth300', 1);
  1311. print '</td></tr>';
  1312. } else {// For external software
  1313. if (!empty($accountancy_code_sell)) {
  1314. $object->accountancy_code_sell = $accountancy_code_sell;
  1315. }
  1316. if (!empty($accountancy_code_sell_intra)) {
  1317. $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
  1318. }
  1319. if (!empty($accountancy_code_sell_export)) {
  1320. $object->accountancy_code_sell_export = $accountancy_code_sell_export;
  1321. }
  1322. if (!empty($accountancy_code_buy)) {
  1323. $object->accountancy_code_buy = $accountancy_code_buy;
  1324. }
  1325. if (!empty($accountancy_code_buy_intra)) {
  1326. $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
  1327. }
  1328. if (!empty($accountancy_code_buy_export)) {
  1329. $object->accountancy_code_buy_export = $accountancy_code_buy_export;
  1330. }
  1331. // Accountancy_code_sell
  1332. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
  1333. print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell" value="'.$object->accountancy_code_sell.'">';
  1334. print '</td></tr>';
  1335. // Accountancy_code_sell_intra
  1336. if ($mysoc->isInEEC()) {
  1337. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
  1338. print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell_intra" value="'.$object->accountancy_code_sell_intra.'">';
  1339. print '</td></tr>';
  1340. }
  1341. // Accountancy_code_sell_export
  1342. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
  1343. print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell_export" value="'.$object->accountancy_code_sell_export.'">';
  1344. print '</td></tr>';
  1345. // Accountancy_code_buy
  1346. print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
  1347. print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy" value="'.$object->accountancy_code_buy.'">';
  1348. print '</td></tr>';
  1349. // Accountancy_code_buy_intra
  1350. if ($mysoc->isInEEC()) {
  1351. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
  1352. print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy_intra" value="'.$object->accountancy_code_buy_intra.'">';
  1353. print '</td></tr>';
  1354. }
  1355. // Accountancy_code_buy_export
  1356. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
  1357. print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy_export" value="'.$object->accountancy_code_buy_export.'">';
  1358. print '</td></tr>';
  1359. }
  1360. }
  1361. print '</table>';
  1362. print dol_get_fiche_end();
  1363. print '<div class="center">';
  1364. print '<input type="submit" class="button" value="'.$langs->trans("Create").'">';
  1365. print ' &nbsp; &nbsp; ';
  1366. print '<input type="button" class="button button-cancel" value="'.$langs->trans("Cancel").'" onClick="javascript:history.go(-1)">';
  1367. print '</div>';
  1368. print '</form>';
  1369. } elseif ($object->id > 0) {
  1370. /*
  1371. * Product card
  1372. */
  1373. // Fiche en mode edition
  1374. if ($action == 'edit' && $usercancreate) {
  1375. //WYSIWYG Editor
  1376. require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  1377. if (!empty($conf->use_javascript_ajax)) {
  1378. print '<script type="text/javascript">';
  1379. print '$(document).ready(function () {
  1380. $("#selectcountry_id").change(function () {
  1381. document.formprod.action.value="edit";
  1382. document.formprod.submit();
  1383. });
  1384. });';
  1385. print '</script>'."\n";
  1386. }
  1387. // We set country_id, country_code and country for the selected country
  1388. $object->country_id = GETPOST('country_id') ? GETPOST('country_id') : $object->country_id;
  1389. if ($object->country_id) {
  1390. $tmparray = getCountry($object->country_id, 'all');
  1391. $object->country_code = $tmparray['code'];
  1392. $object->country = $tmparray['label'];
  1393. }
  1394. $type = $langs->trans('Product');
  1395. if ($object->isService()) {
  1396. $type = $langs->trans('Service');
  1397. }
  1398. //print load_fiche_titre($langs->trans('Modify').' '.$type.' : '.(is_object($object->oldcopy)?$object->oldcopy->ref:$object->ref), "");
  1399. // Main official, simple, and not duplicated code
  1400. print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'" method="POST" name="formprod">'."\n";
  1401. print '<input type="hidden" name="token" value="'.newToken().'">';
  1402. print '<input type="hidden" name="action" value="update">';
  1403. print '<input type="hidden" name="id" value="'.$object->id.'">';
  1404. print '<input type="hidden" name="canvas" value="'.$object->canvas.'">';
  1405. $head = product_prepare_head($object);
  1406. $titre = $langs->trans("CardProduct".$object->type);
  1407. $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
  1408. print dol_get_fiche_head($head, 'card', $titre, 0, $picto);
  1409. print '<table class="border allwidth">';
  1410. // Ref
  1411. print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Ref").'</td><td colspan="3"><input name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag($object->ref).'"></td></tr>';
  1412. // Label
  1413. print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td colspan="3"><input name="label" class="minwidth300 maxwidth400onsmartphone" maxlength="255" value="'.dol_escape_htmltag($object->label).'"></td></tr>';
  1414. // Status To sell
  1415. print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td colspan="3">';
  1416. print '<select class="flat" name="statut">';
  1417. if ($object->status) {
  1418. print '<option value="1" selected>'.$langs->trans("OnSell").'</option>';
  1419. print '<option value="0">'.$langs->trans("NotOnSell").'</option>';
  1420. } else {
  1421. print '<option value="1">'.$langs->trans("OnSell").'</option>';
  1422. print '<option value="0" selected>'.$langs->trans("NotOnSell").'</option>';
  1423. }
  1424. print '</select>';
  1425. print '</td></tr>';
  1426. // Status To Buy
  1427. print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td colspan="3">';
  1428. print '<select class="flat" name="statut_buy">';
  1429. if ($object->status_buy) {
  1430. print '<option value="1" selected>'.$langs->trans("ProductStatusOnBuy").'</option>';
  1431. print '<option value="0">'.$langs->trans("ProductStatusNotOnBuy").'</option>';
  1432. } else {
  1433. print '<option value="1">'.$langs->trans("ProductStatusOnBuy").'</option>';
  1434. print '<option value="0" selected>'.$langs->trans("ProductStatusNotOnBuy").'</option>';
  1435. }
  1436. print '</select>';
  1437. print '</td></tr>';
  1438. // Batch number managment
  1439. if ($conf->productbatch->enabled) {
  1440. if ($object->isProduct() || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
  1441. print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
  1442. $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial"));
  1443. print $form->selectarray('status_batch', $statutarray, $object->status_batch);
  1444. print '</td></tr>';
  1445. if (!empty($object->status_batch) || !empty($conf->use_javascript_ajax)) {
  1446. $langs->load("admin");
  1447. $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
  1448. $tooltip .= '<br>'.$langs->trans("GenericMaskCodes2");
  1449. $tooltip .= '<br>'.$langs->trans("GenericMaskCodes3");
  1450. $tooltip .= '<br>'.$langs->trans("GenericMaskCodes4a", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
  1451. $tooltip .= '<br>'.$langs->trans("GenericMaskCodes5");
  1452. print '<tr><td id="mask_option">'.$langs->trans("ManageLotMask").'</td>';
  1453. if ($object->status_batch == '1' && getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
  1454. $mask = !empty($object->batch_mask) ? $object->batch_mask : getDolGlobalString('LOT_ADVANCED_MASK');
  1455. }
  1456. if ($object->status_batch == '2' && getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
  1457. $mask = !empty($object->batch_mask) ? $object->batch_mask : getDolGlobalString('SN_ADVANCED_MASK');
  1458. }
  1459. $inherited_mask_lot = getDolGlobalString('LOT_ADVANCED_MASK');
  1460. $inherited_mask_sn = getDolGlobalString('SN_ADVANCED_MASK');
  1461. print '<td id="field_mask">';
  1462. print $form->textwithpicto('<input type="text" class="flat minwidth175" name="batch_mask" id="batch_mask_input" value="'.$mask.'">', $tooltip, 1, 1);
  1463. // Add javascript to sho/hide field for custom mask
  1464. if (!empty($conf->use_javascript_ajax)) {
  1465. print '<script type="text/javascript">
  1466. $(document).ready(function() {
  1467. $("#field_mask").parent().addClass("hideobject");
  1468. var preselect = document.getElementById("status_batch");';
  1469. if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS')) {
  1470. print 'if (preselect.value == "2") {
  1471. $("#field_mask").parent().removeClass("hideobject");
  1472. }';
  1473. }
  1474. if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS')) {
  1475. print 'if (preselect.value == "1") {
  1476. $("#field_mask").parent().removeClass("hideobject");
  1477. }';
  1478. }
  1479. print '$("#status_batch").on("change", function () {
  1480. var optionSelected = $("option:selected", this);
  1481. var valueSelected = this.value;
  1482. $("#field_mask").parent().addClass("hideobject");
  1483. ';
  1484. if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
  1485. print '
  1486. if (this.value == 1) {
  1487. $("#field_mask").parent().removeClass("hideobject");
  1488. $("#batch_mask_input").val("'.$inherited_mask_lot.'");
  1489. }
  1490. ';
  1491. }
  1492. if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
  1493. print '
  1494. if (this.value == 2) {
  1495. $("#field_mask").parent().removeClass("hideobject");
  1496. $("#batch_mask_input").val("'.$inherited_mask_sn.'");
  1497. }
  1498. ';
  1499. }
  1500. print '
  1501. })
  1502. })
  1503. </script>';
  1504. }
  1505. print '</td></tr>';
  1506. }
  1507. }
  1508. }
  1509. // Barcode
  1510. $showbarcode = empty($conf->barcode->enabled) ? 0 : 1;
  1511. if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
  1512. $showbarcode = 0;
  1513. }
  1514. if ($showbarcode) {
  1515. print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
  1516. if (GETPOSTISSET('fk_barcode_type')) {
  1517. $fk_barcode_type = GETPOST('fk_barcode_type');
  1518. } else {
  1519. $fk_barcode_type = $object->barcode_type;
  1520. if (empty($fk_barcode_type) && !empty($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE)) {
  1521. $fk_barcode_type = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
  1522. }
  1523. }
  1524. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
  1525. $formbarcode = new FormBarCode($db);
  1526. print $formbarcode->selectBarcodeType($fk_barcode_type, 'fk_barcode_type', 1);
  1527. print '</td></tr>';
  1528. print '<tr><td>'.$langs->trans("BarcodeValue").'</td><td>';
  1529. $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
  1530. if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
  1531. $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
  1532. }
  1533. print '<input class="maxwidth150 maxwidthonsmartphone" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
  1534. print '</td></tr>';
  1535. }
  1536. // Description (used in invoice, propal...)
  1537. print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
  1538. // 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.
  1539. $doleditor = new DolEditor('desc', $object->description, '', 160, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, ROWS_4, '90%');
  1540. $doleditor->Create();
  1541. print "</td></tr>";
  1542. print "\n";
  1543. // Public Url
  1544. if (empty($conf->global->PRODUCT_DISABLE_PUBLIC_URL)) {
  1545. print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
  1546. print img_picto('', 'globe', 'class="pictofixedwidth"');
  1547. print '<input type="text" name="url" class="quatrevingtpercent" value="'.$object->url.'">';
  1548. print '</td></tr>';
  1549. }
  1550. // Stock
  1551. if ($object->isProduct() && !empty($conf->stock->enabled)) {
  1552. // Default warehouse
  1553. print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
  1554. print img_picto($langs->trans("DefaultWarehouse"), 'stock', 'class="pictofixedwidth"');
  1555. print $formproduct->selectWarehouses($object->fk_default_warehouse, 'fk_default_warehouse', 'warehouseopen', 1);
  1556. print ' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create&amp;backtopage='.urlencode($_SERVER['PHP_SELF'].'?action=create&type='.GETPOST('type', 'int')).'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddWarehouse").'"></span></a>';
  1557. print '</td></tr>';
  1558. /*
  1559. print "<tr>".'<td>'.$langs->trans("StockLimit").'</td><td>';
  1560. print '<input name="seuil_stock_alerte" size="4" value="'.$object->seuil_stock_alerte.'">';
  1561. print '</td>';
  1562. print '<td>'.$langs->trans("DesiredStock").'</td><td>';
  1563. print '<input name="desiredstock" size="4" value="'.$object->desiredstock.'">';
  1564. print '</td></tr>';
  1565. */
  1566. }
  1567. /*
  1568. else
  1569. {
  1570. print '<input name="seuil_stock_alerte" type="hidden" value="'.$object->seuil_stock_alerte.'">';
  1571. print '<input name="desiredstock" type="hidden" value="'.$object->desiredstock.'">';
  1572. }*/
  1573. if ($object->isService()) {
  1574. // Duration
  1575. print '<tr><td>'.$langs->trans("Duration").'</td><td>';
  1576. print '<input name="duration_value" size="5" value="'.$object->duration_value.'"> ';
  1577. print $formproduct->selectMeasuringUnits("duration_unit", "time", $object->duration_unit, 0, 1);
  1578. print '</td></tr>';
  1579. } else {
  1580. if (empty($conf->global->PRODUCT_DISABLE_NATURE)) {
  1581. // Nature
  1582. print '<tr><td>'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
  1583. print $formproduct->selectProductNature('finished', $object->finished);
  1584. print '</td></tr>';
  1585. }
  1586. if (empty($conf->global->PRODUCT_DISABLE_WEIGHT)) {
  1587. // Brut Weight
  1588. print '<tr><td>'.$langs->trans("Weight").'</td><td>';
  1589. print '<input name="weight" size="5" value="'.$object->weight.'"> ';
  1590. print $formproduct->selectMeasuringUnits("weight_units", "weight", $object->weight_units, 0, 2);
  1591. print '</td></tr>';
  1592. }
  1593. if (empty($conf->global->PRODUCT_DISABLE_SIZE)) {
  1594. // Brut Length
  1595. print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
  1596. print '<input name="size" size="5" value="'.$object->length.'">x';
  1597. print '<input name="sizewidth" size="5" value="'.$object->width.'">x';
  1598. print '<input name="sizeheight" size="5" value="'.$object->height.'"> ';
  1599. print $formproduct->selectMeasuringUnits("size_units", "size", $object->length_units, 0, 2);
  1600. print '</td></tr>';
  1601. }
  1602. if (empty($conf->global->PRODUCT_DISABLE_SURFACE)) {
  1603. // Brut Surface
  1604. print '<tr><td>'.$langs->trans("Surface").'</td><td>';
  1605. print '<input name="surface" size="5" value="'.$object->surface.'"> ';
  1606. print $formproduct->selectMeasuringUnits("surface_units", "surface", $object->surface_units, 0, 2);
  1607. print '</td></tr>';
  1608. }
  1609. if (empty($conf->global->PRODUCT_DISABLE_VOLUME)) {
  1610. // Brut Volume
  1611. print '<tr><td>'.$langs->trans("Volume").'</td><td>';
  1612. print '<input name="volume" size="5" value="'.$object->volume.'"> ';
  1613. print $formproduct->selectMeasuringUnits("volume_units", "volume", $object->volume_units, 0, 2);
  1614. print '</td></tr>';
  1615. }
  1616. if (!empty($conf->global->PRODUCT_ADD_NET_MEASURE)) {
  1617. // Net Measure
  1618. print '<tr><td>'.$langs->trans("NetMeasure").'</td><td>';
  1619. print '<input name="net_measure" size="5" value="'.$object->net_measure.'"> ';
  1620. print $formproduct->selectMeasuringUnits("net_measure_units", "", $object->net_measure_units, 0, 0);
  1621. print '</td></tr>';
  1622. }
  1623. }
  1624. // Units
  1625. if (!empty($conf->global->PRODUCT_USE_UNITS)) {
  1626. print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
  1627. print '<td>';
  1628. print $form->selectUnits($object->fk_unit, 'units');
  1629. print '</td></tr>';
  1630. }
  1631. // Custom code
  1632. if (!$object->isService() && empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO)) {
  1633. print '<tr><td class="wordbreak">'.$langs->trans("CustomCode").'</td><td><input name="customcode" class="maxwidth100onsmartphone" value="'.$object->customcode.'"></td></tr>';
  1634. // Origin country
  1635. print '<tr><td>'.$langs->trans("CountryOrigin").'</td>';
  1636. print '<td>';
  1637. print img_picto('', 'globe-americas', 'class="paddingrightonly"');
  1638. print $form->select_country(GETPOSTISSET('country_id') ? GETPOST('country_id', 'int') : $object->country_id, 'country_id', '', 0, 'minwidth100 maxwidthonsmartphone');
  1639. if ($user->admin) {
  1640. print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
  1641. }
  1642. print '</td></tr>';
  1643. // State
  1644. if (empty($conf->global->PRODUCT_DISABLE_STATE)) {
  1645. print '<tr>';
  1646. if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && ($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 || $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 2)) {
  1647. print '<td>'.$form->editfieldkey('RegionStateOrigin', 'state_id', '', $object, 0).'</td><td>';
  1648. } else {
  1649. print '<td>'.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).'</td><td>';
  1650. }
  1651. print img_picto('', 'state', 'class="pictofixedwidth"');
  1652. print $formcompany->select_state(GETPOSTISSET('state_id') ? GETPOST('state_id', 'int') : $object->state_id, $object->country_code);
  1653. print '</td>';
  1654. print '</tr>';
  1655. }
  1656. }
  1657. // Quality control
  1658. if (!empty($conf->global->PRODUCT_LOT_ENABLE_QUALITY_CONTROL)) {
  1659. print '<tr><td>'.$langs->trans("LifeTime").'</td><td><input name="lifetime" class="maxwidth100onsmartphone" value="'.$object->lifetime.'"></td></tr>';
  1660. print '<tr><td>'.$langs->trans("QCFrequency").'</td><td><input name="qc_frequency" class="maxwidth100onsmartphone" value="'.$object->qc_frequency.'"></td></tr>';
  1661. }
  1662. // Other attributes
  1663. $parameters = array('colspan' => ' colspan="2"', 'cols' => 2);
  1664. $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
  1665. print $hookmanager->resPrint;
  1666. if (empty($reshook)) {
  1667. print $object->showOptionals($extrafields, 'edit', $parameters);
  1668. }
  1669. // Tags-Categories
  1670. if ($conf->categorie->enabled) {
  1671. print '<tr><td>'.$langs->trans("Categories").'</td><td>';
  1672. $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', 'parent', 64, 0, 1);
  1673. $c = new Categorie($db);
  1674. $cats = $c->containing($object->id, Categorie::TYPE_PRODUCT);
  1675. $arrayselected = array();
  1676. if (is_array($cats)) {
  1677. foreach ($cats as $cat) {
  1678. $arrayselected[] = $cat->id;
  1679. }
  1680. }
  1681. print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0);
  1682. print "</td></tr>";
  1683. }
  1684. // Note private
  1685. if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
  1686. print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td>';
  1687. $doleditor = new DolEditor('note_private', $object->note_private, '', 140, 'dolibarr_notes', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, ROWS_4, '90%');
  1688. $doleditor->Create();
  1689. print "</td></tr>";
  1690. }
  1691. print '</table>';
  1692. print '<br>';
  1693. print '<table class="border centpercent">';
  1694. if (empty($conf->global->PRODUCT_DISABLE_ACCOUNTING)) {
  1695. if (!empty($conf->accounting->enabled)) {
  1696. // Accountancy_code_sell
  1697. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
  1698. print '<td>';
  1699. print $formaccounting->select_account($object->accountancy_code_sell, 'accountancy_code_sell', 1, '', 1, 1, 'minwidth150 maxwidth300');
  1700. print '</td></tr>';
  1701. // Accountancy_code_sell_intra
  1702. if ($mysoc->isInEEC()) {
  1703. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
  1704. print '<td>';
  1705. print $formaccounting->select_account($object->accountancy_code_sell_intra, 'accountancy_code_sell_intra', 1, '', 1, 1, 'minwidth150 maxwidth300');
  1706. print '</td></tr>';
  1707. }
  1708. // Accountancy_code_sell_export
  1709. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
  1710. print '<td>';
  1711. print $formaccounting->select_account($object->accountancy_code_sell_export, 'accountancy_code_sell_export', 1, '', 1, 1, 'minwidth150 maxwidth300');
  1712. print '</td></tr>';
  1713. // Accountancy_code_buy
  1714. print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
  1715. print '<td>';
  1716. print $formaccounting->select_account($object->accountancy_code_buy, 'accountancy_code_buy', 1, '', 1, 1, 'minwidth150 maxwidth300');
  1717. print '</td></tr>';
  1718. // Accountancy_code_buy_intra
  1719. if ($mysoc->isInEEC()) {
  1720. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
  1721. print '<td>';
  1722. print $formaccounting->select_account($object->accountancy_code_buy_intra, 'accountancy_code_buy_intra', 1, '', 1, 1, 'minwidth150 maxwidth300');
  1723. print '</td></tr>';
  1724. }
  1725. // Accountancy_code_buy_export
  1726. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
  1727. print '<td>';
  1728. print $formaccounting->select_account($object->accountancy_code_buy_export, 'accountancy_code_buy_export', 1, '', 1, 1, 'minwidth150 maxwidth300');
  1729. print '</td></tr>';
  1730. } else {
  1731. // For external software
  1732. // Accountancy_code_sell
  1733. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
  1734. print '<td><input name="accountancy_code_sell" class="maxwidth200" value="'.$object->accountancy_code_sell.'">';
  1735. print '</td></tr>';
  1736. // Accountancy_code_sell_intra
  1737. if ($mysoc->isInEEC()) {
  1738. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
  1739. print '<td><input name="accountancy_code_sell_intra" class="maxwidth200" value="'.$object->accountancy_code_sell_intra.'">';
  1740. print '</td></tr>';
  1741. }
  1742. // Accountancy_code_sell_export
  1743. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
  1744. print '<td><input name="accountancy_code_sell_export" class="maxwidth200" value="'.$object->accountancy_code_sell_export.'">';
  1745. print '</td></tr>';
  1746. // Accountancy_code_buy
  1747. print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
  1748. print '<td><input name="accountancy_code_buy" class="maxwidth200" value="'.$object->accountancy_code_buy.'">';
  1749. print '</td></tr>';
  1750. // Accountancy_code_buy_intra
  1751. if ($mysoc->isInEEC()) {
  1752. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
  1753. print '<td><input name="accountancy_code_buy_intra" class="maxwidth200" value="'.$object->accountancy_code_buy_intra.'">';
  1754. print '</td></tr>';
  1755. }
  1756. // Accountancy_code_buy_export
  1757. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
  1758. print '<td><input name="accountancy_code_buy_export" class="maxwidth200" value="'.$object->accountancy_code_buy_export.'">';
  1759. print '</td></tr>';
  1760. }
  1761. }
  1762. print '</table>';
  1763. print dol_get_fiche_end();
  1764. print '<div class="center">';
  1765. print '<input type="submit" class="button button-save" value="'.$langs->trans("Save").'">';
  1766. print '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
  1767. print '<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
  1768. print '</div>';
  1769. print '</form>';
  1770. } else {
  1771. // Fiche en mode visu
  1772. $showbarcode = empty($conf->barcode->enabled) ? 0 : 1;
  1773. if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
  1774. $showbarcode = 0;
  1775. }
  1776. $head = product_prepare_head($object);
  1777. $titre = $langs->trans("CardProduct".$object->type);
  1778. $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
  1779. print dol_get_fiche_head($head, 'card', $titre, -1, $picto);
  1780. $linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?restore_lastsearch_values=1&type='.$object->type.'">'.$langs->trans("BackToList").'</a>';
  1781. $object->next_prev_filter = " fk_product_type = ".$object->type;
  1782. $shownav = 1;
  1783. if ($user->socid && !in_array('product', explode(',', $conf->global->MAIN_MODULES_FOR_EXTERNAL))) {
  1784. $shownav = 0;
  1785. }
  1786. dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref');
  1787. print '<div class="fichecenter">';
  1788. print '<div class="fichehalfleft">';
  1789. print '<div class="underbanner clearboth"></div>';
  1790. print '<table class="border tableforfield centpercent">';
  1791. // Type
  1792. if (!empty($conf->product->enabled) && !empty($conf->service->enabled)) {
  1793. $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
  1794. print '<tr><td class="titlefield">';
  1795. print (empty($conf->global->PRODUCT_DENY_CHANGE_PRODUCT_TYPE)) ? $form->editfieldkey("Type", 'fk_product_type', $object->type, $object, $usercancreate, $typeformat) : $langs->trans('Type');
  1796. print '</td><td>';
  1797. print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, $usercancreate, $typeformat);
  1798. print '</td></tr>';
  1799. }
  1800. if ($showbarcode) {
  1801. // Barcode type
  1802. print '<tr><td class="nowrap">';
  1803. print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
  1804. print $langs->trans("BarcodeType");
  1805. print '</td>';
  1806. if (($action != 'editbarcodetype') && $usercancreate && $createbarcode) {
  1807. 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>';
  1808. }
  1809. print '</tr></table>';
  1810. print '</td><td>';
  1811. if ($action == 'editbarcodetype' || $action == 'editbarcode') {
  1812. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
  1813. $formbarcode = new FormBarCode($db);
  1814. }
  1815. $fk_barcode_type = '';
  1816. if ($action == 'editbarcodetype') {
  1817. print $formbarcode->formBarcodeType($_SERVER['PHP_SELF'].'?id='.$object->id, $object->barcode_type, 'fk_barcode_type');
  1818. $fk_barcode_type = $object->barcode_type;
  1819. } else {
  1820. $object->fetch_barcode();
  1821. $fk_barcode_type = $object->barcode_type;
  1822. print $object->barcode_type_label ? $object->barcode_type_label : ($object->barcode ? '<div class="warning">'.$langs->trans("SetDefaultBarcodeType").'<div>' : '');
  1823. }
  1824. print '</td></tr>'."\n";
  1825. // Barcode value
  1826. print '<tr><td class="nowrap">';
  1827. print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
  1828. print $langs->trans("BarcodeValue");
  1829. print '</td>';
  1830. if (($action != 'editbarcode') && $usercancreate && $createbarcode) {
  1831. 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>';
  1832. }
  1833. print '</tr></table>';
  1834. print '</td><td>';
  1835. if ($action == 'editbarcode') {
  1836. $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
  1837. if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
  1838. $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
  1839. }
  1840. print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
  1841. print '<input type="hidden" name="token" value="'.newToken().'">';
  1842. print '<input type="hidden" name="action" value="setbarcode">';
  1843. print '<input type="hidden" name="barcode_type_code" value="'.$object->barcode_type_code.'">';
  1844. print '<input size="40" class="maxwidthonsmartphone" type="text" name="barcode" value="'.$tmpcode.'">';
  1845. print '&nbsp;<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
  1846. print '</form>';
  1847. } else {
  1848. print showValueWithClipboardCPButton($object->barcode);
  1849. }
  1850. print '</td></tr>'."\n";
  1851. }
  1852. // Batch number management (to batch)
  1853. if (!empty($conf->productbatch->enabled)) {
  1854. if ($object->isProduct() || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
  1855. print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
  1856. print $object->getLibStatut(0, 2);
  1857. print '</td></tr>';
  1858. if ((($object->status_batch == '1' && $conf->global->PRODUCTBATCH_LOT_USE_PRODUCT_MASKS && $conf->global->PRODUCTBATCH_LOT_ADDON == 'mod_lot_advanced')
  1859. || ($object->status_batch == '2' && $conf->global->PRODUCTBATCH_SN_ADDON == 'mod_sn_advanced' && $conf->global->PRODUCTBATCH_SN_USE_PRODUCT_MASKS))) {
  1860. print '<tr><td>'.$langs->trans("ManageLotMask").'</td><td>';
  1861. print $object->batch_mask;
  1862. print '</td></tr>';
  1863. }
  1864. }
  1865. }
  1866. // Accountancy sell code
  1867. print '<tr><td class="nowrap">';
  1868. print $langs->trans("ProductAccountancySellCode");
  1869. print '</td><td>';
  1870. if (!empty($conf->accounting->enabled)) {
  1871. if (!empty($object->accountancy_code_sell)) {
  1872. $accountingaccount = new AccountingAccount($db);
  1873. $accountingaccount->fetch('', $object->accountancy_code_sell, 1);
  1874. print $accountingaccount->getNomUrl(0, 1, 1, '', 1);
  1875. }
  1876. } else {
  1877. print $object->accountancy_code_sell;
  1878. }
  1879. print '</td></tr>';
  1880. // Accountancy sell code intra-community
  1881. if ($mysoc->isInEEC()) {
  1882. print '<tr><td class="nowrap">';
  1883. print $langs->trans("ProductAccountancySellIntraCode");
  1884. print '</td><td>';
  1885. if (!empty($conf->accounting->enabled)) {
  1886. if (!empty($object->accountancy_code_sell_intra)) {
  1887. $accountingaccount2 = new AccountingAccount($db);
  1888. $accountingaccount2->fetch('', $object->accountancy_code_sell_intra, 1);
  1889. print $accountingaccount2->getNomUrl(0, 1, 1, '', 1);
  1890. }
  1891. } else {
  1892. print $object->accountancy_code_sell_intra;
  1893. }
  1894. print '</td></tr>';
  1895. }
  1896. // Accountancy sell code export
  1897. print '<tr><td class="nowrap">';
  1898. print $langs->trans("ProductAccountancySellExportCode");
  1899. print '</td><td>';
  1900. if (!empty($conf->accounting->enabled)) {
  1901. if (!empty($object->accountancy_code_sell_export)) {
  1902. $accountingaccount3 = new AccountingAccount($db);
  1903. $accountingaccount3->fetch('', $object->accountancy_code_sell_export, 1);
  1904. print $accountingaccount3->getNomUrl(0, 1, 1, '', 1);
  1905. }
  1906. } else {
  1907. print $object->accountancy_code_sell_export;
  1908. }
  1909. print '</td></tr>';
  1910. // Accountancy buy code
  1911. print '<tr><td class="nowrap">';
  1912. print $langs->trans("ProductAccountancyBuyCode");
  1913. print '</td><td>';
  1914. if (!empty($conf->accounting->enabled)) {
  1915. if (!empty($object->accountancy_code_buy)) {
  1916. $accountingaccount4 = new AccountingAccount($db);
  1917. $accountingaccount4->fetch('', $object->accountancy_code_buy, 1);
  1918. print $accountingaccount4->getNomUrl(0, 1, 1, '', 1);
  1919. }
  1920. } else {
  1921. print $object->accountancy_code_buy;
  1922. }
  1923. print '</td></tr>';
  1924. // Accountancy buy code intra-community
  1925. if ($mysoc->isInEEC()) {
  1926. print '<tr><td class="nowrap">';
  1927. print $langs->trans("ProductAccountancyBuyIntraCode");
  1928. print '</td><td>';
  1929. if (!empty($conf->accounting->enabled)) {
  1930. if (!empty($object->accountancy_code_buy_intra)) {
  1931. $accountingaccount5 = new AccountingAccount($db);
  1932. $accountingaccount5->fetch('', $object->accountancy_code_buy_intra, 1);
  1933. print $accountingaccount5->getNomUrl(0, 1, 1, '', 1);
  1934. }
  1935. } else {
  1936. print $object->accountancy_code_buy_intra;
  1937. }
  1938. print '</td></tr>';
  1939. }
  1940. // Accountancy buy code export
  1941. print '<tr><td class="nowrap">';
  1942. print $langs->trans("ProductAccountancyBuyExportCode");
  1943. print '</td><td>';
  1944. if (!empty($conf->accounting->enabled)) {
  1945. if (!empty($object->accountancy_code_buy_export)) {
  1946. $accountingaccount6 = new AccountingAccount($db);
  1947. $accountingaccount6->fetch('', $object->accountancy_code_buy_export, 1);
  1948. print $accountingaccount6->getNomUrl(0, 1, 1, '', 1);
  1949. }
  1950. } else {
  1951. print $object->accountancy_code_buy_export;
  1952. }
  1953. print '</td></tr>';
  1954. // Description
  1955. print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>'.(dol_textishtml($object->description) ? $object->description : dol_nl2br($object->description, 1, true)).'</td></tr>';
  1956. // Public URL
  1957. if (empty($conf->global->PRODUCT_DISABLE_PUBLIC_URL)) {
  1958. print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
  1959. print dol_print_url($object->url);
  1960. print '</td></tr>';
  1961. }
  1962. // Default warehouse
  1963. if ($object->isProduct() && !empty($conf->stock->enabled)) {
  1964. $warehouse = new Entrepot($db);
  1965. $warehouse->fetch($object->fk_default_warehouse);
  1966. print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
  1967. print (!empty($warehouse->id) ? $warehouse->getNomUrl(1) : '');
  1968. print '</td>';
  1969. }
  1970. // Parent product.
  1971. if (!empty($conf->variants->enabled) && ($object->isProduct() || $object->isService())) {
  1972. $combination = new ProductCombination($db);
  1973. if ($combination->fetchByFkProductChild($object->id) > 0) {
  1974. $prodstatic = new Product($db);
  1975. $prodstatic->fetch($combination->fk_product_parent);
  1976. // Parent product
  1977. print '<tr><td>'.$langs->trans("ParentProduct").'</td><td>';
  1978. print $prodstatic->getNomUrl(1);
  1979. print '</td></tr>';
  1980. }
  1981. }
  1982. print '</table>';
  1983. print '</div>';
  1984. print '<div class="fichehalfright"><div class="ficheaddleft">';
  1985. print '<div class="underbanner clearboth"></div>';
  1986. print '<table class="border tableforfield centpercent">';
  1987. if ($object->isService()) {
  1988. // Duration
  1989. print '<tr><td class="titlefield">'.$langs->trans("Duration").'</td><td>'.$object->duration_value.'&nbsp;';
  1990. if ($object->duration_value > 1) {
  1991. $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"));
  1992. } elseif ($object->duration_value > 0) {
  1993. $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"));
  1994. }
  1995. print (!empty($object->duration_unit) && isset($dur[$object->duration_unit]) ? $langs->trans($dur[$object->duration_unit]) : '')."&nbsp;";
  1996. print '</td></tr>';
  1997. } else {
  1998. if (empty($conf->global->PRODUCT_DISABLE_NATURE)) {
  1999. // Nature
  2000. print '<tr><td class="titlefield">'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
  2001. print $object->getLibFinished();
  2002. print '</td></tr>';
  2003. }
  2004. // Brut Weight
  2005. if (empty($conf->global->PRODUCT_DISABLE_WEIGHT)) {
  2006. print '<tr><td class="titlefield">'.$langs->trans("Weight").'</td><td>';
  2007. if ($object->weight != '') {
  2008. print $object->weight." ".measuringUnitString(0, "weight", $object->weight_units);
  2009. } else {
  2010. print '&nbsp;';
  2011. }
  2012. print "</td></tr>\n";
  2013. }
  2014. if (empty($conf->global->PRODUCT_DISABLE_SIZE)) {
  2015. // Brut Length
  2016. print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
  2017. if ($object->length != '' || $object->width != '' || $object->height != '') {
  2018. print $object->length;
  2019. if ($object->width) {
  2020. print " x ".$object->width;
  2021. }
  2022. if ($object->height) {
  2023. print " x ".$object->height;
  2024. }
  2025. print ' '.measuringUnitString(0, "size", $object->length_units);
  2026. } else {
  2027. print '&nbsp;';
  2028. }
  2029. print "</td></tr>\n";
  2030. }
  2031. if (empty($conf->global->PRODUCT_DISABLE_SURFACE)) {
  2032. // Brut Surface
  2033. print '<tr><td>'.$langs->trans("Surface").'</td><td>';
  2034. if ($object->surface != '') {
  2035. print $object->surface." ".measuringUnitString(0, "surface", $object->surface_units);
  2036. } else {
  2037. print '&nbsp;';
  2038. }
  2039. print "</td></tr>\n";
  2040. }
  2041. if (empty($conf->global->PRODUCT_DISABLE_VOLUME)) {
  2042. // Brut Volume
  2043. print '<tr><td>'.$langs->trans("Volume").'</td><td>';
  2044. if ($object->volume != '') {
  2045. print $object->volume." ".measuringUnitString(0, "volume", $object->volume_units);
  2046. } else {
  2047. print '&nbsp;';
  2048. }
  2049. print "</td></tr>\n";
  2050. }
  2051. if (!empty($conf->global->PRODUCT_ADD_NET_MEASURE)) {
  2052. // Net Measure
  2053. print '<tr><td class="titlefield">'.$langs->trans("NetMeasure").'</td><td>';
  2054. if ($object->net_measure != '') {
  2055. print $object->net_measure." ".measuringUnitString($object->net_measure_units);
  2056. } else {
  2057. print '&nbsp;';
  2058. }
  2059. print '</td></tr>';
  2060. }
  2061. }
  2062. // Unit
  2063. if (!empty($conf->global->PRODUCT_USE_UNITS)) {
  2064. $unit = $object->getLabelOfUnit();
  2065. print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td><td>';
  2066. if ($unit !== '') {
  2067. print $langs->trans($unit);
  2068. }
  2069. print '</td></tr>';
  2070. }
  2071. // Custom code
  2072. if (!$object->isService() && empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO)) {
  2073. print '<tr><td>'.$langs->trans("CustomCode").'</td><td>'.$object->customcode.'</td>';
  2074. // Origin country code
  2075. print '<tr><td>'.$langs->trans("Origin").'</td><td>'.getCountry($object->country_id, 0, $db);
  2076. if (!empty($object->state_id)) {
  2077. print ' - '.getState($object->state_id, 0, $db);
  2078. }
  2079. print '</td>';
  2080. }
  2081. // Quality Control
  2082. if (!empty($conf->global->PRODUCT_LOT_ENABLE_QUALITY_CONTROL)) {
  2083. print '<tr><td>'.$langs->trans("LifeTime").'</td><td">'.$object->lifetime.'</td></tr>';
  2084. print '<tr><td>'.$langs->trans("QCFrequency").'</td><td>'.$object->qc_frequency.'</td></tr>';
  2085. }
  2086. // Other attributes
  2087. $parameters = array();
  2088. include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
  2089. // Categories
  2090. if ($conf->categorie->enabled) {
  2091. print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
  2092. print $form->showCategories($object->id, Categorie::TYPE_PRODUCT, 1);
  2093. print "</td></tr>";
  2094. }
  2095. // Note private
  2096. if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
  2097. print '<!-- show Note --> '."\n";
  2098. 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";
  2099. print '<!-- End show Note --> '."\n";
  2100. }
  2101. print "</table>\n";
  2102. print '</div>';
  2103. print '</div></div>';
  2104. print '<div style="clear:both"></div>';
  2105. print dol_get_fiche_end();
  2106. }
  2107. } elseif ($action != 'create') {
  2108. exit;
  2109. }
  2110. }
  2111. // Load object modCodeProduct
  2112. $module = (!empty($conf->global->PRODUCT_CODEPRODUCT_ADDON) ? $conf->global->PRODUCT_CODEPRODUCT_ADDON : 'mod_codeproduct_leopard');
  2113. if (substr($module, 0, 16) == 'mod_codeproduct_' && substr($module, -3) == 'php') {
  2114. $module = substr($module, 0, dol_strlen($module) - 4);
  2115. }
  2116. $result = dol_include_once('/core/modules/product/'.$module.'.php');
  2117. if ($result > 0) {
  2118. $modCodeProduct = new $module();
  2119. }
  2120. $tmpcode = '';
  2121. if (!empty($modCodeProduct->code_auto)) {
  2122. $tmpcode = $modCodeProduct->getNextValue($object, $object->type);
  2123. }
  2124. $formconfirm = '';
  2125. // Confirm delete product
  2126. if (($action == 'delete' && (empty($conf->use_javascript_ajax) || !empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
  2127. || (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) { // Always output when not jmobile nor js
  2128. $formconfirm = $form->formconfirm("card.php?id=".$object->id, $langs->trans("DeleteProduct"), $langs->trans("ConfirmDeleteProduct"), "confirm_delete", '', 0, "action-delete");
  2129. }
  2130. // Clone confirmation
  2131. if (($action == 'clone' && (empty($conf->use_javascript_ajax) || !empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
  2132. || (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) { // Always output when not jmobile nor js
  2133. // Define confirmation messages
  2134. $formquestionclone = array(
  2135. 'text' => $langs->trans("ConfirmClone"),
  2136. array('type' => 'text', 'name' => 'clone_ref', 'label' => $langs->trans("NewRefForClone"), 'value' => empty($tmpcode) ? $langs->trans("CopyOf").' '.$object->ref : $tmpcode, 'morecss'=>'width150'),
  2137. array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneContentProduct"), 'value' => 1),
  2138. array('type' => 'checkbox', 'name' => 'clone_categories', 'label' => $langs->trans("CloneCategoriesProduct"), 'value' => 1),
  2139. );
  2140. if (!empty($conf->global->PRODUIT_MULTIPRICES)) {
  2141. $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_prices', 'label' => $langs->trans("ClonePricesProduct").' ('.$langs->trans("CustomerPrices").')', 'value' => 0);
  2142. }
  2143. if (!empty($conf->global->PRODUIT_SOUSPRODUITS)) {
  2144. $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_composition', 'label' => $langs->trans('CloneCompositionProduct'), 'value' => 1);
  2145. }
  2146. $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);
  2147. }
  2148. // Call Hook formConfirm
  2149. $parameters = array('formConfirm' => $formconfirm, 'object' => $object);
  2150. $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
  2151. if (empty($reshook)) {
  2152. $formconfirm .= $hookmanager->resPrint;
  2153. } elseif ($reshook > 0) {
  2154. $formconfirm = $hookmanager->resPrint;
  2155. }
  2156. // Print form confirm
  2157. print $formconfirm;
  2158. /*
  2159. * Action bar
  2160. */
  2161. if ($action != 'create' && $action != 'edit') {
  2162. print "\n".'<div class="tabsAction">'."\n";
  2163. $parameters = array();
  2164. $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
  2165. if (empty($reshook)) {
  2166. if ($usercancreate) {
  2167. if (!isset($object->no_button_edit) || $object->no_button_edit <> 1) {
  2168. print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&amp;id='.$object->id.'">'.$langs->trans("Modify").'</a>';
  2169. }
  2170. if (!isset($object->no_button_copy) || $object->no_button_copy <> 1) {
  2171. if (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile)) {
  2172. print '<span id="action-clone" class="butAction">'.$langs->trans('ToClone').'</span>'."\n";
  2173. } else {
  2174. print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=clone&amp;id='.$object->id.'">'.$langs->trans("ToClone").'</a>';
  2175. }
  2176. }
  2177. }
  2178. $object_is_used = $object->isObjectUsed($object->id);
  2179. if ($usercandelete) {
  2180. if (empty($object_is_used) && (!isset($object->no_button_delete) || $object->no_button_delete <> 1)) {
  2181. if (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile)) {
  2182. print '<span id="action-delete" class="butActionDelete">'.$langs->trans('Delete').'</span>'."\n";
  2183. } else {
  2184. print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=delete&amp;token='.newToken().'&amp;id='.$object->id.'">'.$langs->trans("Delete").'</a>';
  2185. }
  2186. } else {
  2187. print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("ProductIsUsed").'">'.$langs->trans("Delete").'</a>';
  2188. }
  2189. } else {
  2190. print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("Delete").'</a>';
  2191. }
  2192. }
  2193. print "\n</div>\n";
  2194. }
  2195. /*
  2196. * All the "Add to" areas
  2197. */
  2198. if (!empty($conf->global->PRODUCT_ADD_FORM_ADD_TO) && $object->id && ($action == '' || $action == 'view') && $object->status) {
  2199. //Variable used to check if any text is going to be printed
  2200. $html = '';
  2201. //print '<div class="fichecenter"><div class="fichehalfleft">';
  2202. // Propals
  2203. if (!empty($conf->propal->enabled) && $user->rights->propale->creer) {
  2204. $propal = new Propal($db);
  2205. $langs->load("propal");
  2206. $otherprop = $propal->liste_array(2, 1, 0);
  2207. if (is_array($otherprop) && count($otherprop)) {
  2208. $html .= '<tr><td style="width: 200px;">';
  2209. $html .= $langs->trans("AddToDraftProposals").'</td><td>';
  2210. $html .= $form->selectarray("propalid", $otherprop, 0, 1);
  2211. $html .= '</td></tr>';
  2212. } else {
  2213. $html .= '<tr><td style="width: 200px;">';
  2214. $html .= $langs->trans("AddToDraftProposals").'</td><td>';
  2215. $html .= $langs->trans("NoDraftProposals");
  2216. $html .= '</td></tr>';
  2217. }
  2218. }
  2219. // Commande
  2220. if (!empty($conf->commande->enabled) && $user->rights->commande->creer) {
  2221. $commande = new Commande($db);
  2222. $langs->load("orders");
  2223. $othercom = $commande->liste_array(2, 1, null);
  2224. if (is_array($othercom) && count($othercom)) {
  2225. $html .= '<tr><td style="width: 200px;">';
  2226. $html .= $langs->trans("AddToDraftOrders").'</td><td>';
  2227. $html .= $form->selectarray("commandeid", $othercom, 0, 1);
  2228. $html .= '</td></tr>';
  2229. } else {
  2230. $html .= '<tr><td style="width: 200px;">';
  2231. $html .= $langs->trans("AddToDraftOrders").'</td><td>';
  2232. $html .= $langs->trans("NoDraftOrders");
  2233. $html .= '</td></tr>';
  2234. }
  2235. }
  2236. // Factures
  2237. if (!empty($conf->facture->enabled) && $user->rights->facture->creer) {
  2238. $invoice = new Facture($db);
  2239. $langs->load("bills");
  2240. $otherinvoice = $invoice->liste_array(2, 1, null);
  2241. if (is_array($otherinvoice) && count($otherinvoice)) {
  2242. $html .= '<tr><td style="width: 200px;">';
  2243. $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
  2244. $html .= $form->selectarray("factureid", $otherinvoice, 0, 1);
  2245. $html .= '</td></tr>';
  2246. } else {
  2247. $html .= '<tr><td style="width: 200px;">';
  2248. $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
  2249. $html .= $langs->trans("NoDraftInvoices");
  2250. $html .= '</td></tr>';
  2251. }
  2252. }
  2253. //If any text is going to be printed, then we show the table
  2254. if (!empty($html)) {
  2255. print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
  2256. print '<input type="hidden" name="token" value="'.newToken().'">';
  2257. print '<input type="hidden" name="action" value="addin">';
  2258. print load_fiche_titre($langs->trans("AddToDraft"), '', '');
  2259. print dol_get_fiche_head('');
  2260. $html .= '<tr><td class="nowrap">'.$langs->trans("Quantity").' ';
  2261. $html .= '<input type="text" class="flat" name="qty" size="1" value="1"></td>';
  2262. $html .= '<td class="nowrap">'.$langs->trans("ReductionShort").'(%) ';
  2263. $html .= '<input type="text" class="flat" name="remise_percent" size="1" value="0">';
  2264. $html .= '</td></tr>';
  2265. print '<table width="100%" class="border">';
  2266. print $html;
  2267. print '</table>';
  2268. print '<div class="center">';
  2269. print '<input type="submit" class="button" value="'.$langs->trans("Add").'">';
  2270. print '</div>';
  2271. print dol_get_fiche_end();
  2272. print '</form>';
  2273. }
  2274. }
  2275. /*
  2276. * Generated documents
  2277. */
  2278. if ($action != 'create' && $action != 'edit' && $action != 'delete') {
  2279. print '<div class="fichecenter"><div class="fichehalfleft">';
  2280. print '<a name="builddoc"></a>'; // ancre
  2281. // Documents
  2282. $objectref = dol_sanitizeFileName($object->ref);
  2283. $relativepath = $comref.'/'.$objectref.'.pdf';
  2284. if (!empty($conf->product->multidir_output[$object->entity])) {
  2285. $filedir = $conf->product->multidir_output[$object->entity].'/'.$objectref; //Check repertories of current entities
  2286. } else {
  2287. $filedir = $conf->product->dir_output.'/'.$objectref;
  2288. }
  2289. $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
  2290. $genallowed = $usercanread;
  2291. $delallowed = $usercancreate;
  2292. print $formfile->showdocuments($modulepart, $object->ref, $filedir, $urlsource, $genallowed, $delallowed, '', 0, 0, 0, 28, 0, '', 0, '', $object->default_lang, '', $object);
  2293. $somethingshown = $formfile->numoffiles;
  2294. print '</div><div class="fichehalfright"><div class="ficheaddleft">';
  2295. $MAXEVENT = 10;
  2296. $morehtmlright = '<a href="'.DOL_URL_ROOT.'/product/agenda.php?id='.$object->id.'">';
  2297. $morehtmlright .= $langs->trans("SeeAll");
  2298. $morehtmlright .= '</a>';
  2299. // List of actions on element
  2300. include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
  2301. $formactions = new FormActions($db);
  2302. $somethingshown = $formactions->showactions($object, 'product', 0, 1, '', $MAXEVENT, '', $morehtmlright); // Show all action for product
  2303. print '</div></div></div>';
  2304. }
  2305. // End of page
  2306. llxFooter();
  2307. $db->close();