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