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