dolibarr  17.0.4
price.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
5  * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
6  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
7  * Copyright (C) 2014 Florian Henry <florian.henry@open-concept.pro>
8  * Copyright (C) 2014-2018 Juanjo Menent <jmenent@2byte.es>
9  * Copyright (C) 2014-2019 Philippe Grand <philippe.grand@atoo-net.com>
10  * Copyright (C) 2014 Ion agorria <ion@agorria.com>
11  * Copyright (C) 2015 Alexandre Spangaro <aspangaro@open-dsi.fr>
12  * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
13  * Copyright (C) 2016 Ferran Marcet <fmarcet@2byte.es>
14  * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
15  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program. If not, see <https://www.gnu.org/licenses/>.
29  */
30 
37 // Load Dolibarr environment
38 require '../main.inc.php';
39 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
40 require_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
41 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
42 require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_expression.class.php';
43 require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
44 
45 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
46  require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
47 
48  $prodcustprice = new Productcustomerprice($db);
49 }
50 
51 // Load translation files required by the page
52 $langs->loadLangs(array('products', 'bills', 'companies', 'other'));
53 
54 $error = 0;
55 $errors = array();
56 
57 $id = GETPOST('id', 'int');
58 $ref = GETPOST('ref', 'alpha');
59 $action = GETPOST('action', 'aZ09');
60 $cancel = GETPOST('cancel', 'alpha');
61 $eid = GETPOST('eid', 'int');
62 
63 $search_soc = GETPOST('search_soc');
64 
65 // Security check
66 $fieldvalue = (!empty($id) ? $id : (!empty($ref) ? $ref : ''));
67 $fieldtype = (!empty($ref) ? 'ref' : 'rowid');
68 if ($user->socid) {
69  $socid = $user->socid;
70 }
71 
72 if ($id > 0 || !empty($ref)) {
73  $object = new Product($db);
74  $object->fetch($id, $ref);
75 }
76 
77 // Clean param
78 if ((!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && empty($conf->global->PRODUIT_MULTIPRICES_LIMIT)) {
79  $conf->global->PRODUIT_MULTIPRICES_LIMIT = 5;
80 }
81 
82 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
83 $hookmanager->initHooks(array('productpricecard', 'globalcard'));
84 
85 if ($object->id > 0) {
86  if ($object->type == $object::TYPE_PRODUCT) {
87  restrictedArea($user, 'produit', $object->id, 'product&product', '', '');
88  }
89  if ($object->type == $object::TYPE_SERVICE) {
90  restrictedArea($user, 'service', $object->id, 'product&product', '', '');
91  }
92 } else {
93  restrictedArea($user, 'produit|service', $fieldvalue, 'product&product', '', '', $fieldtype);
94 }
95 
96 
97 /*
98  * Actions
99  */
100 
101 if ($cancel) {
102  $action = '';
103 }
104 
105 $parameters = array('id'=>$id, 'ref'=>$ref);
106 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
107 if ($reshook < 0) {
108  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
109 }
110 
111 if (empty($reshook)) {
112  if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
113  $search_soc = '';
114  }
115 
116  if ($action == 'setlabelsellingprice' && $user->admin) {
117  require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
118  $keyforlabel = 'PRODUIT_MULTIPRICES_LABEL'.GETPOST('pricelevel');
119  dolibarr_set_const($db, $keyforlabel, GETPOST('labelsellingprice', 'alpha'), 'chaine', 0, '', $conf->entity);
120  $action = '';
121  }
122 
123  if (($action == 'update_vat') && !$cancel && ($user->rights->produit->creer || $user->rights->service->creer)) {
124  $tva_tx_txt = GETPOST('tva_tx', 'alpha'); // tva_tx can be '8.5' or '8.5*' or '8.5 (XXX)' or '8.5* (XXX)'
125 
126  // We must define tva_tx, npr and local taxes
127  $tva_tx = $tva_tx_txt;
128  $reg = array();
129  $vatratecode = '';
130  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
131  $vatratecode = $reg[1];
132  $tva_tx = preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx_txt); // Remove code into vatrate.
133  }
134 
135  $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot
136  $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
137  $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0';
138  // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes
139 
140  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
141  // We look into database using code (we can't use get_localtax() because it depends on buyer that is not known). Same in create product.
142  $vatratecode = $reg[1];
143  // Get record from code
144  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
145  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
146  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
147  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
148  $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
149  $resql = $db->query($sql);
150  if ($resql) {
151  $obj = $db->fetch_object($resql);
152  if ($obj) {
153  $npr = $obj->recuperableonly;
154  $localtax1 = $obj->localtax1;
155  $localtax2 = $obj->localtax2;
156  $localtax1_type = $obj->localtax1_type;
157  $localtax2_type = $obj->localtax2_type;
158  }
159  }
160  } else {
161  // Get record with empty code
162  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
163  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
164  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
165  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
166  $sql .= " AND t.code = ''";
167  $resql = $db->query($sql);
168  if ($resql) {
169  $obj = $db->fetch_object($resql);
170  if ($obj) {
171  $npr = $obj->recuperableonly;
172  $localtax1 = $obj->localtax1;
173  $localtax2 = $obj->localtax2;
174  $localtax1_type = $obj->localtax1_type;
175  $localtax2_type = $obj->localtax2_type;
176  }
177  }
178  }
179 
180  $object->default_vat_code = $vatratecode;
181  $object->tva_tx = $tva_tx;
182  $object->tva_npr = $npr;
183  $object->localtax1_tx = $localtax1;
184  $object->localtax2_tx = $localtax2;
185  $object->localtax1_type = $localtax1_type;
186  $object->localtax2_type = $localtax2_type;
187 
188  $db->begin();
189 
190  $resql = $object->update($object->id, $user);
191  if ($resql <= 0) {
192  $error++;
193  setEventMessages($object->error, $object->errors, 'errors');
194  }
195 
196  if (!$error) {
197  if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
198  for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
199  // Force the update of the price of the product using the new VAT
200  if ($object->multiprices_base_type[$i] == 'HT') {
201  $oldprice = $object->multiprices[$i];
202  $oldminprice = $object->multiprices_min[$i];
203  } else {
204  $oldprice = $object->multiprices_ttc[$i];
205  $oldminprice = $object->multiprices_min_ttc[$i];
206  }
207  $oldpricebasetype = $object->multiprices_base_type[$i];
208  $oldnpr = $object->multiprices_recuperableonly[$i];
209 
210  //$localtaxarray=array('0'=>$localtax1_type,'1'=>$localtax1,'2'=>$localtax2_type,'3'=>$localtax2);
211  $localtaxarray = array(); // We do not store localtaxes into product, we will use instead the "vat code" to retrieve them.
212  $level = $i;
213  $ret = $object->updatePrice($oldprice, $oldpricebasetype, $user, $tva_tx, $oldminprice, $level, $oldnpr, 0, 0, $localtaxarray, $vatratecode);
214 
215  if ($ret < 0) {
216  $error++;
217  setEventMessages($object->error, $object->errors, 'errors');
218  }
219  }
220  } else {
221  // Force the update of the price of the product using the new VAT
222  if ($object->price_base_type == 'HT') {
223  $oldprice = $object->price;
224  $oldminprice = $object->price_min;
225  } else {
226  $oldprice = $object->price_ttc;
227  $oldminprice = $object->price_min_ttc;
228  }
229  $oldpricebasetype = $object->price_base_type;
230  $oldnpr = $object->tva_npr;
231 
232  //$localtaxarray=array('0'=>$localtax1_type,'1'=>$localtax1,'2'=>$localtax2_type,'3'=>$localtax2);
233  $localtaxarray = array(); // We do not store localtaxes into product, we will use instead the "vat code" to retrieve them when required.
234  $level = 0;
235  $ret = $object->updatePrice($oldprice, $oldpricebasetype, $user, $tva_tx, $oldminprice, $level, $oldnpr, 0, 0, $localtaxarray, $vatratecode);
236 
237  if ($ret < 0) {
238  $error++;
239  setEventMessages($object->error, $object->errors, 'errors');
240  }
241  }
242  }
243 
244  if (!$error) {
245  $db->commit();
246  } else {
247  $db->rollback();
248  }
249 
250  $action = '';
251  }
252 
253  if (($action == 'update_price') && !$cancel && $object->getRights()->creer) {
254  $error = 0;
255  $pricestoupdate = array();
256 
257  $psq = GETPOST('psqflag');
258  $psq = empty($newpsq) ? 0 : $newpsq;
259  $maxpricesupplier = $object->min_recommended_price();
260 
261  if (isModEnabled('dynamicprices')) {
262  $object->fk_price_expression = empty($eid) ? 0 : $eid; //0 discards expression
263 
264  if ($object->fk_price_expression != 0) {
265  //Check the expression validity by parsing it
266  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
267  $priceparser = new PriceParser($db);
268 
269  if ($priceparser->parseProduct($object) < 0) {
270  $error++;
271  setEventMessages($priceparser->translatedError(), null, 'errors');
272  }
273  }
274  }
275 
276  // Multiprices
277  if (!$error && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) {
278  $newprice = GETPOST('price', 'array');
279  $newprice_min = GETPOST('price_min', 'array');
280  $newpricebase = GETPOST('multiprices_base_type', 'array');
281  $newvattx = GETPOST('tva_tx', 'array');
282  $newvatnpr = GETPOST('tva_npr', 'array');
283  $newlocaltax1_tx = GETPOST('localtax1_tx', 'array');
284  $newlocaltax1_type = GETPOST('localtax1_type', 'array');
285  $newlocaltax2_tx = GETPOST('localtax2_tx', 'array');
286  $newlocaltax2_type = GETPOST('localtax2_type', 'array');
287 
288  //Shall we generate prices using price rules?
289  $object->price_autogen = GETPOST('usePriceRules') == 'on';
290 
291  for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
292  if (!isset($newprice[$i])) {
293  continue;
294  }
295 
296  $tva_tx_txt = $newvattx[$i];
297 
298  $tva_tx = $tva_tx_txt;
299  $vatratecode = '';
300  $reg = array();
301  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
302  $vat_src_code = $reg[1];
303  $tva_tx = preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx_txt); // Remove code into vatrate.
304  }
305  $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot
306 
307  $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
308  $localtax1 = $newlocaltax1_tx[$i];
309  $localtax1_type = $newlocaltax1_type[$i];
310  $localtax2 = $newlocaltax2_tx[$i];
311  $localtax2_type = $newlocaltax2_type[$i];
312  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
313  // We look into database using code
314  $vatratecode = $reg[1];
315  // Get record from code
316  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
317  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
318  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
319  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
320  $sql .= " AND t.code ='".$db->escape($vatratecode)."'";
321  $resql = $db->query($sql);
322  if ($resql) {
323  $obj = $db->fetch_object($resql);
324  if ($obj) {
325  $npr = $obj->recuperableonly;
326  $localtax1 = $obj->localtax1;
327  $localtax2 = $obj->localtax2;
328  $localtax1_type = $obj->localtax1_type;
329  $localtax2_type = $obj->localtax2_type;
330  }
331 
332  // If spain, we don't use the localtax found into tax record in database with same code, but using the get_localtax rule.
333  if (in_array($mysoc->country_code, array('ES'))) {
334  $localtax1 = get_localtax($tva_tx, 1);
335  $localtax2 = get_localtax($tva_tx, 2);
336  }
337  }
338  } else {
339  // Get record with empty code
340  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
341  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
342  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
343  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
344  $sql .= " AND t.code = ''";
345  $resql = $db->query($sql);
346  if ($resql) {
347  $obj = $db->fetch_object($resql);
348  if ($obj) {
349  $npr = $obj->recuperableonly;
350  $localtax1 = $obj->localtax1;
351  $localtax2 = $obj->localtax2;
352  $localtax1_type = $obj->localtax1_type;
353  $localtax2_type = $obj->localtax2_type;
354  }
355  }
356  }
357 
358  $pricestoupdate[$i] = array(
359  'price' => price2num($newprice[$i], '', 2),
360  'price_min' => price2num($newprice_min[$i], '', 2),
361  'price_base_type' => $newpricebase[$i],
362  'default_vat_code' => $vatratecode,
363  'vat_tx' => $tva_tx, // default_vat_code should be used in priority in a future
364  'npr' => $npr, // default_vat_code should be used in priority in a future
365  'localtaxes_array' => array('0'=>$localtax1_type, '1'=>$localtax1, '2'=>$localtax2_type, '3'=>$localtax2) // default_vat_code should be used in priority in a future
366  );
367 
368  //If autogeneration is enabled, then we only set the first level
369  if ($object->price_autogen) {
370  break;
371  }
372  }
373  } elseif (!$error) {
374  $newprice = price2num(GETPOST('price', 'alpha'), '', 2);
375  $newprice_min = price2num(GETPOST('price_min', 'alpha'), '', 2);
376  $newpricebase = GETPOST('price_base_type', 'alpha');
377  $tva_tx_txt = GETPOST('tva_tx', 'alpha'); // tva_tx can be '8.5' or '8.5*' or '8.5 (XXX)' or '8.5* (XXX)'
378 
379  $tva_tx = $tva_tx_txt;
380  $vatratecode = '';
381  $reg = array();
382  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
383  $vat_src_code = $reg[1];
384  $tva_tx = preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx_txt); // Remove code into vatrate.
385  }
386  $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot
387 
388  $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
389  $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0';
390  // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes
391  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
392  // We look into database using code
393  $vatratecode = $reg[1];
394  // Get record from code
395  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
396  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
397  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
398  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
399  $sql .= " AND t.code ='".$db->escape($vatratecode)."'";
400  $resql = $db->query($sql);
401  if ($resql) {
402  $obj = $db->fetch_object($resql);
403  if ($obj) {
404  $npr = $obj->recuperableonly;
405  $localtax1 = $obj->localtax1;
406  $localtax2 = $obj->localtax2;
407  $localtax1_type = $obj->localtax1_type;
408  $localtax2_type = $obj->localtax2_type;
409  }
410 
411  // If spain, we don't use the localtax found into tax record in database with same code, but using the get_localtax rule.
412  if (in_array($mysoc->country_code, array('ES'))) {
413  $localtax1 = get_localtax($tva_tx, 1);
414  $localtax2 = get_localtax($tva_tx, 2);
415  }
416  }
417  } else {
418  // Get record with empty code
419  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
420  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
421  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
422  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
423  $sql .= " AND t.code = ''";
424  $resql = $db->query($sql);
425  if ($resql) {
426  $obj = $db->fetch_object($resql);
427  if ($obj) {
428  $npr = $obj->recuperableonly;
429  $localtax1 = $obj->localtax1;
430  $localtax2 = $obj->localtax2;
431  $localtax1_type = $obj->localtax1_type;
432  $localtax2_type = $obj->localtax2_type;
433  }
434  }
435  }
436 
437  $pricestoupdate[0] = array(
438  'price' => $newprice,
439  'price_min' => $newprice_min,
440  'price_base_type' => $newpricebase,
441  'default_vat_code' => $vatratecode,
442  'vat_tx' => $tva_tx, // default_vat_code should be used in priority in a future
443  'npr' => $npr, // default_vat_code should be used in priority in a future
444  'localtaxes_array' => array('0'=>$localtax1_type, '1'=>$localtax1, '2'=>$localtax2_type, '3'=>$localtax2) // default_vat_code should be used in priority in a future
445  );
446  }
447 
448  if (!$error) {
449  $db->begin();
450 
451  foreach ($pricestoupdate as $key => $val) {
452  $newprice = $val['price'];
453 
454  if ($val['price'] < $val['price_min'] && !empty($object->fk_price_expression)) {
455  $newprice = $val['price_min']; //Set price same as min, the user will not see the
456  }
457 
458  $newprice = price2num($newprice, 'MU');
459  $newprice_min = price2num($val['price_min'], 'MU');
460  $newvattx = price2num($val['vat_tx']);
461 
462  if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE) && $newprice_min < $maxpricesupplier) {
463  setEventMessages($langs->trans("MinimumPriceLimit", price($maxpricesupplier, 0, '', 1, - 1, - 1, 'auto')), null, 'errors');
464  $error++;
465  break;
466  }
467 
468  // If price has changed, we update it
469  if (!array_key_exists($key, $object->multiprices) || $object->multiprices[$key] != $newprice || $object->multiprices_min[$key] != $newprice_min || $object->multiprices_base_type[$key] != $val['price_base_type'] || $object->multiprices_tva_tx[$key] != $newvattx) {
470  $res = $object->updatePrice($newprice, $val['price_base_type'], $user, $val['vat_tx'], $newprice_min, $key, $val['npr'], $psq, 0, $val['localtaxes_array'], $val['default_vat_code']);
471  } else {
472  $res = 0;
473  }
474 
475  if ($res < 0) {
476  $error++;
477  setEventMessages($object->error, $object->errors, 'errors');
478  break;
479  }
480  }
481  }
482 
483  if (!$error && $object->update($object->id, $user) < 0) {
484  $error++;
485  setEventMessages($object->error, $object->errors, 'errors');
486  }
487 
488  if (empty($error)) {
489  $action = '';
490  setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
491  $db->commit();
492  } else {
493  $action = 'edit_price';
494  $db->rollback();
495  }
496  }
497 
498 
499  if ($action == 'delete' && $user->rights->produit->supprimer) {
500  $result = $object->log_price_delete($user, GETPOST('lineid', 'int'));
501  if ($result < 0) {
502  setEventMessages($object->error, $object->errors, 'errors');
503  }
504  }
505 
506  // Set Price by quantity
507  if ($action == 'activate_price_by_qty') {
508  // Activating product price by quantity add a new price line with price_by_qty set to 1
509  $level = GETPOST('level', 'int');
510  $ret = $object->updatePrice(0, $object->price_base_type, $user, $object->tva_tx, 0, $level, $object->tva_npr, 1);
511 
512  if ($ret < 0) {
513  setEventMessages($object->error, $object->errors, 'errors');
514  }
515  }
516  // Unset Price by quantity
517  if ($action == 'disable_price_by_qty') {
518  // Disabling product price by quantity add a new price line with price_by_qty set to 0
519  $level = GETPOST('level', 'int');
520  $ret = $object->updatePrice(0, $object->price_base_type, $user, $object->tva_tx, 0, $level, $object->tva_npr, 0);
521 
522  if ($ret < 0) {
523  setEventMessages($object->error, $object->errors, 'errors');
524  }
525  }
526 
527  if ($action == 'edit_price_by_qty') { // Edition d'un prix par quantité
528  $rowid = GETPOST('rowid', 'int');
529  }
530 
531  // Add or update price by quantity
532  if ($action == 'update_price_by_qty') {
533  // Récupération des variables
534  $rowid = GETPOST('rowid', 'int');
535  $priceid = GETPOST('priceid', 'int');
536  $newprice = price2num(GETPOST("price"), 'MU', 2);
537  // $newminprice=price2num(GETPOST("price_min"),'MU'); // TODO : Add min price management
538  $quantity = price2num(GETPOST('quantity'), 'MS', 2);
539  $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
540  $remise = 0; // TODO : allow discount by amount when available on documents
541 
542  if (empty($quantity)) {
543  $error++;
544  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Qty")), null, 'errors');
545  }
546  if (empty($newprice)) {
547  $error++;
548  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Price")), null, 'errors');
549  }
550  if (!$error) {
551  // Calcul du prix HT et du prix unitaire
552  if ($object->price_base_type == 'TTC') {
553  $price = price2num($newprice) / (1 + ($object->tva_tx / 100));
554  }
555 
556  $price = price2num($newprice, 'MU');
557  $unitPrice = price2num($price / $quantity, 'MU');
558 
559  // Ajout / mise à jour
560  if ($rowid > 0) {
561  $sql = "UPDATE ".MAIN_DB_PREFIX."product_price_by_qty SET";
562  $sql .= " price=".((float) $price).",";
563  $sql .= " unitprice=".((float) $unitPrice).",";
564  $sql .= " quantity=".((float) $quantity).",";
565  $sql .= " remise_percent=".((float) $remise_percent).",";
566  $sql .= " remise=".((float) $remise);
567  $sql .= " WHERE rowid = ".((int) $rowid);
568 
569  $result = $db->query($sql);
570  if (!$result) {
571  dol_print_error($db);
572  }
573  } else {
574  $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,unitprice,quantity,remise_percent,remise) values (";
575  $sql .= ((int) $priceid).','.((float) $price).','.((float) $unitPrice).','.((float) $quantity).','.((float) $remise_percent).','.((float) $remise).')';
576 
577  $result = $db->query($sql);
578  if (!$result) {
579  if ($db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
580  setEventMessages($langs->trans("DuplicateRecord"), null, 'errors');
581  } else {
582  dol_print_error($db);
583  }
584  }
585  }
586  }
587  }
588 
589  if ($action == 'delete_price_by_qty') {
590  $rowid = GETPOST('rowid', 'int');
591  if (!empty($rowid)) {
592  $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price_by_qty";
593  $sql .= " WHERE rowid = ".((int) $rowid);
594 
595  $result = $db->query($sql);
596  } else {
597  setEventMessages(('delete_price_by_qty'.$langs->transnoentities('MissingIds')), null, 'errors');
598  }
599  }
600 
601  if ($action == 'delete_all_price_by_qty') {
602  $priceid = GETPOST('priceid', 'int');
603  if (!empty($rowid)) {
604  $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price_by_qty";
605  $sql .= " WHERE fk_product_price = ".((int) $priceid);
606 
607  $result = $db->query($sql);
608  } else {
609  setEventMessages(('delete_price_by_qty'.$langs->transnoentities('MissingIds')), null, 'errors');
610  }
611  }
612 
618  if ($action == 'add_customer_price_confirm' && !$cancel && ($user->rights->produit->creer || $user->rights->service->creer)) {
619  $maxpricesupplier = $object->min_recommended_price();
620 
621  $update_child_soc = GETPOST('updatechildprice', 'int');
622 
623  // add price by customer
624  $prodcustprice->fk_soc = GETPOST('socid', 'int');
625  $prodcustprice->ref_customer = GETPOST('ref_customer', 'alpha');
626  $prodcustprice->fk_product = $object->id;
627  $prodcustprice->price = price2num(GETPOST("price"), 'MU');
628  $prodcustprice->price_min = price2num(GETPOST("price_min"), 'MU');
629  $prodcustprice->price_base_type = GETPOST("price_base_type", 'alpha');
630 
631  $tva_tx_txt = GETPOST("tva_tx", 'alpha');
632 
633  $tva_tx = $tva_tx_txt;
634  $vatratecode = '';
635  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
636  $vat_src_code = $reg[1];
637  $tva_tx = preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx_txt); // Remove code into vatrate.
638  }
639  $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot
640 
641  $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
642  $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0';
643  // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes
644  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
645  // We look into database using code
646  $vatratecode = $reg[1];
647  // Get record from code
648  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
649  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
650  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
651  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
652  $sql .= " AND t.code ='".$db->escape($vatratecode)."'";
653  $resql = $db->query($sql);
654  if ($resql) {
655  $obj = $db->fetch_object($resql);
656  if ($obj) {
657  $npr = $obj->recuperableonly;
658  $localtax1 = $obj->localtax1;
659  $localtax2 = $obj->localtax2;
660  $localtax1_type = $obj->localtax1_type;
661  $localtax2_type = $obj->localtax2_type;
662  }
663 
664  // If spain, we don't use the localtax found into tax record in database with same code, but using the get_localtax rule.
665  if (in_array($mysoc->country_code, array('ES'))) {
666  $localtax1 = get_localtax($tva_tx, 1);
667  $localtax2 = get_localtax($tva_tx, 2);
668  }
669  }
670  } else {
671  // Get record with empty code
672  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
673  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
674  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
675  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
676  $sql .= " AND t.code = ''";
677  $resql = $db->query($sql);
678  if ($resql) {
679  $obj = $db->fetch_object($resql);
680  if ($obj) {
681  $npr = $obj->recuperableonly;
682  $localtax1 = $obj->localtax1;
683  $localtax2 = $obj->localtax2;
684  $localtax1_type = $obj->localtax1_type;
685  $localtax2_type = $obj->localtax2_type;
686  }
687  }
688  }
689 
690  $prodcustprice->default_vat_code = $vatratecode;
691  $prodcustprice->tva_tx = $tva_tx;
692  $prodcustprice->recuperableonly = $npr;
693  $prodcustprice->localtax1_tx = $localtax1;
694  $prodcustprice->localtax2_tx = $localtax2;
695  $prodcustprice->localtax1_type = $localtax1_type;
696  $prodcustprice->localtax2_type = $localtax2_type;
697 
698  if (!($prodcustprice->fk_soc > 0)) {
699  $langs->load("errors");
700  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ThirdParty")), null, 'errors');
701  $error++;
702  $action = 'add_customer_price';
703  }
704  if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE) && $prodcustprice->price_min < $maxpricesupplier) {
705  $langs->load("errors");
706  setEventMessages($langs->trans("MinimumPriceLimit", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')), null, 'errors');
707  $error++;
708  $action = 'add_customer_price';
709  }
710 
711  if (!$error) {
712  $result = $prodcustprice->create($user, 0, $update_child_soc);
713 
714  if ($result < 0) {
715  setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
716  } else {
717  setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
718  }
719 
720  $action = '';
721  }
722  }
723 
724  if ($action == 'delete_customer_price' && ($user->rights->produit->supprimer || $user->rights->service->supprimer)) {
725  // Delete price by customer
726  $prodcustprice->id = GETPOST('lineid', 'int');
727  $result = $prodcustprice->delete($user);
728 
729  if ($result < 0) {
730  setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
731  } else {
732  setEventMessages($langs->trans('RecordDeleted'), null, 'mesgs');
733  }
734  $action = '';
735  }
736 
737  if ($action == 'update_customer_price_confirm' && !$cancel && ($user->rights->produit->creer || $user->rights->service->creer)) {
738  $maxpricesupplier = $object->min_recommended_price();
739 
740  $update_child_soc = GETPOST('updatechildprice', 'int');
741 
742  $prodcustprice->fetch(GETPOST('lineid', 'int'));
743 
744  // update price by customer
745  $prodcustprice->ref_customer = GETPOST('ref_customer', 'alpha');
746  $prodcustprice->price = price2num(GETPOST("price"), 'MU');
747  $prodcustprice->price_min = price2num(GETPOST("price_min"), 'MU');
748  $prodcustprice->price_base_type = GETPOST("price_base_type", 'alpha');
749 
750  $tva_tx_txt = GETPOST("tva_tx");
751 
752  $tva_tx = $tva_tx_txt;
753  $vatratecode = '';
754  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
755  $vat_src_code = $reg[1];
756  $tva_tx = preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx_txt); // Remove code into vatrate.
757  }
758  $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot
759 
760  $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
761  $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0';
762  // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes
763  if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
764  // We look into database using code
765  $vatratecode = $reg[1];
766  // Get record from code
767  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
768  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
769  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
770  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
771  $sql .= " AND t.code ='".$db->escape($vatratecode)."'";
772  $resql = $db->query($sql);
773  if ($resql) {
774  $obj = $db->fetch_object($resql);
775  if ($obj) {
776  $npr = $obj->recuperableonly;
777  $localtax1 = $obj->localtax1;
778  $localtax2 = $obj->localtax2;
779  $localtax1_type = $obj->localtax1_type;
780  $localtax2_type = $obj->localtax2_type;
781  }
782 
783  // If spain, we don't use the localtax found into tax record in database with same code, but using the get_localtax rule.
784  if (in_array($mysoc->country_code, array('ES'))) {
785  $localtax1 = get_localtax($tva_tx, 1);
786  $localtax2 = get_localtax($tva_tx, 2);
787  }
788  }
789  } else {
790  // Get record with empty code
791  $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
792  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
793  $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
794  $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
795  $sql .= " AND t.code = ''";
796  $resql = $db->query($sql);
797  if ($resql) {
798  $obj = $db->fetch_object($resql);
799  if ($obj) {
800  $npr = $obj->recuperableonly;
801  $localtax1 = $obj->localtax1;
802  $localtax2 = $obj->localtax2;
803  $localtax1_type = $obj->localtax1_type;
804  $localtax2_type = $obj->localtax2_type;
805  }
806  }
807  }
808 
809  $prodcustprice->default_vat_code = $vatratecode;
810  $prodcustprice->tva_tx = $tva_tx;
811  $prodcustprice->recuperableonly = $npr;
812  $prodcustprice->localtax1_tx = $localtax1;
813  $prodcustprice->localtax2_tx = $localtax2;
814  $prodcustprice->localtax1_type = $localtax1_type;
815  $prodcustprice->localtax2_type = $localtax2_type;
816 
817  if ($prodcustprice->price_min < $maxpricesupplier && !empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE)) {
818  setEventMessages($langs->trans("MinimumPriceLimit", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')), null, 'errors');
819  $error++;
820  $action = 'update_customer_price';
821  }
822 
823  if (!$error) {
824  $result = $prodcustprice->update($user, 0, $update_child_soc);
825 
826  if ($result < 0) {
827  setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
828  } else {
829  setEventMessages($langs->trans("Save"), null, 'mesgs');
830  }
831 
832  $action = '';
833  }
834  }
835 }
836 
837 
838 /*
839  * View
840  */
841 
842 $form = new Form($db);
843 
844 if (!empty($id) || !empty($ref)) {
845  // fetch updated prices
846  $object->fetch($id, $ref);
847 }
848 
849 $title = $langs->trans('ProductServiceCard');
850 $helpurl = '';
851 $shortlabel = dol_trunc($object->label, 16);
852 if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT)) {
853  $title = $langs->trans('Product')." ".$shortlabel." - ".$langs->trans('SellingPrices');
854  $helpurl = 'EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
855 }
856 if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE)) {
857  $title = $langs->trans('Service')." ".$shortlabel." - ".$langs->trans('SellingPrices');
858  $helpurl = 'EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
859 }
860 
861 llxHeader('', $title, $helpurl, '', 0, 0, '', '', '', 'classforhorizontalscrolloftabs');
862 
863 $head = product_prepare_head($object);
864 $titre = $langs->trans("CardProduct".$object->type);
865 $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
866 
867 print dol_get_fiche_head($head, 'price', $titre, -1, $picto);
868 
869 $linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
870 $object->next_prev_filter = " fk_product_type = ".$object->type;
871 
872 $shownav = 1;
873 if ($user->socid && !in_array('product', explode(',', $conf->global->MAIN_MODULES_FOR_EXTERNAL))) {
874  $shownav = 0;
875 }
876 
877 dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref');
878 
879 
880 print '<div class="fichecenter">';
881 
882 print '<div class="underbanner clearboth"></div>';
883 print '<table class="border tableforfield centpercent">';
884 
885 // Price per customer segment/level
886 if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
887  // Price and min price are variable (depends on level of company).
888  if (!empty($socid)) {
889  $soc = new Societe($db);
890  $soc->id = $socid;
891  $soc->fetch($socid);
892 
893  // Type
894  if (isModEnabled("product") && isModEnabled("service")) {
895  $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
896  print '<tr><td class="">';
897  print (empty($conf->global->PRODUCT_DENY_CHANGE_PRODUCT_TYPE)) ? $form->editfieldkey("Type", 'fk_product_type', $object->type, $object, 0, $typeformat) : $langs->trans('Type');
898  print '</td><td>';
899  print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, 0, $typeformat);
900  print '</td></tr>';
901  }
902 
903  // Selling price
904  print '<tr><td class="titlefieldcreate">';
905  print $langs->trans("SellingPrice");
906  print '</td>';
907  print '<td colspan="2">';
908  if ($object->multiprices_base_type[$soc->price_level] == 'TTC') {
909  print '<span class="amount">'.price($object->multiprices_ttc[$soc->price_level]).'</span>';
910  } else {
911  print '<span class="amount">'.price($object->multiprices[$soc->price_level]).'</span>';
912  }
913  if ($object->multiprices_base_type[$soc->price_level]) {
914  print ' '.$langs->trans($object->multiprices_base_type[$soc->price_level]);
915  } else {
916  print ' '.$langs->trans($object->price_base_type);
917  }
918  print '</td></tr>';
919 
920  // Price min
921  print '<tr><td>'.$langs->trans("MinPrice").'</td><td colspan="2">';
922  if ($object->multiprices_base_type[$soc->price_level] == 'TTC') {
923  print price($object->multiprices_min_ttc[$soc->price_level]).' '.$langs->trans($object->multiprices_base_type[$soc->price_level]);
924  } else {
925  print price($object->multiprices_min[$soc->price_level]).' '.$langs->trans(empty($object->multiprices_base_type[$soc->price_level]) ? 'HT' : $object->multiprices_base_type[$soc->price_level]);
926  }
927  print '</td></tr>';
928 
929  if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility
930  // TVA
931  print '<tr><td>'.$langs->trans("DefaultTaxRate").'</td><td colspan="2">';
932 
933  $positiverates = '';
934  if (price2num($object->multiprices_tva_tx[$soc->price_level])) {
935  $positiverates .= ($positiverates ? '/' : '').price2num($object->multiprices_tva_tx[$soc->price_level]);
936  }
937  if (price2num($object->multiprices_localtax1_type[$soc->price_level])) {
938  $positiverates .= ($positiverates ? '/' : '').price2num($object->multiprices_localtax1_tx[$soc->price_level]);
939  }
940  if (price2num($object->multiprices_localtax2_type[$soc->price_level])) {
941  $positiverates .= ($positiverates ? '/' : '').price2num($object->multiprices_localtax2_tx[$soc->price_level]);
942  }
943  if (empty($positiverates)) {
944  $positiverates = '0';
945  }
946  echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), '%', $object->tva_npr);
947  //print vatrate($object->multiprices_tva_tx[$soc->price_level], true);
948  print '</td></tr>';
949  } else {
950  // TVA
951  print '<tr><td>'.$langs->trans("DefaultTaxRate").'</td><td>';
952 
953  $positiverates = '';
954  if (price2num($object->tva_tx)) {
955  $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx);
956  }
957  if (price2num($object->localtax1_type)) {
958  $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx);
959  }
960  if (price2num($object->localtax2_type)) {
961  $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx);
962  }
963  if (empty($positiverates)) {
964  $positiverates = '0';
965  }
966  echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), '%', $object->tva_npr);
967  /*
968  if ($object->default_vat_code)
969  {
970  print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')';
971  }
972  else print vatrate($object->tva_tx . ($object->tva_npr ? '*' : ''), true);*/
973  print '</td></tr>';
974  }
975  } else {
976  if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility
977  // Type
978  if (isModEnabled("product") && isModEnabled("service")) {
979  $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
980  print '<tr><td class="">';
981  print (empty($conf->global->PRODUCT_DENY_CHANGE_PRODUCT_TYPE)) ? $form->editfieldkey("Type", 'fk_product_type', $object->type, $object, 0, $typeformat) : $langs->trans('Type');
982  print '</td><td>';
983  print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, 0, $typeformat);
984  print '</td></tr>';
985  }
986 
987  // We show only vat for level 1
988  print '<tr><td class="titlefieldcreate">'.$langs->trans("DefaultTaxRate").'</td>';
989  print '<td colspan="2">'.vatrate($object->multiprices_tva_tx[1], true).'</td>';
990  print '</tr>';
991  } else {
992  // Type
993  if (isModEnabled("product") && isModEnabled("service")) {
994  $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
995  print '<tr><td class="">';
996  print (empty($conf->global->PRODUCT_DENY_CHANGE_PRODUCT_TYPE)) ? $form->editfieldkey("Type", 'fk_product_type', $object->type, $object, 0, $typeformat) : $langs->trans('Type');
997  print '</td><td>';
998  print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, 0, $typeformat);
999  print '</td></tr>';
1000  }
1001 
1002  // TVA
1003  print '<!-- Default VAT Rate -->';
1004  print '<tr><td class="titlefieldcreate">'.$langs->trans("DefaultTaxRate").'</td><td>';
1005 
1006  // TODO We show localtax from $object, but this properties may not be correct. Only value $object->default_vat_code is guaranted.
1007  $positiverates = '';
1008  if (price2num($object->tva_tx)) {
1009  $positiverates .= ($positiverates ? '<span class="opacitymedium">/</span>' : '').price2num($object->tva_tx);
1010  }
1011  if (price2num($object->localtax1_type)) {
1012  $positiverates .= ($positiverates ? '<span class="opacitymedium">/</span>' : '').price2num($object->localtax1_tx);
1013  }
1014  if (price2num($object->localtax2_type)) {
1015  $positiverates .= ($positiverates ? '<span class="opacitymedium">/</span>' : '').price2num($object->localtax2_tx);
1016  }
1017  if (empty($positiverates)) {
1018  $positiverates = '0';
1019  }
1020 
1021  print vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), true, $object->tva_npr, 1);
1022  /*
1023  if ($object->default_vat_code)
1024  {
1025  print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')';
1026  }
1027  else print vatrate($object->tva_tx . ($object->tva_npr ? '*' : ''), true);*/
1028  print '</td></tr>';
1029  }
1030  print '</table>';
1031 
1032  print '<br>';
1033 
1034  print '<table class="noborder tableforfield centpercent">';
1035  print '<tr class="liste_titre"><td>';
1036  print $langs->trans("PriceLevel");
1037  if ($user->admin) {
1038  print ' <a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editlabelsellingprice&token='.newToken().'&pricelevel='.$i.'&id='.$object->id.'">'.img_edit($langs->trans('EditSellingPriceLabel'), 0).'</a>';
1039  }
1040  print '</td>';
1041  print '<td style="text-align: right">'.$langs->trans("SellingPrice").'</td>';
1042  print '<td style="text-align: right">'.$langs->trans("MinPrice").'</td>';
1043  print '</tr>';
1044 
1045  for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
1046  print '<tr class="oddeven">';
1047 
1048  // Label of price
1049  print '<td>';
1050  $keyforlabel = 'PRODUIT_MULTIPRICES_LABEL'.$i;
1051  if (preg_match('/editlabelsellingprice/', $action)) {
1052  print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
1053  print '<input type="hidden" name="token" value="'.newToken().'">';
1054  print '<input type="hidden" name="action" value="setlabelsellingprice">';
1055  print '<input type="hidden" name="pricelevel" value="'.$i.'">';
1056  print $langs->trans("SellingPrice").' '.$i.' - ';
1057  print '<input class="maxwidthonsmartphone" type="text" name="labelsellingprice" value="'.$conf->global->$keyforlabel.'">';
1058  print '&nbsp;<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
1059  print '</form>';
1060  } else {
1061  print $langs->trans("SellingPrice").' '.$i;
1062  if (!empty($conf->global->$keyforlabel)) {
1063  print ' - '.$langs->trans($conf->global->$keyforlabel);
1064  }
1065  }
1066  print '</td>';
1067 
1068  if ($object->multiprices_base_type [$i] == 'TTC') {
1069  print '<td class="right"><span class="amount">'.price($object->multiprices_ttc[$i]);
1070  } else {
1071  print '<td class="right"><span class="amount">'.price($object->multiprices[$i]);
1072  }
1073 
1074  if ($object->multiprices_base_type[$i]) {
1075  print ' '.$langs->trans($object->multiprices_base_type [$i]).'</span></td>';
1076  } else {
1077  print ' '.$langs->trans($object->price_base_type).'</span></td>';
1078  }
1079 
1080  // Prix min
1081  print '<td style="text-align: right">';
1082  if (empty($object->multiprices_base_type[$i])) {
1083  $object->multiprices_base_type[$i] = "HT";
1084  }
1085  if ($object->multiprices_base_type[$i] == 'TTC') {
1086  print price($object->multiprices_min_ttc[$i]).' '.$langs->trans($object->multiprices_base_type[$i]);
1087  } else {
1088  print price($object->multiprices_min[$i]).' '.$langs->trans($object->multiprices_base_type[$i]);
1089  }
1090  print '</td></tr>';
1091 
1092  // Price by quantity
1093  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { // TODO Fix the form included into a tr instead of a td
1094  print '<tr><td>'.$langs->trans("PriceByQuantity").' '.$i;
1095  if (!empty($conf->global->$keyforlabel)) {
1096  print ' - '.$langs->trans($conf->global->$keyforlabel);
1097  }
1098  print '</td><td colspan="2">';
1099 
1100  if ($object->prices_by_qty[$i] == 1) {
1101  print '<table width="50%" class="border" summary="List of quantities">';
1102 
1103  print '<tr class="liste_titre">';
1104  print '<td>'.$langs->trans("PriceByQuantityRange").' '.$i.'</td>';
1105  print '<td class="right">'.$langs->trans("HT").'</td>';
1106  print '<td class="right">'.$langs->trans("UnitPrice").'</td>';
1107  print '<td class="right">'.$langs->trans("Discount").'</td>';
1108  print '<td>&nbsp;</td>';
1109  print '</tr>';
1110  foreach ($object->prices_by_qty_list[$i] as $ii => $prices) {
1111  if ($action == 'edit_price_by_qty' && $rowid == $prices['rowid'] && ($user->rights->produit->creer || $user->rights->service->creer)) {
1112  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1113  print '<input type="hidden" name="token" value="'.newToken().'">';
1114  print '<input type="hidden" name="action" value="update_price_by_qty">';
1115  print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[$i].'">';
1116  print '<input type="hidden" value="'.$prices['rowid'].'" name="rowid">';
1117  print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1118  print '<td><input size="5" type="text" value="'.$prices['quantity'].'" name="quantity"></td>';
1119  print '<td class="right" colspan="2"><input size="10" type="text" value="'.price2num($prices['price'], 'MU').'" name="price">&nbsp;'.$object->price_base_type.'</td>';
1120  print '<td class="right nowraponall"><input size="5" type="text" value="'.$prices['remise_percent'].'" name="remise_percent"> %</td>';
1121  print '<td class="center"><input type="submit" value="'.$langs->trans("Modify").'" class="button"></td>';
1122  print '</tr>';
1123  print '</form>';
1124  } else {
1125  print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1126  print '<td>'.$prices['quantity'].'</td>';
1127  print '<td class="right">'.price($prices['price']).'</td>';
1128  print '<td class="right">'.price($prices['unitprice']).'</td>';
1129  print '<td class="right">'.price($prices['remise_percent']).' %</td>';
1130  print '<td class="center">';
1131  if (($user->rights->produit->creer || $user->rights->service->creer)) {
1132  print '<a class="editfielda marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit_price_by_qty&token='.newToken().'&rowid='.$prices["rowid"].'">';
1133  print img_edit().'</a>';
1134  print '<a class="marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete_price_by_qty&token='.newToken().'&rowid='.$prices["rowid"].'">';
1135  print img_delete().'</a>';
1136  } else {
1137  print '&nbsp;';
1138  }
1139  print '</td>';
1140  print '</tr>';
1141  }
1142  }
1143  if ($action != 'edit_price_by_qty' && ($user->rights->produit->creer || $user->rights->service->creer)) {
1144  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1145  print '<input type="hidden" name="token" value="'.newToken().'">';
1146  print '<input type="hidden" name="action" value="update_price_by_qty">';
1147  print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[$i].'">'; // id in product_price
1148  print '<input type="hidden" value="0" name="rowid">'; // id in product_price
1149  print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1150  print '<td><input size="5" type="text" value="1" name="quantity"></td>';
1151  print '<td class="right" class="nowrap"><input size="10" type="text" value="0" name="price">&nbsp;'.$object->price_base_type.'</td>';
1152  print '<td class="right">&nbsp;</td>';
1153  print '<td class="right" class="nowraponall"><input size="5" type="text" value="0" name="remise_percent"> %</td>';
1154  print '<td class="center"><input type="submit" value="'.$langs->trans("Add").'" class="button"></td>';
1155  print '</tr>';
1156  print '</form>';
1157  }
1158 
1159  print '</table>';
1160  print '<a class="editfielda marginleftonly marginrightonly" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=disable_price_by_qty&level='.$i.'&token='.newToken().'">('.$langs->trans("DisablePriceByQty").')</a>';
1161  } else {
1162  print $langs->trans("No");
1163  print '&nbsp; <a class="marginleftonly marginrightonly" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=activate_price_by_qty&level='.$i.'&token='.newToken().'">('.$langs->trans("Activate").')</a>';
1164  }
1165  print '</td></tr>';
1166  }
1167  }
1168  }
1169 } else {
1170  // TVA
1171  print '<tr><td class="titlefield">'.$langs->trans("DefaultTaxRate").'</td><td>';
1172 
1173  $positiverates = '';
1174  if (price2num($object->tva_tx)) {
1175  $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx);
1176  }
1177  if (price2num($object->localtax1_type)) {
1178  $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx);
1179  }
1180  if (price2num($object->localtax2_type)) {
1181  $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx);
1182  }
1183  if (empty($positiverates)) {
1184  $positiverates = '0';
1185  }
1186  echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), '%', $object->tva_npr, 0, 1);
1187  /*
1188  if ($object->default_vat_code)
1189  {
1190  print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')';
1191  }
1192  else print vatrate($object->tva_tx, true, $object->tva_npr, true);*/
1193  print '</td></tr>';
1194 
1195  // Price
1196  print '<tr class="field_selling_price"><td>'.$langs->trans("SellingPrice").'</td><td>';
1197  if ($object->price_base_type == 'TTC') {
1198  print price($object->price_ttc).' '.$langs->trans($object->price_base_type);
1199  } else {
1200  print price($object->price).' '.$langs->trans($object->price_base_type);
1201  if (!empty($conf->global->PRODUCT_DISPLAY_VAT_INCL_PRICES) && !empty($object->price_ttc)) {
1202  print '<i class="opacitymedium"> - ' . price($object->price_ttc).' '.$langs->trans('TTC') . '</i>';
1203  }
1204  }
1205 
1206  print '</td></tr>';
1207 
1208  // Price minimum
1209  print '<tr class="field_min_price"><td>'.$langs->trans("MinPrice").'</td><td>';
1210  if ($object->price_base_type == 'TTC') {
1211  print price($object->price_min_ttc).' '.$langs->trans($object->price_base_type);
1212  } else {
1213  print price($object->price_min).' '.$langs->trans($object->price_base_type);
1214  if (!empty($conf->global->PRODUCT_DISPLAY_VAT_INCL_PRICES) && !empty($object->price_min_ttc)) {
1215  print '<i class="opacitymedium"> - ' . price($object->price_min_ttc).' '.$langs->trans('TTC') . '</i>';
1216  }
1217  }
1218 
1219  print '</td></tr>';
1220 
1221  // Price by quantity
1222  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { // TODO Fix the form inside tr instead of td
1223  print '<tr><td>'.$langs->trans("PriceByQuantity");
1224  if ($object->prices_by_qty[0] == 0) {
1225  print '&nbsp; <a href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=activate_price_by_qty&level=1&token='.newToken().'">('.$langs->trans("Activate").')';
1226  } else {
1227  print '&nbsp; <a href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=disable_price_by_qty&level=1&token='.newToken().'">('.$langs->trans("DisablePriceByQty").')';
1228  }
1229  print '</td><td>';
1230 
1231  if ($object->prices_by_qty[0] == 1) {
1232  print '<table width="50%" class="border" summary="List of quantities">';
1233  print '<tr class="liste_titre">';
1234  //print '<td>' . $langs->trans("PriceByQuantityRange") . '</td>';
1235  print '<td>'.$langs->trans("Quantity").'</td>';
1236  print '<td class="right">'.$langs->trans("Price").'</td>';
1237  print '<td class="right"></td>';
1238  print '<td class="right">'.$langs->trans("UnitPrice").'</td>';
1239  print '<td class="right">'.$langs->trans("Discount").'</td>';
1240  print '<td>&nbsp;</td>';
1241  print '</tr>';
1242  if ($action != 'edit_price_by_qty') {
1243  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">'; // FIXME a form into a table is not allowed
1244  print '<input type="hidden" name="token" value="'.newToken().'">';
1245  print '<input type="hidden" name="action" value="update_price_by_qty">';
1246  print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[0].'">'; // id in product_price
1247  print '<input type="hidden" value="0" name="rowid">'; // id in product_price_by_qty
1248 
1249  print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1250  print '<td><input size="5" type="text" value="1" name="quantity"></td>';
1251  print '<td class="right"><input class="width50 right" type="text" value="0" name="price"></td>';
1252  print '<td>';
1253  //print $object->price_base_type;
1254  print '</td>';
1255  print '<td class="right">&nbsp;</td>';
1256  print '<td class="right nowraponall"><input type="text" class="width50 right" value="0" name="remise_percent"> %</td>';
1257  print '<td class="center"><input type="submit" value="'.$langs->trans("Add").'" class="button"></td>';
1258  print '</tr>';
1259 
1260  print '</form>';
1261  }
1262  foreach ($object->prices_by_qty_list[0] as $ii => $prices) {
1263  if ($action == 'edit_price_by_qty' && $rowid == $prices['rowid'] && ($user->rights->produit->creer || $user->rights->service->creer)) {
1264  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1265  print '<input type="hidden" name="token" value="'.newToken().'">';
1266  print '<input type="hidden" name="action" value="update_price_by_qty">';
1267  print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[0].'">'; // id in product_price
1268  print '<input type="hidden" value="'.$prices['rowid'].'" name="rowid">'; // id in product_price_by_qty
1269  print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1270  print '<td><input size="5" type="text" value="'.$prices['quantity'].'" name="quantity"></td>';
1271  print '<td class="right"><input class="width50 right" type="text" value="'.price2num($prices['price'], 'MU').'" name="price"></td>';
1272  print '<td class="right">';
1273  //print $object->price_base_type;
1274  print $prices['price_base_type'];
1275  print '</td>';
1276  print '<td class="right">&nbsp;</td>';
1277  print '<td class="right nowraponall"><input class="width50 right" type="text" value="'.$prices['remise_percent'].'" name="remise_percent"> %</td>';
1278  print '<td class="center"><input type="submit" value="'.$langs->trans("Modify").'" class="button"></td>';
1279  print '</tr>';
1280  print '</form>';
1281  } else {
1282  print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1283  print '<td>'.$prices['quantity'].'</td>';
1284  print '<td class="right">'.price($prices['price']).'</td>';
1285  print '<td class="right">';
1286  //print $object->price_base_type;
1287  print $prices['price_base_type'];
1288  print '</td>';
1289  print '<td class="right">'.price($prices['unitprice']).'</td>';
1290  print '<td class="right">'.price($prices['remise_percent']).' %</td>';
1291  print '<td class="center">';
1292  if (($user->rights->produit->creer || $user->rights->service->creer)) {
1293  print '<a class="editfielda marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit_price_by_qty&token='.newToken().'&rowid='.$prices["rowid"].'">';
1294  print img_edit().'</a>';
1295  print '<a class="marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete_price_by_qty&token='.newToken().'&rowid='.$prices["rowid"].'">';
1296  print img_delete().'</a>';
1297  } else {
1298  print '&nbsp;';
1299  }
1300  print '</td>';
1301  print '</tr>';
1302  }
1303  }
1304  print '</table>';
1305  } else {
1306  print $langs->trans("No");
1307  }
1308  print '</td></tr>';
1309  }
1310 }
1311 
1312 print "</table>\n";
1313 
1314 print '</div>';
1315 print '<div style="clear:both"></div>';
1316 
1317 
1318 print dol_get_fiche_end();
1319 
1320 
1321 
1322 /*
1323  * Action bar
1324  */
1325 
1326 
1327 if (!$action || $action == 'delete' || $action == 'showlog_customer_price' || $action == 'showlog_default_price' || $action == 'add_customer_price'
1328  || $action == 'activate_price_by_qty' || $action == 'disable_price_by_qty') {
1329  print "\n".'<div class="tabsAction">'."\n";
1330 
1331 
1332  $parameters = array();
1333  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1334  if (empty($reshook)) {
1335  if ($object->isVariant()) {
1336  if ($user->rights->produit->creer || $user->rights->service->creer) {
1337  print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" href="#" title="' . dol_escape_htmltag($langs->trans("NoEditVariants")) . '">' . $langs->trans("UpdateDefaultPrice") . '</a></div>';
1338  }
1339  } else {
1340  if (empty($conf->global->PRODUIT_MULTIPRICES) && empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1341  if ($user->rights->produit->creer || $user->rights->service->creer) {
1342  print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("UpdateDefaultPrice") . '</a></div>';
1343  } else {
1344  print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("UpdateDefaultPrice") . '</span></div>';
1345  }
1346  }
1347 
1348  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
1349  if ($user->rights->produit->creer || $user->rights->service->creer) {
1350  print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?action=add_customer_price&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("AddCustomerPrice") . '</a></div>';
1351  } else {
1352  print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("AddCustomerPrice") . '</span></div>';
1353  }
1354  }
1355 
1356  if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1357  if ($user->rights->produit->creer || $user->rights->service->creer) {
1358  print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_vat&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("UpdateVAT") . '</a></div>';
1359  } else {
1360  print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("UpdateVAT") . '</span></div>';
1361  }
1362 
1363  if ($user->rights->produit->creer || $user->rights->service->creer) {
1364  print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("UpdateLevelPrices") . '</a></div>';
1365  } else {
1366  print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("UpdateLevelPrices") . '</span></div>';
1367  }
1368  }
1369  }
1370  }
1371 
1372  print "\n</div>\n";
1373 }
1374 
1375 
1376 
1377 /*
1378  * Edit price area
1379  */
1380 
1381 if ($action == 'edit_vat' && ($user->rights->produit->creer || $user->rights->service->creer)) {
1382  print load_fiche_titre($langs->trans("UpdateVAT"), '');
1383 
1384  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1385  print '<input type="hidden" name="token" value="'.newToken().'">';
1386  print '<input type="hidden" name="action" value="update_vat">';
1387  print '<input type="hidden" name="id" value="'.$object->id.'">';
1388 
1389  print dol_get_fiche_head('');
1390 
1391  print '<table class="border centpercent">';
1392 
1393  // VAT
1394  print '<tr><td>'.$langs->trans("DefaultTaxRate").'</td><td>';
1395  print $form->load_tva("tva_tx", $object->default_vat_code ? $object->tva_tx.' ('.$object->default_vat_code.')' : $object->tva_tx, $mysoc, '', $object->id, $object->tva_npr, $object->type, false, 1);
1396  print '</td></tr>';
1397 
1398  print '</table>';
1399 
1400  print dol_get_fiche_end();
1401 
1402  print $form->buttonsSaveCancel();
1403 
1404  print '<br></form><br>';
1405 }
1406 
1407 if ($action == 'edit_price' && $object->getRights()->creer) {
1408  print '<br>';
1409  print load_fiche_titre($langs->trans("NewPrice"), '');
1410 
1411  if (empty($conf->global->PRODUIT_MULTIPRICES) && empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1412  print '<!-- Edit price -->'."\n";
1413  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1414  print '<input type="hidden" name="token" value="'.newToken().'">';
1415  print '<input type="hidden" name="action" value="update_price">';
1416  print '<input type="hidden" name="id" value="'.$object->id.'">';
1417 
1418  print dol_get_fiche_head('');
1419 
1420  print '<div class="div-table-responsive-no-min">';
1421  print '<table class="border centpercent">';
1422 
1423  // VAT
1424  print '<tr><td class="titlefield">'.$langs->trans("DefaultTaxRate").'</td><td>';
1425  print $form->load_tva("tva_tx", $object->default_vat_code ? $object->tva_tx.' ('.$object->default_vat_code.')' : $object->tva_tx, $mysoc, '', $object->id, $object->tva_npr, $object->type, false, 1);
1426  print '</td></tr>';
1427 
1428  // Price base
1429  print '<tr><td>';
1430  print $langs->trans('PriceBase');
1431  print '</td>';
1432  print '<td>';
1433  print $form->selectPriceBaseType($object->price_base_type, "price_base_type");
1434  print '</td>';
1435  print '</tr>';
1436 
1437  // Only show price mode and expression selector if module is enabled
1438  if (!empty($conf->dynamicprices->enabled)) {
1439  // Price mode selector
1440  print '<!-- Show price mode of dynamicprices editor -->'."\n";
1441  print '<tr><td>'.$langs->trans("PriceMode").'</td><td>';
1442  print img_picto('', 'dynamicprice', 'class="pictofixedwidth"');
1443  $price_expression = new PriceExpression($db);
1444  $price_expression_list = array(0 => $langs->trans("Numeric").' <span class="opacitymedium">('.$langs->trans("NoDynamicPrice").')</span>'); //Put the numeric mode as first option
1445  foreach ($price_expression->list_price_expression() as $entry) {
1446  $price_expression_list[$entry->id] = $entry->title;
1447  }
1448  $price_expression_preselection = GETPOST('eid') ? GETPOST('eid') : ($object->fk_price_expression ? $object->fk_price_expression : '0');
1449  print $form->selectarray('eid', $price_expression_list, $price_expression_preselection);
1450  print '&nbsp; <a id="expression_editor" class="classlink">'.$langs->trans("PriceExpressionEditor").'</a>';
1451  print '</td></tr>';
1452 
1453  // This code hides the numeric price input if is not selected, loads the editor page if editor button is pressed
1454  ?>
1455 
1456  <script type="text/javascript">
1457  jQuery(document).ready(function() {
1458  jQuery("#expression_editor").click(function() {
1459  window.location = "<?php echo DOL_URL_ROOT ?>/product/dynamic_price/editor.php?id=<?php echo $id ?>&tab=price&eid=" + $("#eid").val();
1460  });
1461  jQuery("#eid").change(on_change);
1462  on_change();
1463  });
1464  function on_change() {
1465  if ($("#eid").val() == 0) {
1466  jQuery("#price_numeric").show();
1467  } else {
1468  jQuery("#price_numeric").hide();
1469  }
1470  }
1471  </script>
1472  <?php
1473  }
1474 
1475  // Price
1476  $product = new Product($db);
1477  $product->fetch($id, $ref, '', 1); //Ignore the math expression when getting the price
1478  print '<tr id="price_numeric"><td>';
1479  $text = $langs->trans('SellingPrice');
1480  print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", $conf->global->MAIN_MAX_DECIMALS_UNIT), 1, 1);
1481  print '</td><td>';
1482  if ($object->price_base_type == 'TTC') {
1483  print '<input name="price" size="10" value="'.price($product->price_ttc).'">';
1484  } else {
1485  print '<input name="price" size="10" value="'.price($product->price).'">';
1486  }
1487  print '</td></tr>';
1488 
1489  // Price minimum
1490  print '<tr><td>';
1491  $text = $langs->trans('MinPrice');
1492  print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", $conf->global->MAIN_MAX_DECIMALS_UNIT), 1, 1);
1493  print '</td><td>';
1494  if ($object->price_base_type == 'TTC') {
1495  print '<input name="price_min" size="10" value="'.price($object->price_min_ttc).'">';
1496  } else {
1497  print '<input name="price_min" size="10" value="'.price($object->price_min).'">';
1498  }
1499  if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE)) {
1500  print ' &nbsp; '.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().'</td>';
1501  }
1502  print '</td>';
1503  print '</tr>';
1504 
1505  $parameters = array();
1506  $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1507 
1508  print '</table>';
1509  print '</div>';
1510 
1511  print dol_get_fiche_end();
1512 
1513  print $form->buttonsSaveCancel();
1514 
1515  print '</form>';
1516  } else {
1517  print '<!-- Edit price per level -->'."\n";
1518  ?>
1519  <script>
1520 
1521  var showHidePriceRules = function () {
1522  var otherPrices = $('div.fiche form table tbody tr:not(:first)');
1523  var minPrice1 = $('div.fiche form input[name="price_min[1]"]');
1524 
1525  if (jQuery('input#usePriceRules').prop('checked')) {
1526  otherPrices.hide();
1527  minPrice1.hide();
1528  } else {
1529  otherPrices.show();
1530  minPrice1.show();
1531  }
1532  };
1533 
1534  jQuery(document).ready(function () {
1535  showHidePriceRules();
1536 
1537  jQuery('input#usePriceRules').click(showHidePriceRules);
1538  });
1539  </script>
1540  <?php
1541 
1542  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1543  print '<input type="hidden" name="token" value="'.newToken().'">';
1544  print '<input type="hidden" name="action" value="update_price">';
1545  print '<input type="hidden" name="id" value="'.$object->id.'">';
1546 
1547  //print dol_get_fiche_head('', '', '', -1);
1548 
1549  if ((!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && !empty($conf->global->PRODUIT_MULTIPRICES_ALLOW_AUTOCALC_PRICELEVEL)) {
1550  print $langs->trans('UseMultipriceRules').' <input type="checkbox" id="usePriceRules" name="usePriceRules" '.($object->price_autogen ? 'checked' : '').'><br><br>';
1551  }
1552 
1553  print '<div class="div-table-responsive-no-min">';
1554  print '<table class="noborder">';
1555  print '<thead><tr class="liste_titre">';
1556 
1557  print '<td>'.$langs->trans("PriceLevel").'</td>';
1558 
1559  if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) {
1560  print '<td style="text-align: center">'.$langs->trans("DefaultTaxRate").'</td>';
1561  } else {
1562  print '<td></td>';
1563  }
1564 
1565  print '<td class="center">'.$langs->trans("SellingPrice").'</td>';
1566 
1567  print '<td class="center">'.$langs->trans("MinPrice").'</td>';
1568 
1569  if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE)) {
1570  print '<td></td>';
1571  }
1572  print '</tr></thead>';
1573 
1574  print '<tbody>';
1575 
1576  for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
1577  print '<tr class="oddeven">';
1578  print '<td>';
1579  $text = $langs->trans('SellingPrice').' '.$i;
1580  print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", $conf->global->MAIN_MAX_DECIMALS_UNIT), 1, 1);
1581  print '</td>';
1582 
1583  // VAT
1584  if (empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) {
1585  print '<td>';
1586  print '<input type="hidden" name="tva_tx['.$i.']" value="'.($object->default_vat_code ? $object->tva_tx.' ('.$object->default_vat_code.')' : $object->tva_tx).'">';
1587  print '<input type="hidden" name="tva_npr['.$i.']" value="'.$object->tva_npr.'">';
1588  print '<input type="hidden" name="localtax1_tx['.$i.']" value="'.$object->localtax1_tx.'">';
1589  print '<input type="hidden" name="localtax1_type['.$i.']" value="'.$object->localtax1_type.'">';
1590  print '<input type="hidden" name="localtax2_tx['.$i.']" value="'.$object->localtax2_tx.'">';
1591  print '<input type="hidden" name="localtax2_type['.$i.']" value="'.$object->localtax2_type.'">';
1592  print '</td>';
1593  } else {
1594  // This option is kept for backward compatibility but has no sense
1595  print '<td style="text-align: center">';
1596  print $form->load_tva("tva_tx[".$i.']', $object->multiprices_tva_tx[$i], $mysoc, '', $object->id, false, $object->type, false, 1);
1597  print '</td>';
1598  }
1599 
1600  // Selling price
1601  print '<td style="text-align: center">';
1602  if ($object->multiprices_base_type [$i] == 'TTC') {
1603  print '<input name="price['.$i.']" size="10" value="'.price($object->multiprices_ttc [$i]).'">';
1604  } else {
1605  print '<input name="price['.$i.']" size="10" value="'.price($object->multiprices [$i]).'">';
1606  }
1607  print '&nbsp;'.$form->selectPriceBaseType($object->multiprices_base_type [$i], "multiprices_base_type[".$i."]");
1608  print '</td>';
1609 
1610  // Min price
1611  print '<td style="text-align: center">';
1612  if ($object->multiprices_base_type [$i] == 'TTC') {
1613  print '<input name="price_min['.$i.']" size="10" value="'.price($object->multiprices_min_ttc [$i]).'">';
1614  } else {
1615  print '<input name="price_min['.$i.']" size="10" value="'.price($object->multiprices_min [$i]).'">';
1616  }
1617  if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE)) {
1618  print '<td class="left">'.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().'</td>';
1619  }
1620  print '</td>';
1621 
1622  print '</tr>';
1623  }
1624 
1625  print '</tbody>';
1626 
1627  print '</table>';
1628  print '</div>';
1629 
1630  //print dol_get_fiche_end();
1631 
1632  print $form->buttonsSaveCancel();
1633 
1634  print '</form>';
1635  }
1636 }
1637 
1638 
1639 // List of price changes - log historic (ordered by descending date)
1640 
1641 if ((empty($conf->global->PRODUIT_CUSTOMER_PRICES) || $action == 'showlog_default_price') && !in_array($action, array('edit_price', 'edit_vat'))) {
1642  $sql = "SELECT p.rowid, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.default_vat_code, p.recuperableonly, p.localtax1_tx, p.localtax1_type, p.localtax2_tx, p.localtax2_type,";
1643  $sql .= " p.price_level, p.price_min, p.price_min_ttc,p.price_by_qty,";
1644  $sql .= " p.date_price as dp, p.fk_price_expression, u.rowid as user_id, u.login";
1645  $sql .= " FROM ".MAIN_DB_PREFIX."product_price as p,";
1646  $sql .= " ".MAIN_DB_PREFIX."user as u";
1647  $sql .= " WHERE fk_product = ".((int) $object->id);
1648  $sql .= " AND p.entity IN (".getEntity('productprice').")";
1649  $sql .= " AND p.fk_user_author = u.rowid";
1650  if (!empty($socid) && !empty($conf->global->PRODUIT_MULTIPRICES)) {
1651  $sql .= " AND p.price_level = ".((int) $soc->price_level);
1652  }
1653  $sql .= " ORDER BY p.date_price DESC, p.rowid DESC, p.price_level ASC";
1654  // $sql .= $db->plimit();
1655  //print $sql;
1656 
1657  $result = $db->query($sql);
1658  if ($result) {
1659  print '<div class="divlogofpreviouscustomerprice">';
1660 
1661  $num = $db->num_rows($result);
1662 
1663  if (!$num) {
1664  $db->free($result);
1665 
1666  // Il doit au moins y avoir la ligne de prix initial.
1667  // On l'ajoute donc pour remettre a niveau (pb vieilles versions)
1668  // We emulate the change of the price from interface with the same value than the one into table llx_product
1669  if (!empty($conf->global->PRODUIT_MULTIPRICES)) {
1670  $ret = $object->updatePrice(($object->multiprices_base_type[1] == 'TTC' ? $object->multiprices_ttc[1] : $object->multiprices[1]), $object->multiprices_base_type[1], $user, (empty($object->multiprices_tva_tx[1]) ? 0 : $object->multiprices_tva_tx[1]), ($object->multiprices_base_type[1] == 'TTC' ? $object->multiprices_min_ttc[1] : $object->multiprices_min[1]), 1);
1671  } else {
1672  $ret = $object->updatePrice(($object->price_base_type == 'TTC' ? $object->price_ttc : $object->price), $object->price_base_type, $user, $object->tva_tx, ($object->price_base_type == 'TTC' ? $object->price_min_ttc : $object->price_min));
1673  }
1674 
1675  if ($ret < 0) {
1676  dol_print_error($db, $object->error, $object->errors);
1677  } else {
1678  $result = $db->query($sql);
1679  $num = $db->num_rows($result);
1680  }
1681  }
1682 
1683  if ($num > 0) {
1684  // Default prices or
1685  // Log of previous customer prices
1686  $backbutton = '<a class="justalink" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">'.$langs->trans("Back").'</a>';
1687 
1688  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
1689  print_barre_liste($langs->trans("DefaultPriceLog"), 0, $_SERVER["PHP_SELF"], '', '', '', $backbutton, 0, $num, 'title_accountancy.png');
1690  } else {
1691  print_barre_liste($langs->trans("PriceByCustomerLog"), 0, $_SERVER["PHP_SELF"], '', '', '', '', 0, $num, 'title_accountancy.png');
1692  }
1693 
1694  print '<!-- List of log prices -->'."\n";
1695  print '<div class="div-table-responsive">'."\n";
1696  print '<table class="liste centpercent">'."\n";
1697 
1698  print '<tr class="liste_titre">';
1699  print '<td>'.$langs->trans("AppliedPricesFrom").'</td>';
1700 
1701  if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1702  print '<td class="center">'.$langs->trans("PriceLevel").'</td>';
1703  }
1704  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1705  print '<td class="center">'.$langs->trans("Type").'</td>';
1706  }
1707 
1708  print '<td class="center">'.$langs->trans("PriceBase").'</td>';
1709  if (empty($conf->global->PRODUIT_MULTIPRICES) && empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1710  print '<td class="right">'.$langs->trans("DefaultTaxRate").'</td>';
1711  }
1712  print '<td class="right">'.$langs->trans("HT").'</td>';
1713  print '<td class="right">'.$langs->trans("TTC").'</td>';
1714  if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
1715  print '<td class="right">'.$langs->trans("INCT").'</td>';
1716  }
1717  if (!empty($conf->dynamicprices->enabled)) {
1718  print '<td class="right">'.$langs->trans("PriceExpressionSelected").'</td>';
1719  }
1720  print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("HT").'</td>';
1721  print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("TTC").'</td>';
1722  print '<td class="right">'.$langs->trans("ChangedBy").'</td>';
1723  if ($user->rights->produit->supprimer) {
1724  print '<td class="right">&nbsp;</td>';
1725  }
1726  print '</tr>';
1727 
1728  $notfirstlineforlevel = array();
1729 
1730  $i = 0;
1731  while ($i < $num) {
1732  $objp = $db->fetch_object($result);
1733 
1734  print '<tr class="oddeven">';
1735  // Date
1736  print "<td>".dol_print_date($db->jdate($objp->dp), "dayhour", 'tzuserrel')."</td>";
1737 
1738  // Price level
1739  if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1740  print '<td class="center">'.$objp->price_level."</td>";
1741  }
1742  // Price by quantity
1743  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1744  $type = ($objp->price_by_qty == 1) ? 'PriceByQuantity' : 'Standard';
1745  print '<td class="center">'.$langs->trans($type)."</td>";
1746  }
1747 
1748  print '<td class="center">';
1749  if (empty($objp->price_by_qty)) {
1750  print $langs->trans($objp->price_base_type);
1751  }
1752  print "</td>";
1753 
1754  if (empty($conf->global->PRODUIT_MULTIPRICES) && empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1755  print '<td class="right">';
1756 
1757  if (empty($objp->price_by_qty)) {
1758  $positiverates = '';
1759  if (price2num($objp->tva_tx)) {
1760  $positiverates .= ($positiverates ? '/' : '').price2num($objp->tva_tx);
1761  }
1762  if (price2num($objp->localtax1_type)) {
1763  $positiverates .= ($positiverates ? '/' : '').price2num($objp->localtax1_tx);
1764  }
1765  if (price2num($objp->localtax2_type)) {
1766  $positiverates .= ($positiverates ? '/' : '').price2num($objp->localtax2_tx);
1767  }
1768  if (empty($positiverates)) {
1769  $positiverates = '0';
1770  }
1771  echo vatrate($positiverates.($objp->default_vat_code ? ' ('.$objp->default_vat_code.')' : ''), '%', !empty($objp->tva_npr) ? $objp->tva_npr : 0);
1772  /*
1773  if ($objp->default_vat_code)
1774  {
1775  print vatrate($objp->tva_tx, true) . ' ('.$objp->default_vat_code.')';
1776  }
1777  else print vatrate($objp->tva_tx, true, $objp->recuperableonly);*/
1778  }
1779 
1780  print "</td>";
1781  }
1782 
1783  // Line for default price
1784  if ($objp->price_base_type == 'HT') {
1785  $pu = $objp->price;
1786  } else {
1787  $pu = $objp->price_ttc;
1788  }
1789 
1790  // Local tax was not saved into table llx_product on old version. So we will use value linked to VAT code.
1791  $localtaxarray = getLocalTaxesFromRate($objp->tva_tx.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), 0, $mysoc, $mysoc);
1792  // Define part of HT, VAT, TTC
1793  $resultarray = calcul_price_total(1, $pu, 0, $objp->tva_tx, 1, 1, 0, $objp->price_base_type, $objp->recuperableonly, $object->type, $mysoc, $localtaxarray);
1794  // Calcul du total ht sans remise
1795  $total_ht = $resultarray[0];
1796  $total_vat = $resultarray[1];
1797  $total_localtax1 = $resultarray[9];
1798  $total_localtax2 = $resultarray[10];
1799  $total_ttc = $resultarray[2];
1800 
1801  // Price
1802  if (!empty($objp->fk_price_expression) && !empty($conf->dynamicprices->enabled)) {
1803  $price_expression = new PriceExpression($db);
1804  $res = $price_expression->fetch($objp->fk_price_expression);
1805  $title = $price_expression->title;
1806  print '<td class="right"></td>';
1807  print '<td class="right"></td>';
1808  if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
1809  print '<td class="right"></td>';
1810  }
1811  print '<td class="right">'.$title."</td>";
1812  } else {
1813  // Price HT
1814  print '<td class="right">';
1815  if (empty($objp->price_by_qty)) {
1816  print '<span class="amount">'.price($objp->price).'</span>';
1817  }
1818  print "</td>";
1819  // Price TTC
1820  print '<td class="right">';
1821  if (empty($objp->price_by_qty)) {
1822  $price_ttc = $objp->price_ttc;
1823  print '<span class="amount">'.price($price_ttc).'<span>';
1824  }
1825  print "</td>";
1826  if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
1827  print '<td class="right">';
1828  print $resultarray[2];
1829  print '</td>';
1830  }
1831  if (!empty($conf->dynamicprices->enabled)) { //Only if module is enabled
1832  print '<td class="right"></td>';
1833  }
1834  }
1835 
1836  // Price min
1837  print '<td class="right">';
1838  if (empty($objp->price_by_qty)) {
1839  print price($objp->price_min);
1840  }
1841  print '</td>';
1842 
1843  // Price min inc tax
1844  print '<td class="right">';
1845  if (empty($objp->price_by_qty)) {
1846  $price_min_ttc = $objp->price_min_ttc;
1847  print price($price_min_ttc);
1848  }
1849  print '</td>';
1850 
1851  // User
1852  print '<td class="right">';
1853  if ($objp->user_id > 0) {
1854  $userstatic = new User($db);
1855  $userstatic->fetch($objp->user_id);
1856  print $userstatic->getNomUrl(1, '', 0, 0, 24, 0, 'login');
1857  }
1858  print '</td>';
1859 
1860  // Action
1861  if ($user->rights->produit->supprimer) {
1862  $candelete = 0;
1863  if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1864  if (empty($notfirstlineforlevel[$objp->price_level])) {
1865  $notfirstlineforlevel[$objp->price_level] = 1;
1866  } else {
1867  $candelete = 1;
1868  }
1869  } elseif ($i > 0) {
1870  $candelete = 1;
1871  }
1872 
1873  print '<td class="right">';
1874  if ($candelete || ($db->jdate($objp->dp) >= dol_now())) { // Test on date is to be able to delete a corrupted record with a date in future
1875  print '<a href="'.$_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id.'&lineid='.$objp->rowid.'">';
1876  print img_delete();
1877  print '</a>';
1878  } else {
1879  print '&nbsp;'; // Can not delete last price (it's current price)
1880  }
1881  print '</td>';
1882  }
1883 
1884  print "</tr>\n";
1885  $i++;
1886  }
1887 
1888  $db->free($result);
1889  print "</table>";
1890  print '</div>';
1891  print "<br>";
1892  }
1893 
1894  print '</div>';
1895  } else {
1896  dol_print_error($db);
1897  }
1898 }
1899 
1900 
1901 // Add area to show/add/edit a price for a dedicated customer
1902 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
1903  $prodcustprice = new Productcustomerprice($db);
1904 
1905  $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;
1906  $sortfield = GETPOST('sortfield', 'aZ09comma');
1907  $sortorder = GETPOST('sortorder', 'aZ09comma');
1908  $page = (GETPOST("page", 'int') ?GETPOST("page", 'int') : 0);
1909  if (empty($page) || $page == -1) {
1910  $page = 0;
1911  } // If $page is not defined, or '' or -1
1912  $offset = $limit * $page;
1913  $pageprev = $page - 1;
1914  $pagenext = $page + 1;
1915  if (!$sortorder) {
1916  $sortorder = "ASC";
1917  }
1918  if (!$sortfield) {
1919  $sortfield = "soc.nom";
1920  }
1921 
1922  // Build filter to diplay only concerned lines
1923  $filter = array('t.fk_product' => $object->id);
1924 
1925  if (!empty($search_soc)) {
1926  $filter['soc.nom'] = $search_soc;
1927  }
1928 
1929  if ($action == 'add_customer_price') {
1930  // Form to add a new customer price
1931  $maxpricesupplier = $object->min_recommended_price();
1932 
1933  print '<!-- add_customer_price -->';
1934  print load_fiche_titre($langs->trans('AddCustomerPrice'));
1935 
1936  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1937  print '<input type="hidden" name="token" value="'.newToken().'">';
1938  print '<input type="hidden" name="action" value="add_customer_price_confirm">';
1939  print '<input type="hidden" name="id" value="'.$object->id.'">';
1940 
1941  print '<div class="tabBar tabBarWithBottom">';
1942 
1943  print '<table class="border centpercent">';
1944  print '<tr>';
1945  print '<td class="fieldrequired">'.$langs->trans('ThirdParty').'</td>';
1946  print '<td>';
1947  print img_picto('', 'company').$form->select_company('', 'socid', 's.client IN (1,2,3)', 'SelectThirdParty', 0, 0, array(), 0, 'minwidth300');
1948  print '</td>';
1949  print '</tr>';
1950 
1951  // Ref. Customer
1952  print '<tr><td>' . $langs->trans('RefCustomer') . '</td>';
1953  print '<td><input name="ref_customer" size="12"></td></tr>';
1954 
1955  // VAT
1956  print '<tr><td class="fieldrequired">'.$langs->trans("DefaultTaxRate").'</td><td>';
1957  print $form->load_tva("tva_tx", $object->default_vat_code ? $object->tva_tx.' ('.$object->default_vat_code.')' : $object->tva_tx, $mysoc, '', $object->id, $object->tva_npr, $object->type, false, 1);
1958  print '</td></tr>';
1959 
1960  // Price base
1961  print '<tr><td class="fieldrequired">';
1962  print $langs->trans('PriceBase');
1963  print '</td>';
1964  print '<td>';
1965  print $form->selectPriceBaseType($object->price_base_type, "price_base_type");
1966  print '</td>';
1967  print '</tr>';
1968 
1969  // Price
1970  print '<tr><td class="fieldrequired">';
1971  $text = $langs->trans('SellingPrice');
1972  print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", $conf->global->MAIN_MAX_DECIMALS_UNIT), 1, 1);
1973  print '</td><td>';
1974  if ($object->price_base_type == 'TTC') {
1975  print '<input name="price" size="10" value="'.price($object->price_ttc).'">';
1976  } else {
1977  print '<input name="price" size="10" value="'.price($object->price).'">';
1978  }
1979  print '</td></tr>';
1980 
1981  // Price minimum
1982  print '<tr><td>';
1983  $text = $langs->trans('MinPrice');
1984  print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", $conf->global->MAIN_MAX_DECIMALS_UNIT), 1, 1);
1985  if ($object->price_base_type == 'TTC') {
1986  print '<td><input name="price_min" size="10" value="'.price($object->price_min_ttc).'">';
1987  } else {
1988  print '<td><input name="price_min" size="10" value="'.price($object->price_min).'">';
1989  }
1990  if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE)) {
1991  print '<td class="left">'.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().'</td>';
1992  }
1993  print '</td></tr>';
1994 
1995  print '</table>';
1996 
1997  print '</div>';
1998 
1999 
2000  print '<div class="center">';
2001 
2002  // Update all child soc
2003  print '<div class="marginbottomonly">';
2004  print '<input type="checkbox" name="updatechildprice" id="updatechildprice" value="1"> ';
2005  print '<label for="updatechildprice">'.$langs->trans('ForceUpdateChildPriceSoc').'</label>';
2006  print '</div>';
2007 
2008  print $form->buttonsSaveCancel();
2009 
2010  print '</form>';
2011  } elseif ($action == 'edit_customer_price') {
2012  // Edit mode
2013  $maxpricesupplier = $object->min_recommended_price();
2014 
2015  print '<!-- edit_customer_price -->';
2016  print load_fiche_titre($langs->trans('PriceByCustomer'));
2017 
2018  $result = $prodcustprice->fetch(GETPOST('lineid', 'int'));
2019  if ($result < 0) {
2020  setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
2021  }
2022 
2023  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
2024  print '<input type="hidden" name="token" value="'.newToken().'">';
2025  print '<input type="hidden" name="action" value="update_customer_price_confirm">';
2026  print '<input type="hidden" name="lineid" value="'.$prodcustprice->id.'">';
2027 
2028  print '<table class="liste centpercent">';
2029  print '<tr>';
2030  print '<td class="titlefield fieldrequired">'.$langs->trans('ThirdParty').'</td>';
2031  $staticsoc = new Societe($db);
2032  $staticsoc->fetch($prodcustprice->fk_soc);
2033  print "<td>".$staticsoc->getNomUrl(1)."</td>";
2034  print '</tr>';
2035 
2036  // Ref. Customer
2037  print '<tr><td>' . $langs->trans('RefCustomer') . '</td>';
2038  print '<td><input name="ref_customer" size="12" value="' . dol_escape_htmltag($prodcustprice->ref_customer) . '"></td></tr>';
2039 
2040  // VAT
2041  print '<tr><td class="fieldrequired">'.$langs->trans("DefaultTaxRate").'</td><td>';
2042  print $form->load_tva("tva_tx", $prodcustprice->default_vat_code ? $prodcustprice->tva_tx.' ('.$prodcustprice->default_vat_code.')' : $prodcustprice->tva_tx, $mysoc, '', $object->id, $prodcustprice->recuperableonly, $object->type, false, 1);
2043  print '</td></tr>';
2044 
2045  // Price base
2046  print '<tr><td class="fieldrequired">';
2047  print $langs->trans('PriceBase');
2048  print '</td>';
2049  print '<td>';
2050  print $form->selectPriceBaseType($prodcustprice->price_base_type, "price_base_type");
2051  print '</td>';
2052  print '</tr>';
2053 
2054  // Price
2055  print '<tr><td class="fieldrequired">';
2056  $text = $langs->trans('SellingPrice');
2057  print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", $conf->global->MAIN_MAX_DECIMALS_UNIT), 1, 1);
2058  print '</td><td>';
2059  if ($prodcustprice->price_base_type == 'TTC') {
2060  print '<input name="price" size="10" value="'.price($prodcustprice->price_ttc).'">';
2061  } else {
2062  print '<input name="price" size="10" value="'.price($prodcustprice->price).'">';
2063  }
2064  print '</td></tr>';
2065 
2066  // Price minimum
2067  print '<tr><td>';
2068  $text = $langs->trans('MinPrice');
2069  print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", $conf->global->MAIN_MAX_DECIMALS_UNIT), 1, 1);
2070  print '</td><td>';
2071  if ($prodcustprice->price_base_type == 'TTC') {
2072  print '<input name="price_min" size="10" value="'.price($prodcustprice->price_min_ttc).'">';
2073  } else {
2074  print '<input name="price_min" size="10" value="'.price($prodcustprice->price_min).'">';
2075  }
2076  print '</td>';
2077  if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE)) {
2078  print '<td class="left">'.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().'</td>';
2079  }
2080  print '</tr>';
2081 
2082  print '</table>';
2083 
2084 
2085  print '<div class="center">';
2086  print '<div class="marginbottomonly">';
2087  print '<input type="checkbox" name="updatechildprice" id="updatechildprice" value="1"> ';
2088  print '<label for="updatechildprice">'.$langs->trans('ForceUpdateChildPriceSoc').'</label>';
2089  print "</div>";
2090 
2091  print $form->buttonsSaveCancel();
2092 
2093  print '<br></form>';
2094  } elseif ($action == 'showlog_customer_price') {
2095  // List of all log of prices by customers
2096  print '<!-- list of all log of prices per customer -->'."\n";
2097 
2098  $filter = array('t.fk_product' => $object->id, 't.fk_soc' => GETPOST('socid', 'int'));
2099 
2100  // Count total nb of records
2101  $nbtotalofrecords = '';
2102  if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
2103  $nbtotalofrecords = $prodcustprice->fetch_all_log($sortorder, $sortfield, $conf->liste_limit, $offset, $filter);
2104  }
2105 
2106  $result = $prodcustprice->fetch_all_log($sortorder, $sortfield, $conf->liste_limit, $offset, $filter);
2107  if ($result < 0) {
2108  setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
2109  }
2110 
2111  $option = '&socid='.GETPOST('socid', 'int').'&id='.$object->id;
2112 
2113  $staticsoc = new Societe($db);
2114  $staticsoc->fetch(GETPOST('socid', 'int'));
2115 
2116  $title = $langs->trans('PriceByCustomerLog');
2117  $title .= ' - '.$staticsoc->getNomUrl(1);
2118 
2119  $backbutton = '<a class="justalink" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">'.$langs->trans("Back").'</a>';
2120 
2121  print_barre_liste($title, $page, $_SERVER['PHP_SELF'], $option, $sortfield, $sortorder, $backbutton, count($prodcustprice->lines), $nbtotalofrecords, 'title_accountancy.png');
2122 
2123  if (count($prodcustprice->lines) > 0) {
2124  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
2125  print '<input type="hidden" name="token" value="'.newToken().'">';
2126  print '<input type="hidden" name="id" value="'.$object->id.'">';
2127 
2128  print '<div class="div-table-responsive-no-min">';
2129  print '<table class="liste centpercent">';
2130 
2131  print '<tr class="liste_titre">';
2132  print '<td>'.$langs->trans("ThirdParty").'</td>';
2133  print '<td>'.$langs->trans('RefCustomer').'</td>';
2134  print '<td>'.$langs->trans("AppliedPricesFrom").'</td>';
2135  print '<td class="center">'.$langs->trans("PriceBase").'</td>';
2136  print '<td class="right">'.$langs->trans("DefaultTaxRate").'</td>';
2137  print '<td class="right">'.$langs->trans("HT").'</td>';
2138  print '<td class="right">'.$langs->trans("TTC").'</td>';
2139  if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2140  print '<td class="right">'.$langs->trans("INCT").'</td>';
2141  }
2142  print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("HT").'</td>';
2143  print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("TTC").'</td>';
2144  print '<td class="right">'.$langs->trans("ChangedBy").'</td>';
2145  print '<td>&nbsp;</td>';
2146  print '</tr>';
2147 
2148  foreach ($prodcustprice->lines as $line) {
2149  // Date
2150  $staticsoc = new Societe($db);
2151  $staticsoc->fetch($line->fk_soc);
2152 
2153  $tva_tx = $line->default_vat_code ? $line->tva_tx.' ('.$line->default_vat_code.')' : $line->tva_tx;
2154 
2155  // Line for default price
2156  if ($line->price_base_type == 'HT') {
2157  $pu = $line->price;
2158  } else {
2159  $pu = $line->price_ttc;
2160  }
2161 
2162  // Local tax is not saved into table of product. We use value linked to VAT code.
2163  $localtaxarray = getLocalTaxesFromRate($line->tva_tx.($line->default_vat_code ? ' ('.$line->default_vat_code.')' : ''), 0, $staticsoc, $mysoc);
2164  // Define part of HT, VAT, TTC
2165  $resultarray = calcul_price_total(1, $pu, 0, $line->tva_tx, 1, 1, 0, $line->price_base_type, $line->recuperableonly, $object->type, $mysoc, $localtaxarray);
2166  // Calcul du total ht sans remise
2167  $total_ht = $resultarray[0];
2168  $total_vat = $resultarray[1];
2169  $total_localtax1 = $resultarray[9];
2170  $total_localtax2 = $resultarray[10];
2171  $total_ttc = $resultarray[2];
2172 
2173  print '<tr class="oddeven">';
2174 
2175  print "<td>".$staticsoc->getNomUrl(1)."</td>";
2176  print '<td>'.$line->ref_customer.'</td>';
2177  print "<td>".dol_print_date($line->datec, "dayhour", 'tzuserrel')."</td>";
2178  print '<td class="center">'.$langs->trans($line->price_base_type)."</td>";
2179  print '<td class="right">';
2180 
2181  $positiverates = '';
2182  if (price2num($line->tva_tx)) {
2183  $positiverates .= ($positiverates ? '/' : '').price2num($line->tva_tx);
2184  }
2185  if (price2num($line->localtax1_type)) {
2186  $positiverates .= ($positiverates ? '/' : '').price2num($line->localtax1_tx);
2187  }
2188  if (price2num($line->localtax2_type)) {
2189  $positiverates .= ($positiverates ? '/' : '').price2num($line->localtax2_tx);
2190  }
2191  if (empty($positiverates)) {
2192  $positiverates = '0';
2193  }
2194 
2195  echo vatrate($positiverates.($line->default_vat_code ? ' ('.$line->default_vat_code.')' : ''), '%', ($line->tva_npr ? $line->tva_npr : $line->recuperableonly));
2196 
2197  //. vatrate($tva_tx, true, $line->recuperableonly) .
2198  print "</td>";
2199  print '<td class="right"><span class="amount">'.price($line->price)."</span></td>";
2200 
2201  print '<td class="right"><span class="amount">'.price($line->price_ttc)."</span></td>";
2202  if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2203  print '<td class="right">'.price($resultarray[2]).'</td>';
2204  }
2205 
2206  print '<td class="right">'.price($line->price_min).'</td>';
2207  print '<td class="right">'.price($line->price_min_ttc).'</td>';
2208 
2209  // User
2210  $userstatic = new User($db);
2211  $userstatic->fetch($line->fk_user);
2212  print '<td class="right">';
2213  print $userstatic->getNomUrl(1, '', 0, 0, 24, 0, 'login');
2214  //print $userstatic->getLoginUrl(1);
2215  print '</td>';
2216  print '</tr>';
2217  }
2218  print "</table>";
2219  print '</div>';
2220  } else {
2221  print $langs->trans('None');
2222  }
2223  } elseif ($action != 'showlog_default_price' && $action != 'edit_price') {
2224  // List of all prices by customers
2225  print '<!-- list of all prices per customer -->'."\n";
2226 
2227  // Count total nb of records
2228  $nbtotalofrecords = '';
2229  if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
2230  $nbtotalofrecords = $prodcustprice->fetchAll($sortorder, $sortfield, 0, 0, $filter);
2231  }
2232 
2233  $result = $prodcustprice->fetchAll($sortorder, $sortfield, $conf->liste_limit, $offset, $filter);
2234  if ($result < 0) {
2235  setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
2236  }
2237 
2238  $option = '&search_soc='.$search_soc.'&id='.$object->id;
2239 
2240  print_barre_liste($langs->trans('PriceByCustomer'), $page, $_SERVER ['PHP_SELF'], $option, $sortfield, $sortorder, '', count($prodcustprice->lines), $nbtotalofrecords, 'title_accountancy.png');
2241 
2242  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
2243  print '<input type="hidden" name="token" value="'.newToken().'">';
2244  print '<input type="hidden" name="id" value="'.$object->id.'">';
2245 
2246  print '<!-- List of prices per customer -->'."\n";
2247  print '<div class="div-table-responsive-no-min">'."\n";
2248  print '<table class="liste centpercent">'."\n";
2249 
2250  if (count($prodcustprice->lines) > 0 || $search_soc) {
2251  $colspan = 9;
2252  if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2253  $colspan++;
2254  }
2255 
2256  print '<tr class="liste_titre">';
2257  print '<td class="liste_titre"><input type="text" class="flat maxwidth125" name="search_soc" value="'.$search_soc.'"></td>';
2258  print '<td class="liste_titre" colspan="'.$colspan.'">&nbsp;</td>';
2259  // Print the search button
2260  print '<td class="liste_titre maxwidthsearch">';
2261  $searchpicto = $form->showFilterAndCheckAddButtons(0);
2262  print $searchpicto;
2263  print '</td>';
2264  print '</tr>';
2265  }
2266 
2267  print '<tr class="liste_titre">';
2268  print '<td>'.$langs->trans("ThirdParty").'</td>';
2269  print '<td>'.$langs->trans('RefCustomer').'</td>';
2270  print '<td>'.$langs->trans("AppliedPricesFrom").'</td>';
2271  print '<td class="center">'.$langs->trans("PriceBase").'</td>';
2272  print '<td class="right">'.$langs->trans("DefaultTaxRate").'</td>';
2273  print '<td class="right">'.$langs->trans("HT").'</td>';
2274  print '<td class="right">'.$langs->trans("TTC").'</td>';
2275  if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2276  print '<td class="right">'.$langs->trans("INCT").'</td>';
2277  }
2278  print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("HT").'</td>';
2279  print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("TTC").'</td>';
2280  print '<td class="right">'.$langs->trans("ChangedBy").'</td>';
2281  print '<td></td>';
2282  print '</tr>';
2283 
2284  // Line for default price
2285  if ($object->price_base_type == 'HT') {
2286  $pu = $object->price;
2287  } else {
2288  $pu = $object->price_ttc;
2289  }
2290 
2291  // Local tax was not saved into table llx_product on old version. So we will use value linked to VAT code.
2292  $localtaxarray = getLocalTaxesFromRate($object->tva_tx.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), 0, $mysoc, $mysoc);
2293  // Define part of HT, VAT, TTC
2294  $resultarray = calcul_price_total(1, $pu, 0, $object->tva_tx, 1, 1, 0, $object->price_base_type, $object->recuperableonly, $object->type, $mysoc, $localtaxarray);
2295  // Calcul du total ht sans remise
2296  $total_ht = $resultarray[0];
2297  $total_vat = $resultarray[1];
2298  $total_localtax1 = $resultarray[9];
2299  $total_localtax2 = $resultarray[10];
2300  $total_ttc = $resultarray[2];
2301 
2302  print '<tr class="oddeven">';
2303  print '<td colspan="3">' . $langs->trans('Default') . '</td>';
2304 
2305  print '<td class="center">'.$langs->trans($object->price_base_type)."</td>";
2306 
2307  // VAT Rate
2308  print '<td class="right">';
2309 
2310  $positiverates = '';
2311  if (price2num($object->tva_tx)) {
2312  $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx);
2313  }
2314  if (price2num($object->localtax1_type)) {
2315  $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx);
2316  }
2317  if (price2num($object->localtax2_type)) {
2318  $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx);
2319  }
2320  if (empty($positiverates)) {
2321  $positiverates = '0';
2322  }
2323  echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), '%', $object->tva_npr);
2324 
2325  //print vatrate($object->tva_tx, true, $object->tva_npr);
2326  //print $object->default_vat_code?' ('.$object->default_vat_code.')':'';
2327  print "</td>";
2328 
2329  print '<td class="right"><span class="amount">'.price($object->price)."</span></td>";
2330 
2331  print '<td class="right"><span class="amount">'.price($object->price_ttc)."</span></td>";
2332  if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2333  //print '<td class="right">' . price($object->price_ttc) . "</td>";
2334  print '<td class="right"><span class="amount">'.price($resultarray[2]).'</span></td>';
2335  }
2336 
2337  print '<td class="right">'.price($object->price_min).'</td>';
2338  print '<td class="right">'.price($object->price_min_ttc).'</td>';
2339  print '<td class="right">';
2340  print '</td>';
2341  if ($user->rights->produit->supprimer || $user->rights->service->supprimer) {
2342  print '<td class="nowraponall">';
2343  print '<a class="marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?action=showlog_default_price&token='.newToken().'&id='.$object->id.'">';
2344  print img_info($langs->trans('PriceByCustomerLog'));
2345  print '</a>';
2346  print ' ';
2347  print '<a class="marginleftonly marginrightonly editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit_price&token='.newToken().'&id='.$object->id.'">';
2348  print img_edit('default', 0, 'style="vertical-align: middle;"');
2349  print '</a>';
2350  print '</td>';
2351  }
2352  print "</tr>\n";
2353 
2354  if (count($prodcustprice->lines) > 0) {
2355  foreach ($prodcustprice->lines as $line) {
2356  // Date
2357  $staticsoc = new Societe($db);
2358  $staticsoc->fetch($line->fk_soc);
2359 
2360  $tva_tx = $line->default_vat_code ? $line->tva_tx.' ('.$line->default_vat_code.')' : $line->tva_tx;
2361 
2362  // Line for default price
2363  if ($line->price_base_type == 'HT') {
2364  $pu = $line->price;
2365  } else {
2366  $pu = $line->price_ttc;
2367  }
2368 
2369  // Local tax is not saved into table of product. We use value linked to VAT code.
2370  $localtaxarray = getLocalTaxesFromRate($line->tva_tx.($line->default_vat_code ? ' ('.$line->default_vat_code.')' : ''), 0, $staticsoc, $mysoc);
2371  // Define part of HT, VAT, TTC
2372  $resultarray = calcul_price_total(1, $pu, 0, $line->tva_tx, 1, 1, 0, $line->price_base_type, $line->recuperableonly, $object->type, $mysoc, $localtaxarray);
2373  // Calcul du total ht sans remise
2374  $total_ht = $resultarray[0];
2375  $total_vat = $resultarray[1];
2376  $total_localtax1 = $resultarray[9];
2377  $total_localtax2 = $resultarray[10];
2378  $total_ttc = $resultarray[2];
2379 
2380  print '<tr class="oddeven">';
2381 
2382  print "<td>".$staticsoc->getNomUrl(1)."</td>";
2383  print '<td>'.dol_escape_htmltag($line->ref_customer).'</td>';
2384  print "<td>".dol_print_date($line->datec, "dayhour", 'tzuserrel')."</td>";
2385  print '<td class="center">'.$langs->trans($line->price_base_type)."</td>";
2386  // VAT Rate
2387  print '<td class="right">';
2388 
2389  $positiverates = '';
2390  if (price2num($line->tva_tx)) {
2391  $positiverates .= ($positiverates ? '/' : '').price2num($line->tva_tx);
2392  }
2393  if (price2num($line->localtax1_type)) {
2394  $positiverates .= ($positiverates ? '/' : '').price2num($line->localtax1_tx);
2395  }
2396  if (price2num($line->localtax2_type)) {
2397  $positiverates .= ($positiverates ? '/' : '').price2num($line->localtax2_tx);
2398  }
2399  if (empty($positiverates)) {
2400  $positiverates = '0';
2401  }
2402 
2403  echo vatrate($positiverates.($line->default_vat_code ? ' ('.$line->default_vat_code.')' : ''), '%', ($line->tva_npr ? $line->tva_npr : $line->recuperableonly));
2404 
2405  print "</td>";
2406 
2407  print '<td class="right"><span class="amount">'.price($line->price)."</span></td>";
2408 
2409  print '<td class="right"><span class="amount">'.price($line->price_ttc)."</span></td>";
2410  if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2411  //print '<td class="right">' . price($line->price_ttc) . "</td>";
2412  print '<td class="right"><span class="amount">'.price($resultarray[2]).'</span></td>';
2413  }
2414 
2415  print '<td class="right">'.price($line->price_min).'</td>';
2416  print '<td class="right">'.price($line->price_min_ttc).'</td>';
2417 
2418  // User
2419  $userstatic = new User($db);
2420  $userstatic->fetch($line->fk_user);
2421  print '<td class="right">';
2422  print $userstatic->getNomUrl(1, '', 0, 0, 24, 0, 'login');
2423  print '</td>';
2424 
2425  // Todo Edit or delete button
2426  // Action
2427  if ($user->rights->produit->supprimer || $user->rights->service->supprimer) {
2428  print '<td class="right nowraponall">';
2429  print '<a href="'.$_SERVER["PHP_SELF"].'?action=showlog_customer_price&token='.newToken().'&id='.$object->id.'&socid='.$line->fk_soc.'">';
2430  print img_info($langs->trans('PriceByCustomerLog'));
2431  print '</a>';
2432  print ' ';
2433  print '<a class="marginleftonly editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit_customer_price&token='.newToken().'&id='.$object->id.'&lineid='.$line->id.'">';
2434  print img_edit('default', 0, 'style="vertical-align: middle;"');
2435  print '</a>';
2436  print ' ';
2437  print '<a class="marginleftonly" href="'.$_SERVER["PHP_SELF"].'?action=delete_customer_price&token='.newToken().'&id='.$object->id.'&lineid='.$line->id.'">';
2438  print img_delete('default', 'style="vertical-align: middle;"');
2439  print '</a>';
2440  print '</td>';
2441  }
2442 
2443  print "</tr>\n";
2444  }
2445  }
2446 
2447  print "</table>";
2448  print '</div>';
2449 
2450  print "</form>";
2451  }
2452 }
2453 
2454 // End of page
2455 llxFooter();
2456 $db->close();
dolibarr_set_const($db, $name, $value, $type='chaine', $visible=0, $note='', $entity=1)
Insert a parameter (key,value) into database (delete old key then insert it again).
Definition: admin.lib.php:632
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
Class to manage generation of HTML components Only common components must be here.
Class for accesing price expression table.
Class to parse product price expressions.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
File of class to manage predefined price products or services by customer.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
Definition: user.class.php:47
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:745
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tabs of a record.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_get_fiche_end($notab=0)
Return tab footer of a card.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
img_info($titlealt='default')
Show info logo.
div float
Buy price without taxes.
Definition: style.css.php:913
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller='', $localtaxes_array='', $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition: price.lib.php:86
$nbtotalofrecords
Count total nb of records.
Definition: list.php:329
product_prepare_head($object)
Prepare array with list of tabs.
Definition: product.lib.php:35
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:119
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.