product.lib.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. <?php
  2. /* Copyright (C) 2006-2015 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  4. * Copyright (C) 2009-2010 Regis Houssin <regis.houssin@inodbox.com>
  5. * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
  6. * Copyright (C) 2015-2016 Marcos García <marcosgdf@gmail.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. * or see https://www.gnu.org/
  21. */
  22. /**
  23. * \file htdocs/core/lib/product.lib.php
  24. * \brief Ensemble de fonctions de base pour le module produit et service
  25. * \ingroup product
  26. */
  27. /**
  28. * Prepare array with list of tabs
  29. *
  30. * @param Product $object Object related to tabs
  31. * @return array Array of tabs to show
  32. */
  33. function product_prepare_head($object)
  34. {
  35. global $db, $langs, $conf, $user;
  36. $langs->load("products");
  37. $label = $langs->trans('Product');
  38. $usercancreadprice = getDolGlobalString('MAIN_USE_ADVANCED_PERMS')?$user->hasRight('product', 'product_advance', 'read_prices'):$user->hasRight('product', 'read');
  39. if ($object->isService()) {
  40. $label = $langs->trans('Service');
  41. $usercancreadprice = getDolGlobalString('MAIN_USE_ADVANCED_PERMS')?$user->hasRight('service', 'service_advance', 'read_prices'):$user->hasRight('service', 'read');
  42. }
  43. $h = 0;
  44. $head = array();
  45. $head[$h][0] = DOL_URL_ROOT."/product/card.php?id=".$object->id;
  46. $head[$h][1] = $label;
  47. $head[$h][2] = 'card';
  48. $h++;
  49. if (!empty($object->status) && $usercancreadprice) {
  50. $head[$h][0] = DOL_URL_ROOT."/product/price.php?id=".$object->id;
  51. $head[$h][1] = $langs->trans("SellingPrices");
  52. $head[$h][2] = 'price';
  53. $h++;
  54. }
  55. if (!empty($object->status_buy) || (!empty($conf->margin->enabled) && !empty($object->status))) { // If margin is on and product on sell, we may need the cost price even if product os not on purchase
  56. if ((((isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || isModEnabled("supplier_order") || isModEnabled("supplier_invoice")) && $user->rights->fournisseur->lire)
  57. || (!empty($conf->margin->enabled) && $user->rights->margin->liretous)
  58. ) {
  59. if ($usercancreadprice) {
  60. $head[$h][0] = DOL_URL_ROOT."/product/fournisseurs.php?id=".$object->id;
  61. $head[$h][1] = $langs->trans("BuyingPrices");
  62. $head[$h][2] = 'suppliers';
  63. $h++;
  64. }
  65. }
  66. }
  67. // Multilangs
  68. if (!empty($conf->global->MAIN_MULTILANGS)) {
  69. $head[$h][0] = DOL_URL_ROOT."/product/traduction.php?id=".$object->id;
  70. $head[$h][1] = $langs->trans("Translation");
  71. $head[$h][2] = 'translation';
  72. $h++;
  73. }
  74. // Sub products
  75. if (!empty($conf->global->PRODUIT_SOUSPRODUITS)) {
  76. $head[$h][0] = DOL_URL_ROOT."/product/composition/card.php?id=".$object->id;
  77. $head[$h][1] = $langs->trans('AssociatedProducts');
  78. $nbFatherAndChild = $object->hasFatherOrChild();
  79. if ($nbFatherAndChild > 0) {
  80. $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbFatherAndChild.'</span>';
  81. }
  82. $head[$h][2] = 'subproduct';
  83. $h++;
  84. }
  85. if (!empty($conf->variants->enabled) && ($object->isProduct() || $object->isService())) {
  86. global $db;
  87. require_once DOL_DOCUMENT_ROOT.'/variants/class/ProductCombination.class.php';
  88. $prodcomb = new ProductCombination($db);
  89. if ($prodcomb->fetchByFkProductChild($object->id) <= 0) {
  90. $head[$h][0] = DOL_URL_ROOT."/variants/combinations.php?id=".$object->id;
  91. $head[$h][1] = $langs->trans('ProductCombinations');
  92. $head[$h][2] = 'combinations';
  93. $nbVariant = $prodcomb->countNbOfCombinationForFkProductParent($object->id);
  94. if ($nbVariant > 0) {
  95. $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbVariant.'</span>';
  96. }
  97. }
  98. $h++;
  99. }
  100. if ($object->isProduct() || ($object->isService() && !empty($conf->global->STOCK_SUPPORTS_SERVICES))) { // If physical product we can stock (or service with option)
  101. if (!empty($conf->stock->enabled) && $user->rights->stock->lire) {
  102. $head[$h][0] = DOL_URL_ROOT."/product/stock/product.php?id=".$object->id;
  103. $head[$h][1] = $langs->trans("Stock");
  104. $head[$h][2] = 'stock';
  105. $h++;
  106. }
  107. }
  108. // Tab to link resources
  109. if (isModEnabled('resource')) {
  110. if ($object->isProduct() && !empty($conf->global->RESOURCE_ON_PRODUCTS)) {
  111. $head[$h][0] = DOL_URL_ROOT.'/resource/element_resource.php?element=product&ref='.$object->ref;
  112. $head[$h][1] = $langs->trans("Resources");
  113. $head[$h][2] = 'resources';
  114. $h++;
  115. }
  116. if ($object->isService() && !empty($conf->global->RESOURCE_ON_SERVICES)) {
  117. $head[$h][0] = DOL_URL_ROOT.'/resource/element_resource.php?element=service&ref='.$object->ref;
  118. $head[$h][1] = $langs->trans("Resources");
  119. $head[$h][2] = 'resources';
  120. $h++;
  121. }
  122. }
  123. $head[$h][0] = DOL_URL_ROOT."/product/stats/facture.php?showmessage=1&id=".$object->id;
  124. $head[$h][1] = $langs->trans('Referers');
  125. $head[$h][2] = 'referers';
  126. $h++;
  127. $head[$h][0] = DOL_URL_ROOT."/product/stats/card.php?id=".$object->id;
  128. $head[$h][1] = $langs->trans('Statistics');
  129. $head[$h][2] = 'stats';
  130. $h++;
  131. // Show more tabs from modules
  132. // Entries must be declared in modules descriptor with line
  133. // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
  134. // $this->tabs = array('entity:-tabname); to remove a tab
  135. complete_head_from_modules($conf, $langs, $object, $head, $h, 'product', 'add', 'core');
  136. // Notes
  137. if (empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
  138. $nbNote = 0;
  139. if (!empty($object->note_private)) {
  140. $nbNote++;
  141. }
  142. if (!empty($object->note_public)) {
  143. $nbNote++;
  144. }
  145. $head[$h][0] = DOL_URL_ROOT.'/product/note.php?id='.$object->id;
  146. $head[$h][1] = $langs->trans('Notes');
  147. if ($nbNote > 0) {
  148. $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbNote.'</span>';
  149. }
  150. $head[$h][2] = 'note';
  151. $h++;
  152. }
  153. // Attachments
  154. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  155. require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
  156. if (isModEnabled("product") && ($object->type == Product::TYPE_PRODUCT)) {
  157. $upload_dir = $conf->product->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
  158. }
  159. if (isModEnabled("service") && ($object->type == Product::TYPE_SERVICE)) {
  160. $upload_dir = $conf->service->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
  161. }
  162. $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
  163. if (!empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) {
  164. if (isModEnabled("product") && ($object->type == Product::TYPE_PRODUCT)) {
  165. $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'product').$object->id.'/photos';
  166. }
  167. if (isModEnabled("service") && ($object->type == Product::TYPE_SERVICE)) {
  168. $upload_dir = $conf->service->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'product').$object->id.'/photos';
  169. }
  170. $nbFiles += count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
  171. }
  172. $nbLinks = Link::count($db, $object->element, $object->id);
  173. $head[$h][0] = DOL_URL_ROOT.'/product/document.php?id='.$object->id;
  174. $head[$h][1] = $langs->trans('Documents');
  175. if (($nbFiles + $nbLinks) > 0) {
  176. $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbFiles + $nbLinks).'</span>';
  177. }
  178. $head[$h][2] = 'documents';
  179. $h++;
  180. // Log
  181. $head[$h][0] = DOL_URL_ROOT.'/product/agenda.php?id='.$object->id;
  182. $head[$h][1] = $langs->trans("Events");
  183. if (isModEnabled('agenda') && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) {
  184. $head[$h][1] .= '/';
  185. $head[$h][1] .= $langs->trans("Agenda");
  186. }
  187. $head[$h][2] = 'agenda';
  188. $h++;
  189. complete_head_from_modules($conf, $langs, $object, $head, $h, 'product', 'add', 'external');
  190. complete_head_from_modules($conf, $langs, $object, $head, $h, 'product', 'remove');
  191. return $head;
  192. }
  193. /**
  194. * Prepare array with list of tabs
  195. *
  196. * @param ProductLot $object Object related to tabs
  197. * @return array Array of tabs to show
  198. */
  199. function productlot_prepare_head($object)
  200. {
  201. global $db, $langs, $conf, $user;
  202. // Load translation files required by the page
  203. $langs->loadLangs(array("products", "productbatch"));
  204. $h = 0;
  205. $head = array();
  206. $head[$h][0] = DOL_URL_ROOT."/product/stock/productlot_card.php?id=".$object->id;
  207. $head[$h][1] = $langs->trans("Lot");
  208. $head[$h][2] = 'card';
  209. $h++;
  210. // Attachments
  211. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  212. require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
  213. $upload_dir = $conf->productbatch->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
  214. $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
  215. $nbLinks = Link::count($db, $object->element, $object->id);
  216. $head[$h][0] = DOL_URL_ROOT."/product/stock/productlot_document.php?id=".$object->id;
  217. $head[$h][1] = $langs->trans("Documents");
  218. if (($nbFiles + $nbLinks) > 0) {
  219. $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbFiles + $nbLinks).'</span>';
  220. }
  221. $head[$h][2] = 'documents';
  222. $h++;
  223. // Show more tabs from modules
  224. // Entries must be declared in modules descriptor with line
  225. // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
  226. // $this->tabs = array('entity:-tabname); to remove a tab
  227. complete_head_from_modules($conf, $langs, $object, $head, $h, 'productlot');
  228. complete_head_from_modules($conf, $langs, $object, $head, $h, 'productlot', 'remove');
  229. // Log
  230. /*
  231. $head[$h][0] = DOL_URL_ROOT.'/product/info.php?id='.$object->id;
  232. $head[$h][1] = $langs->trans("Info");
  233. $head[$h][2] = 'info';
  234. $h++;
  235. */
  236. return $head;
  237. }
  238. /**
  239. * Return array head with list of tabs to view object informations.
  240. *
  241. * @return array head array with tabs
  242. */
  243. function product_admin_prepare_head()
  244. {
  245. global $langs, $conf, $user, $db;
  246. $extrafields = new ExtraFields($db);
  247. $extrafields->fetch_name_optionals_label('product');
  248. $extrafields->fetch_name_optionals_label('product_fournisseur_price');
  249. $h = 0;
  250. $head = array();
  251. $head[$h][0] = DOL_URL_ROOT."/product/admin/product.php";
  252. $head[$h][1] = $langs->trans('Parameters');
  253. $head[$h][2] = 'general';
  254. $h++;
  255. if (!empty($conf->global->PRODUIT_MULTIPRICES) && !empty($conf->global->PRODUIT_MULTIPRICES_ALLOW_AUTOCALC_PRICELEVEL)) {
  256. $head[$h] = array(
  257. 0 => DOL_URL_ROOT."/product/admin/price_rules.php",
  258. 1 => $langs->trans('MultipriceRules'),
  259. 2 => 'generator'
  260. );
  261. $h++;
  262. }
  263. // Show more tabs from modules
  264. // Entries must be declared in modules descriptor with line
  265. // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
  266. // $this->tabs = array('entity:-tabname); to remove a tab
  267. complete_head_from_modules($conf, $langs, null, $head, $h, 'product_admin');
  268. $head[$h][0] = DOL_URL_ROOT.'/product/admin/product_extrafields.php';
  269. $head[$h][1] = $langs->trans("ExtraFields");
  270. $nbExtrafields = $extrafields->attributes['product']['count'];
  271. if ($nbExtrafields > 0) {
  272. $head[$h][1] .= ' <span class="badge">'.$nbExtrafields.'</span>';
  273. }
  274. $head[$h][2] = 'attributes';
  275. $h++;
  276. $head[$h][0] = DOL_URL_ROOT.'/product/admin/product_supplier_extrafields.php';
  277. $head[$h][1] = $langs->trans("ProductSupplierExtraFields");
  278. $nbExtrafields = $extrafields->attributes['product_fournisseur_price']['count'];
  279. if ($nbExtrafields > 0) {
  280. $head[$h][1] .= ' <span class="badge">'.$nbExtrafields.'</span>';
  281. }
  282. $head[$h][2] = 'supplierAttributes';
  283. $h++;
  284. complete_head_from_modules($conf, $langs, null, $head, $h, 'product_admin', 'remove');
  285. return $head;
  286. }
  287. /**
  288. * Return array head with list of tabs to view object informations.
  289. *
  290. * @return array head array with tabs
  291. */
  292. function product_lot_admin_prepare_head()
  293. {
  294. global $langs, $conf, $user;
  295. $h = 0;
  296. $head = array();
  297. $head[$h][0] = DOL_URL_ROOT."/product/admin/product_lot.php";
  298. $head[$h][1] = $langs->trans('Parameters');
  299. $head[$h][2] = 'settings';
  300. $h++;
  301. // Show more tabs from modules
  302. // Entries must be declared in modules descriptor with line
  303. // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
  304. // $this->tabs = array('entity:-tabname); to remove a tab
  305. complete_head_from_modules($conf, $langs, null, $head, $h, 'product_lot_admin');
  306. $head[$h][0] = DOL_URL_ROOT.'/product/admin/product_lot_extrafields.php';
  307. $head[$h][1] = $langs->trans("ExtraFields");
  308. $head[$h][2] = 'attributes';
  309. $h++;
  310. complete_head_from_modules($conf, $langs, null, $head, $h, 'product_lot_admin', 'remove');
  311. return $head;
  312. }
  313. /**
  314. * Show stats for company
  315. *
  316. * @param Product $product Product object
  317. * @param int $socid Thirdparty id
  318. * @return integer NB of lines shown into array
  319. */
  320. function show_stats_for_company($product, $socid)
  321. {
  322. global $conf, $langs, $user, $db, $hookmanager;
  323. $form = new Form($db);
  324. $nblines = 0;
  325. print '<tr class="liste_titre">';
  326. print '<td class="left" width="25%">'.$langs->trans("Referers").'</td>';
  327. print '<td class="right" width="25%">'.$langs->trans("NbOfThirdParties").'</td>';
  328. print '<td class="right" width="25%">'.$langs->trans("NbOfObjectReferers").'</td>';
  329. print '<td class="right" width="25%">'.$langs->trans("TotalQuantity").'</td>';
  330. print '</tr>';
  331. // Customer proposals
  332. if (isModEnabled("propal") && $user->rights->propale->lire) {
  333. $nblines++;
  334. $ret = $product->load_stats_propale($socid);
  335. if ($ret < 0) {
  336. dol_print_error($db);
  337. }
  338. $langs->load("propal");
  339. print '<tr><td>';
  340. print '<a href="propal.php?id='.$product->id.'">'.img_object('', 'propal', 'class="pictofixedwidth"').$langs->trans("Proposals").'</a>';
  341. print '</td><td class="right">';
  342. print $product->stats_propale['customers'];
  343. print '</td><td class="right">';
  344. print $product->stats_propale['nb'];
  345. print '</td><td class="right">';
  346. print $product->stats_propale['qty'];
  347. print '</td>';
  348. print '</tr>';
  349. }
  350. // Supplier proposals
  351. if (isModEnabled('supplier_proposal') && $user->rights->supplier_proposal->lire) {
  352. $nblines++;
  353. $ret = $product->load_stats_proposal_supplier($socid);
  354. if ($ret < 0) {
  355. dol_print_error($db);
  356. }
  357. $langs->load("supplier_proposal");
  358. print '<tr><td>';
  359. print '<a href="supplier_proposal.php?id='.$product->id.'">'.img_object('', 'supplier_proposal', 'class="pictofixedwidth"').$langs->trans("SupplierProposals").'</a>';
  360. print '</td><td class="right">';
  361. print $product->stats_proposal_supplier['suppliers'];
  362. print '</td><td class="right">';
  363. print $product->stats_proposal_supplier['nb'];
  364. print '</td><td class="right">';
  365. print $product->stats_proposal_supplier['qty'];
  366. print '</td>';
  367. print '</tr>';
  368. }
  369. // Customer orders
  370. if (isModEnabled('commande') && $user->rights->commande->lire) {
  371. $nblines++;
  372. $ret = $product->load_stats_commande($socid);
  373. if ($ret < 0) {
  374. dol_print_error($db);
  375. }
  376. $langs->load("orders");
  377. print '<tr><td>';
  378. print '<a href="commande.php?id='.$product->id.'">'.img_object('', 'order', 'class="pictofixedwidth"').$langs->trans("CustomersOrders").'</a>';
  379. print '</td><td class="right">';
  380. print $product->stats_commande['customers'];
  381. print '</td><td class="right">';
  382. print $product->stats_commande['nb'];
  383. print '</td><td class="right">';
  384. print $product->stats_commande['qty'];
  385. print '</td>';
  386. print '</tr>';
  387. }
  388. // Supplier orders
  389. if ((isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->commande->lire) || (isModEnabled("supplier_order") && $user->rights->supplier_order->lire)) {
  390. $nblines++;
  391. $ret = $product->load_stats_commande_fournisseur($socid);
  392. if ($ret < 0) {
  393. dol_print_error($db);
  394. }
  395. $langs->load("orders");
  396. print '<tr><td>';
  397. print '<a href="commande_fournisseur.php?id='.$product->id.'">'.img_object('', 'supplier_order', 'class="pictofixedwidth"').$langs->trans("SuppliersOrders").'</a>';
  398. print '</td><td class="right">';
  399. print $product->stats_commande_fournisseur['suppliers'];
  400. print '</td><td class="right">';
  401. print $product->stats_commande_fournisseur['nb'];
  402. print '</td><td class="right">';
  403. print $product->stats_commande_fournisseur['qty'];
  404. print '</td>';
  405. print '</tr>';
  406. }
  407. // Customer invoices
  408. if (isModEnabled('facture') && $user->rights->facture->lire) {
  409. $nblines++;
  410. $ret = $product->load_stats_facture($socid);
  411. if ($ret < 0) {
  412. dol_print_error($db);
  413. }
  414. $langs->load("bills");
  415. print '<tr><td>';
  416. print '<a href="facture.php?id='.$product->id.'">'.img_object('', 'bill', 'class="pictofixedwidth"').$langs->trans("CustomersInvoices").'</a>';
  417. print '</td><td class="right">';
  418. print $product->stats_facture['customers'];
  419. print '</td><td class="right">';
  420. print $product->stats_facture['nb'];
  421. print '</td><td class="right">';
  422. print $product->stats_facture['qty'];
  423. print '</td>';
  424. print '</tr>';
  425. }
  426. // Customer template invoices
  427. if (isModEnabled("facture") && $user->rights->facture->lire) {
  428. $nblines++;
  429. $ret = $product->load_stats_facturerec($socid);
  430. if ($ret < 0) {
  431. dol_print_error($db);
  432. }
  433. $langs->load("bills");
  434. print '<tr><td>';
  435. print '<a href="facturerec.php?id='.$product->id.'">'.img_object('', 'bill', 'class="pictofixedwidth"').$langs->trans("RecurringInvoiceTemplate").'</a>';
  436. print '</td><td class="right">';
  437. print $product->stats_facture['customers'];
  438. print '</td><td class="right">';
  439. print $product->stats_facturerec['nb'];
  440. print '</td><td class="right">';
  441. print $product->stats_facturerec['qty'];
  442. print '</td>';
  443. print '</tr>';
  444. }
  445. // Supplier invoices
  446. if ((isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire) || (isModEnabled("supplier_invoice") && $user->rights->supplier_invoice->lire)) {
  447. $nblines++;
  448. $ret = $product->load_stats_facture_fournisseur($socid);
  449. if ($ret < 0) {
  450. dol_print_error($db);
  451. }
  452. $langs->load("bills");
  453. print '<tr><td>';
  454. print '<a href="facture_fournisseur.php?id='.$product->id.'">'.img_object('', 'supplier_invoice', 'class="pictofixedwidth"').$langs->trans("SuppliersInvoices").'</a>';
  455. print '</td><td class="right">';
  456. print $product->stats_facture_fournisseur['suppliers'];
  457. print '</td><td class="right">';
  458. print $product->stats_facture_fournisseur['nb'];
  459. print '</td><td class="right">';
  460. print $product->stats_facture_fournisseur['qty'];
  461. print '</td>';
  462. print '</tr>';
  463. }
  464. // Contracts
  465. if (isModEnabled('contrat') && $user->rights->contrat->lire) {
  466. $nblines++;
  467. $ret = $product->load_stats_contrat($socid);
  468. if ($ret < 0) {
  469. dol_print_error($db);
  470. }
  471. $langs->load("contracts");
  472. print '<tr><td>';
  473. print '<a href="contrat.php?id='.$product->id.'">'.img_object('', 'contract', 'class="pictofixedwidth"').$langs->trans("Contracts").'</a>';
  474. print '</td><td class="right">';
  475. print $product->stats_contrat['customers'];
  476. print '</td><td class="right">';
  477. print $product->stats_contrat['nb'];
  478. print '</td><td class="right">';
  479. print $product->stats_contrat['qty'];
  480. print '</td>';
  481. print '</tr>';
  482. }
  483. // BOM
  484. if (!empty($conf->bom->enabled) && $user->rights->bom->read) {
  485. $nblines++;
  486. $ret = $product->load_stats_bom($socid);
  487. if ($ret < 0) {
  488. setEventMessage($product->error, 'errors');
  489. }
  490. $langs->load("mrp");
  491. print '<tr><td>';
  492. print '<a href="bom.php?id='.$product->id.'">'.img_object('', 'bom', 'class="pictofixedwidth"').$langs->trans("BOM").'</a>';
  493. print '</td><td class="right">';
  494. print '</td><td class="right">';
  495. print $form->textwithpicto($product->stats_bom['nb_toconsume'], $langs->trans("RowMaterial"));
  496. print $form->textwithpicto($product->stats_bom['nb_toproduce'], $langs->trans("Finished"));
  497. print '</td><td class="right">';
  498. print $form->textwithpicto($product->stats_bom['qty_toconsume'], $langs->trans("RowMaterial"));
  499. print $form->textwithpicto($product->stats_bom['qty_toproduce'], $langs->trans("Finished"));
  500. print '</td>';
  501. print '</tr>';
  502. }
  503. // MO
  504. if (!empty($conf->mrp->enabled) && !empty($user->rights->mrp->read)) {
  505. $nblines++;
  506. $ret = $product->load_stats_mo($socid);
  507. if ($ret < 0) {
  508. setEventMessages($product->error, $product->errors, 'errors');
  509. }
  510. $langs->load("mrp");
  511. print '<tr><td>';
  512. print '<a href="mo.php?id='.$product->id.'">'.img_object('', 'mrp', 'class="pictofixedwidth"').$langs->trans("MO").'</a>';
  513. print '</td><td class="right">';
  514. print $form->textwithpicto($product->stats_mo['customers_toconsume'], $langs->trans("ToConsume"));
  515. print $form->textwithpicto($product->stats_mo['customers_consumed'], $langs->trans("QtyAlreadyConsumed"));
  516. print $form->textwithpicto($product->stats_mo['customers_toproduce'], $langs->trans("QtyToProduce"));
  517. print $form->textwithpicto($product->stats_mo['customers_produced'], $langs->trans("QtyAlreadyProduced"));
  518. print '</td><td class="right">';
  519. print $form->textwithpicto($product->stats_mo['nb_toconsume'], $langs->trans("ToConsume"));
  520. print $form->textwithpicto($product->stats_mo['nb_consumed'], $langs->trans("QtyAlreadyConsumed"));
  521. print $form->textwithpicto($product->stats_mo['nb_toproduce'], $langs->trans("QtyToProduce"));
  522. print $form->textwithpicto($product->stats_mo['nb_produced'], $langs->trans("QtyAlreadyProduced"));
  523. print '</td><td class="right">';
  524. print $form->textwithpicto($product->stats_mo['qty_toconsume'], $langs->trans("ToConsume"));
  525. print $form->textwithpicto($product->stats_mo['qty_consumed'], $langs->trans("QtyAlreadyConsumed"));
  526. print $form->textwithpicto($product->stats_mo['qty_toproduce'], $langs->trans("QtyToProduce"));
  527. print $form->textwithpicto($product->stats_mo['qty_produced'], $langs->trans("QtyAlreadyProduced"));
  528. print '</td>';
  529. print '</tr>';
  530. }
  531. $parameters = array('socid'=>$socid);
  532. $reshook = $hookmanager->executeHooks('addMoreProductStat', $parameters, $product, $nblines); // Note that $action and $object may have been modified by some hooks
  533. if ($reshook < 0) {
  534. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  535. }
  536. print $hookmanager->resPrint;
  537. return $nblines++;
  538. }
  539. /**
  540. * Return translation label of a unit key.
  541. * Function kept for backward compatibility.
  542. *
  543. * @param string $scale Scale of unit: '0', '-3', '6', ...
  544. * @param string $measuring_style Style of unit: weight, volume,...
  545. * @param int $unit ID of unit (rowid in llx_c_units table)
  546. * @param int $use_short_label 1=Use short label ('g' instead of 'gram'). Short labels are not translated.
  547. * @param Translate $outputlangs Language object
  548. * @return string Unit string
  549. * @see measuringUnitString() formproduct->selectMeasuringUnits()
  550. */
  551. function measuring_units_string($scale = '', $measuring_style = '', $unit = 0, $use_short_label = 0, $outputlangs = null)
  552. {
  553. return measuringUnitString($unit, $measuring_style, $scale, $use_short_label, $outputlangs);
  554. }
  555. /**
  556. * Return translation label of a unit key
  557. *
  558. * @param int $unit ID of unit (rowid in llx_c_units table)
  559. * @param string $measuring_style Style of unit: 'weight', 'volume', ..., '' = 'net_measure' for option PRODUCT_ADD_NET_MEASURE
  560. * @param string $scale Scale of unit: '0', '-3', '6', ...
  561. * @param int $use_short_label 1=Use short label ('g' instead of 'gram'). Short labels are not translated.
  562. * @param Translate $outputlangs Language object
  563. * @return string Unit string
  564. * @see formproduct->selectMeasuringUnits()
  565. */
  566. function measuringUnitString($unit, $measuring_style = '', $scale = '', $use_short_label = 0, $outputlangs = null)
  567. {
  568. global $langs, $db;
  569. global $measuring_unit_cache;
  570. if (empty($outputlangs)) {
  571. $outputlangs = $langs;
  572. }
  573. if (empty($measuring_unit_cache[$unit.'_'.$measuring_style.'_'.$scale.'_'.$use_short_label])) {
  574. require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
  575. $measuringUnits = new CUnits($db);
  576. if ($measuring_style == '' && $scale == '') {
  577. $arrayforfilter = array(
  578. 't.rowid' => $unit,
  579. 't.active' => 1
  580. );
  581. } elseif ($scale !== '') {
  582. $arrayforfilter = array(
  583. 't.scale' => $scale,
  584. 't.unit_type' => $measuring_style,
  585. 't.active' => 1
  586. );
  587. } else {
  588. $arrayforfilter = array(
  589. 't.rowid' => $unit,
  590. 't.unit_type' => $measuring_style,
  591. 't.active' => 1
  592. );
  593. }
  594. $result = $measuringUnits->fetchAll('', '', 0, 0, $arrayforfilter);
  595. if ($result < 0) {
  596. return -1;
  597. } else {
  598. if (is_array($measuringUnits->records) && count($measuringUnits->records) > 0) {
  599. if ($use_short_label) {
  600. $labeltoreturn = $measuringUnits->records[key($measuringUnits->records)]->short_label;
  601. } else {
  602. $labeltoreturn = $outputlangs->transnoentitiesnoconv($measuringUnits->records[key($measuringUnits->records)]->label);
  603. }
  604. } else {
  605. $labeltoreturn = '';
  606. }
  607. $measuring_unit_cache[$unit.'_'.$measuring_style.'_'.$scale.'_'.$use_short_label] = $labeltoreturn;
  608. return $labeltoreturn;
  609. }
  610. } else {
  611. return $measuring_unit_cache[$unit.'_'.$measuring_style.'_'.$scale.'_'.$use_short_label];
  612. }
  613. }
  614. /**
  615. * Transform a given unit scale into the square of that unit, if known.
  616. *
  617. * @param int $unit Unit scale key (-3,-2,-1,0,98,99...)
  618. * @return int Squared unit key (-6,-4,-2,0,98,99...)
  619. * @see formproduct->selectMeasuringUnits
  620. */
  621. function measuring_units_squared($unit)
  622. {
  623. $measuring_units = array();
  624. $measuring_units[0] = 0; // m -> m3
  625. $measuring_units[-1] = -2; // dm-> dm2
  626. $measuring_units[-2] = -4; // cm -> cm2
  627. $measuring_units[-3] = -6; // mm -> mm2
  628. $measuring_units[98] = 98; // foot -> foot2
  629. $measuring_units[99] = 99; // inch -> inch2
  630. return $measuring_units[$unit];
  631. }
  632. /**
  633. * Transform a given unit scale into the cube of that unit, if known
  634. *
  635. * @param int $unit Unit scale key (-3,-2,-1,0,98,99...)
  636. * @return int Cubed unit key (-9,-6,-3,0,88,89...)
  637. * @see formproduct->selectMeasuringUnits
  638. */
  639. function measuring_units_cubed($unit)
  640. {
  641. $measuring_units = array();
  642. $measuring_units[0] = 0; // m -> m2
  643. $measuring_units[-1] = -3; // dm-> dm3
  644. $measuring_units[-2] = -6; // cm -> cm3
  645. $measuring_units[-3] = -9; // mm -> mm3
  646. $measuring_units[98] = 88; // foot -> foot3
  647. $measuring_units[99] = 89; // inch -> inch3
  648. return $measuring_units[$unit];
  649. }