dolibarr 21.0.0-beta
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 if ($res > 0) {
504 $extralabels = $extrafields->fetch_name_optionals_label("product");
505 if (!getDolGlobalString('PRODUIT_MULTIPRICES') && !getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($extralabels)) {
506 // Default price
507 $extrafield_values = $extrafields->getOptionalsFromPost("product");
508 foreach ($extrafield_values as $efkey => $value) {
509 $object->array_options[$efkey] = $value;
510 }
511 $result = $object->insertExtraFields();
512 if ($result < 0) {
513 $error++;
514 }
515 } elseif ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($extralabels)) {
516 $price_extralabels = $extrafields->fetch_name_optionals_label("product_price");
517 $sql = "SELECT rowid";
518 $sql .= " FROM ".$object->db->prefix()."product_price";
519 $sql .= " WHERE entity IN (".getEntity('productprice').")";
520 $sql .= " AND price_level=".((int) $key); // $i
521 $sql .= " AND fk_product = ".((int) $object->id);
522 $sql .= " ORDER BY date_price DESC, rowid DESC";
523 $sql .= " LIMIT 1";
524 $resql = $object->db->query($sql);
525 if ($resql) {
526 $lineid = $object->db->fetch_object($resql);
527 $db->free($resql);
528 }
529 if (!empty($lineid->rowid)) {
530 if (!empty($price_extralabels) && is_array($price_extralabels)) {
531 foreach ($price_extralabels as $code => $label) {
532 $code_array = GETPOST($code, 'array');
533 $object->array_options['options_'.$code] = $code_array[$key];
534 }
535 // We need to force table to update product_price and not product extrafields
536 $object->id = $lineid->rowid;
537 $object->table_element = 'product_price';
538 $result = $object->insertExtraFields();
539 }
540 // Back to product table
541 $object->id = $id;
542 $object->table_element = 'product';
543 if ($result < 0) {
544 $error++;
545 }
546 }
547 }
548 }
549 } else {
550 $res = 0;
551 }
552
553 if ($res < 0) {
554 $error++;
555 setEventMessages($object->error, $object->errors, 'errors');
556 break;
557 }
558 }
559 }
560
561 if (!$error && $object->update($object->id, $user) < 0) {
562 $error++;
563 setEventMessages($object->error, $object->errors, 'errors');
564 }
565
566 if (empty($error)) {
567 $action = '';
568 setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
569 $db->commit();
570 } else {
571 $action = 'edit_price';
572 $db->rollback();
573 }
574 }
575
576
577 if ($action == 'delete' && $user->hasRight('produit', 'supprimer')) {
578 $result = $object->log_price_delete($user, GETPOSTINT('lineid'));
579 if ($result < 0) {
580 setEventMessages($object->error, $object->errors, 'errors');
581 }
582 }
583
584 // Set Price by quantity
585 if ($action == 'activate_price_by_qty') {
586 // Activating product price by quantity add a new price line with price_by_qty set to 1
587 $level = GETPOSTINT('level');
588 $basePrice = ($object->price_base_type == 'HT') ? $object->price : $object->price_ttc;
589 $basePriceMin = ($object->price_base_type == 'HT') ? $object->price_min : $object->price_min_ttc;
590 $ret = $object->updatePrice($basePrice, $object->price_base_type, $user, $object->tva_tx, $basePriceMin, $level, $object->tva_npr, 1);
591
592 if ($ret < 0) {
593 setEventMessages($object->error, $object->errors, 'errors');
594 }
595 }
596 // Unset Price by quantity
597 if ($action == 'disable_price_by_qty') {
598 // Disabling product price by quantity add a new price line with price_by_qty set to 0
599 $level = GETPOSTINT('level');
600 $basePrice = ($object->price_base_type == 'HT') ? $object->price : $object->price_ttc;
601 $basePriceMin = ($object->price_base_type == 'HT') ? $object->price_min : $object->price_min_ttc;
602 $ret = $object->updatePrice($basePrice, $object->price_base_type, $user, $object->tva_tx, $basePriceMin, $level, $object->tva_npr, 0);
603
604 if ($ret < 0) {
605 setEventMessages($object->error, $object->errors, 'errors');
606 }
607 }
608
609 if ($action == 'edit_price_by_qty') { // Edition d'un prix par quantité
610 $rowid = GETPOSTINT('rowid');
611 }
612
613 // Add or update price by quantity
614 if ($action == 'update_price_by_qty') {
615 // Récupération des variables
616 $rowid = GETPOSTINT('rowid');
617 $priceid = GETPOSTINT('priceid');
618 $newprice = price2num(GETPOST("price"), 'MU', 2);
619 // $newminprice=price2num(GETPOST("price_min"),'MU'); // TODO : Add min price management
620 $quantity = price2num(GETPOST('quantity'), 'MS', 2);
621 $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
622 $remise = 0; // TODO : allow discount by amount when available on documents
623
624 if (empty($quantity)) {
625 $error++;
626 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Qty")), null, 'errors');
627 }
628 if (empty($newprice)) {
629 $error++;
630 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Price")), null, 'errors');
631 }
632 if (!$error) {
633 // Calcul du prix HT et du prix unitaire
634 if ($object->price_base_type == 'TTC') {
635 $price = (float) price2num($newprice) / (1 + ($object->tva_tx / 100));
636 }
637
638 $price = price2num($newprice, 'MU');
639 $unitPrice = price2num((float) $price / (float) $quantity, 'MU');
640
641 // Ajout / mise à jour
642 if ($rowid > 0) {
643 $sql = "UPDATE ".MAIN_DB_PREFIX."product_price_by_qty SET";
644 $sql .= " price=".((float) $price).",";
645 $sql .= " unitprice=".((float) $unitPrice).",";
646 $sql .= " quantity=".((float) $quantity).",";
647 $sql .= " remise_percent=".((float) $remise_percent).",";
648 $sql .= " remise=".((float) $remise);
649 $sql .= " WHERE rowid = ".((int) $rowid);
650
651 $result = $db->query($sql);
652 if (!$result) {
653 dol_print_error($db);
654 }
655 } else {
656 $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,unitprice,quantity,remise_percent,remise) values (";
657 $sql .= ((int) $priceid).','.((float) $price).','.((float) $unitPrice).','.((float) $quantity).','.((float) $remise_percent).','.((float) $remise).')';
658
659 $result = $db->query($sql);
660 if (!$result) {
661 if ($db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
662 setEventMessages($langs->trans("DuplicateRecord"), null, 'errors');
663 } else {
664 dol_print_error($db);
665 }
666 }
667 }
668 }
669 }
670
671 if ($action == 'delete_price_by_qty') {
672 $rowid = GETPOSTINT('rowid');
673 if (!empty($rowid)) {
674 $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price_by_qty";
675 $sql .= " WHERE rowid = ".((int) $rowid);
676
677 $result = $db->query($sql);
678 } else {
679 setEventMessages(('delete_price_by_qty'.$langs->transnoentities('MissingIds')), null, 'errors');
680 }
681 }
682
683 if ($action == 'delete_all_price_by_qty') {
684 $priceid = GETPOSTINT('priceid');
685 if (!empty($rowid)) {
686 $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price_by_qty";
687 $sql .= " WHERE fk_product_price = ".((int) $priceid);
688
689 $result = $db->query($sql);
690 } else {
691 setEventMessages(('delete_price_by_qty'.$langs->transnoentities('MissingIds')), null, 'errors');
692 }
693 }
694
700 if ($action == 'add_customer_price_confirm' && !$cancel && $prodcustprice !== null && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
701 $maxpricesupplier = $object->min_recommended_price();
702
703 $update_child_soc = GETPOSTINT('updatechildprice');
704
705 // add price by customer
706 $prodcustprice->fk_soc = GETPOSTINT('socid');
707 $prodcustprice->ref_customer = GETPOST('ref_customer', 'alpha');
708 $prodcustprice->fk_product = $object->id;
709 $prodcustprice->price = price2num(GETPOST("price"), 'MU');
710 $prodcustprice->price_min = price2num(GETPOST("price_min"), 'MU');
711 $prodcustprice->price_base_type = GETPOST("price_base_type", 'alpha');
712 $prodcustprice->price_label = GETPOST("price_label", 'alpha');
713
714 $extralabels = $extrafields->fetch_name_optionals_label("product_customer_price");
715 $extrafield_values = $extrafields->getOptionalsFromPost("product_customer_price");
716
717 $tva_tx_txt = GETPOST("tva_tx", 'alpha');
718
719 $tva_tx = $tva_tx_txt;
720 $vatratecode = '';
721 if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
722 $vat_src_code = $reg[1];
723 $tva_tx = preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx_txt); // Remove code into vatrate.
724 }
725 $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot
726
727 $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
728 $localtax1 = 0;
729 $localtax2 = 0;
730 $localtax1_type = '0';
731 $localtax2_type = '0';
732 // If value contains the unique code of vat line (new recommended method), we use it to find npr and local taxes
733 if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
734 // We look into database using code
735 $vatratecode = $reg[1];
736 // Get record from code
737 $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
738 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
739 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
740 $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
741 $sql .= " AND t.code ='".$db->escape($vatratecode)."'";
742 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
743 $resql = $db->query($sql);
744 if ($resql) {
745 $obj = $db->fetch_object($resql);
746 if ($obj) {
747 $npr = $obj->recuperableonly;
748 $localtax1 = $obj->localtax1;
749 $localtax2 = $obj->localtax2;
750 $localtax1_type = $obj->localtax1_type;
751 $localtax2_type = $obj->localtax2_type;
752 }
753
754 // If spain, we don't use the localtax found into tax record in database with same code, but using the get_localtax rule.
755 if (in_array($mysoc->country_code, array('ES'))) {
756 $localtax1 = get_localtax($tva_tx, 1);
757 $localtax2 = get_localtax($tva_tx, 2);
758 }
759 }
760 } else {
761 // Get record with empty code
762 $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
763 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
764 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
765 $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
766 $sql .= " AND t.code = ''";
767 $resql = $db->query($sql);
768 if ($resql) {
769 $obj = $db->fetch_object($resql);
770 if ($obj) {
771 $npr = $obj->recuperableonly;
772 $localtax1 = $obj->localtax1;
773 $localtax2 = $obj->localtax2;
774 $localtax1_type = $obj->localtax1_type;
775 $localtax2_type = $obj->localtax2_type;
776 }
777 }
778 }
779
780 $prodcustprice->default_vat_code = $vatratecode;
781 $prodcustprice->tva_tx = $tva_tx;
782 $prodcustprice->recuperableonly = $npr;
783 $prodcustprice->localtax1_tx = $localtax1;
784 $prodcustprice->localtax2_tx = $localtax2;
785 $prodcustprice->localtax1_type = $localtax1_type;
786 $prodcustprice->localtax2_type = $localtax2_type;
787
788 if (!($prodcustprice->fk_soc > 0)) {
789 $langs->load("errors");
790 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ThirdParty")), null, 'errors');
791 $error++;
792 $action = 'add_customer_price';
793 }
794 if (getDolGlobalString('PRODUCT_MINIMUM_RECOMMENDED_PRICE') && $prodcustprice->price_min < $maxpricesupplier) {
795 $langs->load("errors");
796 setEventMessages($langs->trans("MinimumPriceLimit", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')), null, 'errors');
797 $error++;
798 $action = 'add_customer_price';
799 }
800
801 if (!$error) {
802 $result = $prodcustprice->create($user, 0, $update_child_soc);
803 if ($result > 0) {
804 if (!empty($extrafield_values) && is_array($extrafield_values)) {
805 $productcustomerprice = new ProductCustomerPrice($db);
806 $res = $productcustomerprice->fetch($prodcustprice->id);
807 if ($res > 0) {
808 foreach ($extrafield_values as $key => $value) {
809 $productcustomerprice->array_options[$key] = $value;
810 }
811 $result2 = $productcustomerprice->insertExtraFields();
812 if ($result2 < 0) {
813 $prodcustprice->error = $productcustomerprice->error;
814 $prodcustprice->errors = $productcustomerprice->errors;
815 $error++;
816 }
817 }
818 }
819 }
820
821 if ($result < 0) {
822 setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
823 } else {
824 setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
825 }
826
827 $action = '';
828 }
829 }
830
831 if ($action == 'delete_customer_price' && $prodcustprice !== null && ($user->hasRight('produit', 'supprimer') || $user->hasRight('service', 'supprimer'))) {
832 // Delete price by customer
833 $prodcustprice->id = GETPOSTINT('lineid');
834 $result = $prodcustprice->delete($user);
835
836 if ($result > 0) {
837 $db->query("DELETE FROM ".MAIN_DB_PREFIX."product_customer_price_extrafields WHERE fk_object = ".((int) $prodcustprice->id));
838 setEventMessages($langs->trans("PriceRemoved"), null, 'mesgs');
839 } else {
840 $error++;
841 setEventMessages($object->error, $object->errors, 'errors');
842 }
843
844 if ($result < 0) {
845 setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
846 } else {
847 setEventMessages($langs->trans('RecordDeleted'), null, 'mesgs');
848 }
849 $action = '';
850 }
851
852 if ($action == 'update_customer_price_confirm' && !$cancel && $prodcustprice !== null && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
853 $maxpricesupplier = $object->min_recommended_price();
854
855 $update_child_soc = GETPOSTINT('updatechildprice');
856
857 $prodcustprice->fetch(GETPOSTINT('lineid'));
858
859 // update price by customer
860 $prodcustprice->ref_customer = GETPOST('ref_customer', 'alpha');
861 $prodcustprice->price = price2num(GETPOST("price"), 'MU');
862 $prodcustprice->price_min = price2num(GETPOST("price_min"), 'MU');
863 $prodcustprice->price_base_type = GETPOST("price_base_type", 'alpha');
864 $prodcustprice->price_label = GETPOST("price_label", 'alpha');
865
866 $extralabels = $extrafields->fetch_name_optionals_label("product_customer_price");
867 $extrafield_values = $extrafields->getOptionalsFromPost("product_customer_price");
868
869 $tva_tx_txt = GETPOST("tva_tx");
870
871 $tva_tx = $tva_tx_txt;
872 $vatratecode = '';
873 if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
874 $vat_src_code = $reg[1];
875 $tva_tx = preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx_txt); // Remove code into vatrate.
876 }
877 $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot
878
879 $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
880 $localtax1 = 0;
881 $localtax2 = 0;
882 $localtax1_type = '0';
883 $localtax2_type = '0';
884 // If value contains the unique code of vat line (new recommended method), we use it to find npr and local taxes
885 if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
886 // We look into database using code
887 $vatratecode = $reg[1];
888 // Get record from code
889 $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
890 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
891 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
892 $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
893 $sql .= " AND t.code ='".$db->escape($vatratecode)."'";
894 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
895 $resql = $db->query($sql);
896 if ($resql) {
897 $obj = $db->fetch_object($resql);
898 if ($obj) {
899 $npr = $obj->recuperableonly;
900 $localtax1 = $obj->localtax1;
901 $localtax2 = $obj->localtax2;
902 $localtax1_type = $obj->localtax1_type;
903 $localtax2_type = $obj->localtax2_type;
904 }
905
906 // If spain, we don't use the localtax found into tax record in database with same code, but using the get_localtax rule.
907 if (in_array($mysoc->country_code, array('ES'))) {
908 $localtax1 = get_localtax($tva_tx, 1);
909 $localtax2 = get_localtax($tva_tx, 2);
910 }
911 }
912 } else {
913 // Get record with empty code
914 $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
915 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
916 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
917 $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
918 $sql .= " AND t.code = ''";
919 $resql = $db->query($sql);
920 if ($resql) {
921 $obj = $db->fetch_object($resql);
922 if ($obj) {
923 $npr = $obj->recuperableonly;
924 $localtax1 = $obj->localtax1;
925 $localtax2 = $obj->localtax2;
926 $localtax1_type = $obj->localtax1_type;
927 $localtax2_type = $obj->localtax2_type;
928 }
929 }
930 }
931
932 $prodcustprice->default_vat_code = $vatratecode;
933 $prodcustprice->tva_tx = $tva_tx;
934 $prodcustprice->recuperableonly = $npr;
935 $prodcustprice->localtax1_tx = $localtax1;
936 $prodcustprice->localtax2_tx = $localtax2;
937 $prodcustprice->localtax1_type = $localtax1_type;
938 $prodcustprice->localtax2_type = $localtax2_type;
939
940 if ($prodcustprice->price_min < $maxpricesupplier && getDolGlobalString('PRODUCT_MINIMUM_RECOMMENDED_PRICE')) {
941 setEventMessages($langs->trans("MinimumPriceLimit", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')), null, 'errors');
942 $error++;
943 $action = 'update_customer_price';
944 }
945
946 if (!$error) {
947 $result = $prodcustprice->update($user, 0, $update_child_soc);
948 if ($result > 0) {
949 if (!empty($extrafield_values) && is_array($extrafield_values)) {
950 $productcustomerprice = new ProductCustomerPrice($db);
951 $res = $productcustomerprice->fetch($prodcustprice->id);
952 if ($res > 0) {
953 foreach ($extrafield_values as $key => $value) {
954 $productcustomerprice->array_options[$key] = $value;
955 }
956 $result2 = $productcustomerprice->insertExtraFields();
957 if ($result2 < 0) {
958 $prodcustprice->error = $productcustomerprice->error;
959 $prodcustprice->errors = $productcustomerprice->errors;
960 $error++;
961 }
962 }
963 }
964 }
965
966 if ($result < 0) {
967 setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
968 } else {
969 setEventMessages($langs->trans("Save"), null, 'mesgs');
970 }
971
972 $action = '';
973 }
974 }
975}
976
977
978/*
979 * View
980 */
981
982$form = new Form($db);
983
984if (!empty($id) || !empty($ref)) {
985 // fetch updated prices
986 $object->fetch($id, $ref);
987}
988
989$title = $langs->trans('ProductServiceCard');
990$helpurl = '';
991$shortlabel = dol_trunc($object->label, 16);
992if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT)) {
993 $title = $langs->trans('Product')." ".$shortlabel." - ".$langs->trans('SellingPrices');
994 $helpurl = 'EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
995}
996if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE)) {
997 $title = $langs->trans('Service')." ".$shortlabel." - ".$langs->trans('SellingPrices');
998 $helpurl = 'EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
999}
1000
1001llxHeader('', $title, $helpurl, '', 0, 0, '', '', '', 'classforhorizontalscrolloftabs mod-product page-price');
1002
1003$head = product_prepare_head($object);
1004$titre = $langs->trans("CardProduct".$object->type);
1005$picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
1006
1007print dol_get_fiche_head($head, 'price', $titre, -1, $picto);
1008
1009$linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?restore_lastsearch_values=1&type='.$object->type.'">'.$langs->trans("BackToList").'</a>';
1010$object->next_prev_filter = "fk_product_type:=:".((int) $object->type);
1011
1012$shownav = 1;
1013if ($user->socid && !in_array('product', explode(',', getDolGlobalString('MAIN_MODULES_FOR_EXTERNAL')))) {
1014 $shownav = 0;
1015}
1016
1017dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref');
1018
1019
1020print '<div class="fichecenter">';
1021
1022print '<div class="underbanner clearboth"></div>';
1023print '<table class="border tableforfield centpercent">';
1024
1025// Price per customer segment/level
1026if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1027 $soc = null;
1028 // Price and min price are variable (depends on level of company).
1029 if (!empty($socid)) {
1030 $soc = new Societe($db);
1031 $soc->id = $socid;
1032 $soc->fetch($socid);
1033
1034 // Type
1035 if (isModEnabled("product") && isModEnabled("service")) {
1036 $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
1037 print '<tr><td class="">';
1038 print (!getDolGlobalString('PRODUCT_DENY_CHANGE_PRODUCT_TYPE')) ? $form->editfieldkey("Type", 'fk_product_type', $object->type, $object, 0, $typeformat) : $langs->trans('Type');
1039 print '</td><td>';
1040 print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, 0, $typeformat);
1041 print '</td></tr>';
1042 }
1043
1044 // Selling price
1045 print '<tr><td class="titlefieldcreate">';
1046 print $langs->trans("SellingPrice");
1047 print '</td>';
1048 print '<td colspan="2">';
1049 if ($object->multiprices_base_type[$soc->price_level] == 'TTC') {
1050 print '<span class="amount">'.price($object->multiprices_ttc[$soc->price_level]).'</span>';
1051 } else {
1052 print '<span class="amount">'.price($object->multiprices[$soc->price_level]).'</span>';
1053 }
1054 if ($object->multiprices_base_type[$soc->price_level]) {
1055 print ' '.$langs->trans($object->multiprices_base_type[$soc->price_level]);
1056 } else {
1057 print ' '.$langs->trans($object->price_base_type);
1058 }
1059 print '</td></tr>';
1060
1061 // Price min
1062 print '<tr><td>'.$langs->trans("MinPrice").'</td><td colspan="2">';
1063 if ($object->multiprices_base_type[$soc->price_level] == 'TTC') {
1064 print price($object->multiprices_min_ttc[$soc->price_level]).' '.$langs->trans($object->multiprices_base_type[$soc->price_level]);
1065 } else {
1066 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]);
1067 }
1068 print '</td></tr>';
1069
1070 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
1071 // TVA
1072 print '<tr><td>'.$langs->trans("DefaultTaxRate").'</td><td colspan="2">';
1073
1074 $positiverates = '';
1075 if (price2num($object->multiprices_tva_tx[$soc->price_level])) {
1076 $positiverates .= ($positiverates ? '/' : '').price2num($object->multiprices_tva_tx[$soc->price_level]);
1077 }
1078 if (price2num($object->multiprices_localtax1_type[$soc->price_level])) {
1079 $positiverates .= ($positiverates ? '/' : '').price2num($object->multiprices_localtax1_tx[$soc->price_level]);
1080 }
1081 if (price2num($object->multiprices_localtax2_type[$soc->price_level])) {
1082 $positiverates .= ($positiverates ? '/' : '').price2num($object->multiprices_localtax2_tx[$soc->price_level]);
1083 }
1084 if (empty($positiverates)) {
1085 $positiverates = '0';
1086 }
1087 echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), true, $object->tva_npr);
1088 //print vatrate($object->multiprices_tva_tx[$soc->price_level], true);
1089 print '</td></tr>';
1090 } else {
1091 // TVA
1092 print '<tr><td>'.$langs->trans("DefaultTaxRate").'</td><td>';
1093
1094 $positiverates = '';
1095 if (price2num($object->tva_tx)) {
1096 $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx);
1097 }
1098 if (price2num($object->localtax1_type)) {
1099 $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx);
1100 }
1101 if (price2num($object->localtax2_type)) {
1102 $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx);
1103 }
1104 if (empty($positiverates)) {
1105 $positiverates = '0';
1106 }
1107 echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), true, $object->tva_npr);
1108 /*
1109 if ($object->default_vat_code)
1110 {
1111 print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')';
1112 }
1113 else print vatrate($object->tva_tx . ($object->tva_npr ? '*' : ''), true);*/
1114 print '</td></tr>';
1115 }
1116 } else {
1117 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
1118 // Type
1119 if (isModEnabled("product") && isModEnabled("service")) {
1120 $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
1121 print '<tr><td class="">';
1122 print (!getDolGlobalString('PRODUCT_DENY_CHANGE_PRODUCT_TYPE')) ? $form->editfieldkey("Type", 'fk_product_type', $object->type, $object, 0, $typeformat) : $langs->trans('Type');
1123 print '</td><td>';
1124 print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, 0, $typeformat);
1125 print '</td></tr>';
1126 }
1127
1128 // We show only vat for level 1
1129 print '<tr><td class="titlefieldcreate">'.$langs->trans("DefaultTaxRate").'</td>';
1130 print '<td colspan="2">'.vatrate($object->multiprices_tva_tx[1], true).'</td>';
1131 print '</tr>';
1132 } else {
1133 // Type
1134 if (isModEnabled("product") && isModEnabled("service")) {
1135 $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
1136 print '<tr><td class="">';
1137 print (!getDolGlobalString('PRODUCT_DENY_CHANGE_PRODUCT_TYPE')) ? $form->editfieldkey("Type", 'fk_product_type', $object->type, $object, 0, $typeformat) : $langs->trans('Type');
1138 print '</td><td>';
1139 print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, 0, $typeformat);
1140 print '</td></tr>';
1141 }
1142
1143 // TVA
1144 print '<!-- Default VAT Rate -->';
1145 print '<tr><td class="titlefieldcreate">'.$langs->trans("DefaultTaxRate").'</td><td>';
1146
1147 // TODO We show localtax from $object, but this properties may not be correct. Only value $object->default_vat_code is guaranteed.
1148 $positiverates = '';
1149 if (price2num($object->tva_tx)) {
1150 $positiverates .= ($positiverates ? '<span class="opacitymedium">/</span>' : '').price2num($object->tva_tx);
1151 }
1152 if (price2num($object->localtax1_type)) {
1153 $positiverates .= ($positiverates ? '<span class="opacitymedium">/</span>' : '').price2num($object->localtax1_tx);
1154 }
1155 if (price2num($object->localtax2_type)) {
1156 $positiverates .= ($positiverates ? '<span class="opacitymedium">/</span>' : '').price2num($object->localtax2_tx);
1157 }
1158 if (empty($positiverates)) {
1159 $positiverates = '0';
1160 }
1161
1162 print vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), true, $object->tva_npr, 1);
1163 /*
1164 if ($object->default_vat_code)
1165 {
1166 print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')';
1167 }
1168 else print vatrate($object->tva_tx . ($object->tva_npr ? '*' : ''), true);*/
1169 print '</td></tr>';
1170 }
1171 print '</table>';
1172
1173 print '<br>';
1174
1175 print '<table class="liste centpercent">';
1176 print '<tr class="liste_titre"><td>';
1177 print $langs->trans("PriceLevel");
1178 if ($user->admin) {
1179 print ' <a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editlabelsellingprice&token='.newToken().'&pricelevel='.$i.'&id='.$object->id.'">'.img_edit($langs->trans('EditSellingPriceLabel'), 0).'</a>';
1180 }
1181 print '</td>';
1182 print '<td style="text-align: right">'.$langs->trans("SellingPrice").'</td>';
1183 print '<td style="text-align: right">'.$langs->trans("MinPrice").'</td>';
1184 // fetch optionals attributes and labels
1185 $extrafields->fetch_name_optionals_label("product_price");
1186 if ($extrafields->attributes["product_price"] && array_key_exists('label', $extrafields->attributes["product_price"])) {
1187 $extralabels = $extrafields->attributes["product_price"]['label'];
1188 if (!empty($extralabels)) {
1189 foreach ($extralabels as $key => $value) {
1190 // Show field if not hidden
1191 if (!empty($extrafields->attributes["product_price"]['list'][$key]) && $extrafields->attributes["product_price"]['list'][$key] != 3) {
1192 if (!empty($extrafields->attributes["product_price"]['langfile'][$key])) {
1193 $langs->load($extrafields->attributes["product_price"]['langfile'][$key]);
1194 }
1195 if (!empty($extrafields->attributes["product_price"]['help'][$key])) {
1196 $extratitle = $form->textwithpicto($langs->trans($value), $langs->trans($extrafields->attributes["product_price"]['help'][$key]));
1197 } else {
1198 $extratitle = $langs->trans($value);
1199 }
1200 $field = 'ef.' . $key;
1201 print '<td style="text-align: right">'.$extratitle.'</td>';
1202 }
1203 }
1204 }
1205 }
1206 print '</tr>';
1207
1208 $produit_multiprices_limit = getDolGlobalInt('PRODUIT_MULTIPRICES_LIMIT');
1209 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
1210 print '<tr class="oddeven">';
1211
1212 // Label of price
1213 print '<td>';
1214 $keyforlabel = 'PRODUIT_MULTIPRICES_LABEL'.$i;
1215 if (preg_match('/editlabelsellingprice/', $action)) {
1216 print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
1217 print '<input type="hidden" name="token" value="'.newToken().'">';
1218 print '<input type="hidden" name="action" value="setlabelsellingprice">';
1219 print '<input type="hidden" name="pricelevel" value="'.$i.'">';
1220 print $langs->trans("SellingPrice").' '.$i.' - ';
1221 print '<input class="maxwidthonsmartphone" type="text" name="labelsellingprice" value="' . getDolGlobalString($keyforlabel).'">';
1222 print '&nbsp;<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
1223 print '</form>';
1224 } else {
1225 print $langs->trans("SellingPrice").' '.$i;
1226 if (getDolGlobalString($keyforlabel)) {
1227 print ' - '.$langs->trans(getDolGlobalString($keyforlabel));
1228 }
1229 }
1230 print '</td>';
1231
1232 if ($object->multiprices_base_type [$i] == 'TTC') {
1233 print '<td class="right"><span class="amount">'.price($object->multiprices_ttc[$i]);
1234 } else {
1235 print '<td class="right"><span class="amount">'.price($object->multiprices[$i]);
1236 }
1237
1238 if ($object->multiprices_base_type[$i]) {
1239 print ' '.$langs->trans($object->multiprices_base_type [$i]).'</span></td>';
1240 } else {
1241 print ' '.$langs->trans($object->price_base_type).'</span></td>';
1242 }
1243
1244 // Prix min
1245 print '<td style="text-align: right">';
1246 if (empty($object->multiprices_base_type[$i])) {
1247 $object->multiprices_base_type[$i] = "HT";
1248 }
1249 if ($object->multiprices_base_type[$i] == 'TTC') {
1250 print price($object->multiprices_min_ttc[$i]).' '.$langs->trans($object->multiprices_base_type[$i]);
1251 } else {
1252 print price($object->multiprices_min[$i]).' '.$langs->trans($object->multiprices_base_type[$i]);
1253 }
1254 print '</td>';
1255 if (!empty($extralabels)) {
1256 $sql1 = "SELECT rowid";
1257 $sql1 .= " FROM ".$object->db->prefix()."product_price";
1258 $sql1 .= " WHERE entity IN (".getEntity('productprice').")";
1259 $sql1 .= " AND price_level=".((int) $i);
1260 $sql1 .= " AND fk_product = ".((int) $object->id);
1261 $sql1 .= " ORDER BY date_price DESC, rowid DESC";
1262 $sql1 .= " LIMIT 1";
1263 $resql1 = $object->db->query($sql1);
1264 if ($resql1) {
1265 $lineid = $object->db->fetch_object($resql1);
1266 }
1267 $sql2 = "SELECT";
1268 $sql2 .= " fk_object";
1269 foreach ($extralabels as $key => $value) {
1270 $sql2 .= ", ".$key;
1271 }
1272 $sql2 .= " FROM ".MAIN_DB_PREFIX."product_price_extrafields";
1273 $sql2 .= " WHERE fk_object = ".((int) $lineid->rowid);
1274 $resql2 = $db->query($sql2);
1275 if ($resql2) {
1276 if ($db->num_rows($resql2) != 1) {
1277 foreach ($extralabels as $key => $value) {
1278 if (!empty($extrafields->attributes["product_price"]['list'][$key]) && $extrafields->attributes["product_price"]['list'][$key] != 3) {
1279 print '<td align="right"></td>';
1280 }
1281 }
1282 } else {
1283 $obj = $db->fetch_object($resql2);
1284 foreach ($extralabels as $key => $value) {
1285 if (!empty($extrafields->attributes["product_price"]['list'][$key]) && $extrafields->attributes["product_price"]['list'][$key] != 3) {
1286 print '<td align="right">'.$extrafields->showOutputField($key, $obj->{$key}, '', 'product_price')."</td>";
1287 }
1288 }
1289 }
1290 $db->free($resql1);
1291 $db->free($resql2);
1292 }
1293 }
1294 print '</tr>';
1295
1296 // Price by quantity
1297 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
1298 print '<tr><td>'.$langs->trans("PriceByQuantity").' '.$i;
1299 if (getDolGlobalString($keyforlabel)) {
1300 print ' - '.$langs->trans(getDolGlobalString($keyforlabel));
1301 }
1302 print '</td><td colspan="2">';
1303
1304 if ($object->prices_by_qty[$i] == 1) {
1305 print '<table width="50%" class="border" summary="List of quantities">';
1306
1307 print '<tr class="liste_titre">';
1308 print '<td>'.$langs->trans("PriceByQuantityRange").' '.$i.'</td>';
1309 print '<td class="right">'.$langs->trans("HT").'</td>';
1310 print '<td class="right">'.$langs->trans("UnitPrice").'</td>';
1311 print '<td class="right">'.$langs->trans("Discount").'</td>';
1312 print '<td>&nbsp;</td>';
1313 print '</tr>';
1314 foreach ($object->prices_by_qty_list[$i] as $ii => $prices) {
1315 if ($action == 'edit_price_by_qty' && $rowid == $prices['rowid'] && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
1316 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1317 print '<input type="hidden" name="token" value="'.newToken().'">';
1318 print '<input type="hidden" name="action" value="update_price_by_qty">';
1319 print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[$i].'">';
1320 print '<input type="hidden" value="'.$prices['rowid'].'" name="rowid">';
1321 print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1322 print '<td><input size="5" type="text" value="'.$prices['quantity'].'" name="quantity"></td>';
1323 print '<td class="right" colspan="2"><input size="10" type="text" value="'.price2num($prices['price'], 'MU').'" name="price">&nbsp;'.$object->price_base_type.'</td>';
1324 print '<td class="right nowraponall"><input size="5" type="text" value="'.$prices['remise_percent'].'" name="remise_percent"> %</td>';
1325 print '<td class="center"><input type="submit" value="'.$langs->trans("Modify").'" class="button"></td>';
1326 print '</tr>';
1327 print '</form>';
1328 } else {
1329 print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1330 print '<td>'.$prices['quantity'].'</td>';
1331 print '<td class="right">'.price($prices['price']).'</td>';
1332 print '<td class="right">'.price($prices['unitprice']).'</td>';
1333 print '<td class="right">'.price($prices['remise_percent']).' %</td>';
1334 print '<td class="center">';
1335 if (($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
1336 print '<a class="editfielda marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit_price_by_qty&token='.newToken().'&rowid='.$prices["rowid"].'">';
1337 print img_edit().'</a>';
1338 print '<a class="marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete_price_by_qty&token='.newToken().'&rowid='.$prices["rowid"].'">';
1339 print img_delete().'</a>';
1340 } else {
1341 print '&nbsp;';
1342 }
1343 print '</td>';
1344 print '</tr>';
1345 }
1346 }
1347 if ($action != 'edit_price_by_qty' && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
1348 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1349 print '<input type="hidden" name="token" value="'.newToken().'">';
1350 print '<input type="hidden" name="action" value="update_price_by_qty">';
1351 print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[$i].'">'; // id in product_price
1352 print '<input type="hidden" value="0" name="rowid">'; // id in product_price
1353 print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1354 print '<td><input size="5" type="text" value="1" name="quantity"></td>';
1355 print '<td class="right" class="nowrap"><input size="10" type="text" value="0" name="price">&nbsp;'.$object->price_base_type.'</td>';
1356 print '<td class="right">&nbsp;</td>';
1357 print '<td class="right" class="nowraponall"><input size="5" type="text" value="0" name="remise_percent"> %</td>';
1358 print '<td class="center"><input type="submit" value="'.$langs->trans("Add").'" class="button"></td>';
1359 print '</tr>';
1360 print '</form>';
1361 }
1362
1363 print '</table>';
1364 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>';
1365 } else {
1366 print $langs->trans("No");
1367 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>';
1368 }
1369 print '</td></tr>';
1370 }
1371 }
1372 }
1373} else {
1374 // TVA
1375 print '<tr><td class="titlefield">'.$langs->trans("DefaultTaxRate").'</td><td>';
1376
1377 $positiverates = '';
1378 if (price2num($object->tva_tx)) {
1379 $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx);
1380 }
1381 if (price2num($object->localtax1_type)) {
1382 $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx);
1383 }
1384 if (price2num($object->localtax2_type)) {
1385 $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx);
1386 }
1387 if (empty($positiverates)) {
1388 $positiverates = '0';
1389 }
1390 echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), true, $object->tva_npr, 0, 1);
1391 /*
1392 if ($object->default_vat_code)
1393 {
1394 print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')';
1395 }
1396 else print vatrate($object->tva_tx, true, $object->tva_npr, true);*/
1397 print '</td></tr>';
1398
1399 // Price
1400 print '<tr class="field_selling_price"><td>'.$langs->trans("SellingPrice").'</td><td>';
1401 if ($object->price_base_type == 'TTC') {
1402 print price($object->price_ttc).' '.$langs->trans($object->price_base_type);
1403 } else {
1404 print price($object->price).' '.$langs->trans($object->price_base_type);
1405 if (getDolGlobalString('PRODUCT_DISPLAY_VAT_INCL_PRICES') && !empty($object->price_ttc)) {
1406 print '<i class="opacitymedium"> - ' . price($object->price_ttc).' '.$langs->trans('TTC') . '</i>';
1407 }
1408 }
1409
1410 print '</td></tr>';
1411
1412 // Price minimum
1413 print '<tr class="field_min_price"><td>'.$langs->trans("MinPrice").'</td><td>';
1414 if ($object->price_base_type == 'TTC') {
1415 print price($object->price_min_ttc).' '.$langs->trans($object->price_base_type);
1416 } else {
1417 print price($object->price_min).' '.$langs->trans($object->price_base_type);
1418 if (getDolGlobalString('PRODUCT_DISPLAY_VAT_INCL_PRICES') && !empty($object->price_min_ttc)) {
1419 print '<i class="opacitymedium"> - ' . price($object->price_min_ttc).' '.$langs->trans('TTC') . '</i>';
1420 }
1421 }
1422 print '</td></tr>';
1423
1424 // Price Label
1425 print '<tr class="field_price_label"><td>'.$langs->trans("PriceLabel").'</td><td>';
1426 print $object->price_label;
1427 print '</td></tr>';
1428
1429 // Price by quantity
1430 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) { // TODO Fix the form inside tr instead of td
1431 print '<tr><td>'.$langs->trans("PriceByQuantity");
1432 if ($object->prices_by_qty[0] == 0) {
1433 print '&nbsp; <a href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=activate_price_by_qty&level=1&token='.newToken().'">('.$langs->trans("Activate").')';
1434 } else {
1435 print '&nbsp; <a href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=disable_price_by_qty&level=1&token='.newToken().'">('.$langs->trans("DisablePriceByQty").')';
1436 }
1437 print '</td><td>';
1438
1439 if ($object->prices_by_qty[0] == 1) {
1440 print '<table width="50%" class="border" summary="List of quantities">';
1441 print '<tr class="liste_titre">';
1442 //print '<td>' . $langs->trans("PriceByQuantityRange") . '</td>';
1443 print '<td>'.$langs->trans("Quantity").'</td>';
1444 print '<td class="right">'.$langs->trans("Price").'</td>';
1445 print '<td class="right"></td>';
1446 print '<td class="right">'.$langs->trans("UnitPrice").'</td>';
1447 print '<td class="right">'.$langs->trans("Discount").'</td>';
1448 print '<td>&nbsp;</td>';
1449 print '</tr>';
1450 if ($action != 'edit_price_by_qty') {
1451 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">'; // FIXME a form into a table is not allowed
1452 print '<input type="hidden" name="token" value="'.newToken().'">';
1453 print '<input type="hidden" name="action" value="update_price_by_qty">';
1454 print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[0].'">'; // id in product_price
1455 print '<input type="hidden" value="0" name="rowid">'; // id in product_price_by_qty
1456
1457 print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1458 print '<td><input size="5" type="text" value="1" name="quantity"></td>';
1459 print '<td class="right"><input class="width50 right" type="text" value="0" name="price"></td>';
1460 print '<td>';
1461 //print $object->price_base_type;
1462 print '</td>';
1463 print '<td class="right">&nbsp;</td>';
1464 print '<td class="right nowraponall"><input type="text" class="width50 right" value="0" name="remise_percent"> %</td>';
1465 print '<td class="center"><input type="submit" value="'.$langs->trans("Add").'" class="button"></td>';
1466 print '</tr>';
1467
1468 print '</form>';
1469 }
1470 foreach ($object->prices_by_qty_list[0] as $ii => $prices) {
1471 if ($action == 'edit_price_by_qty' && $rowid == $prices['rowid'] && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
1472 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1473 print '<input type="hidden" name="token" value="'.newToken().'">';
1474 print '<input type="hidden" name="action" value="update_price_by_qty">';
1475 print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[0].'">'; // id in product_price
1476 print '<input type="hidden" value="'.$prices['rowid'].'" name="rowid">'; // id in product_price_by_qty
1477 print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1478 print '<td><input size="5" type="text" value="'.$prices['quantity'].'" name="quantity"></td>';
1479 print '<td class="right"><input class="width50 right" type="text" value="'.price2num($prices['price'], 'MU').'" name="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">&nbsp;</td>';
1485 print '<td class="right nowraponall"><input class="width50 right" type="text" value="'.$prices['remise_percent'].'" name="remise_percent"> %</td>';
1486 print '<td class="center"><input type="submit" value="'.$langs->trans("Modify").'" class="button"></td>';
1487 print '</tr>';
1488 print '</form>';
1489 } else {
1490 print '<tr class="'.($ii % 2 == 0 ? 'pair' : 'impair').'">';
1491 print '<td>'.$prices['quantity'].'</td>';
1492 print '<td class="right">'.price($prices['price']).'</td>';
1493 print '<td class="right">';
1494 //print $object->price_base_type;
1495 print $prices['price_base_type'];
1496 print '</td>';
1497 print '<td class="right">'.price($prices['unitprice']).'</td>';
1498 print '<td class="right">'.price($prices['remise_percent']).' %</td>';
1499 print '<td class="center">';
1500 if (($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
1501 print '<a class="editfielda marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit_price_by_qty&token='.newToken().'&rowid='.$prices["rowid"].'">';
1502 print img_edit().'</a>';
1503 print '<a class="marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete_price_by_qty&token='.newToken().'&rowid='.$prices["rowid"].'">';
1504 print img_delete().'</a>';
1505 } else {
1506 print '&nbsp;';
1507 }
1508 print '</td>';
1509 print '</tr>';
1510 }
1511 }
1512 print '</table>';
1513 } else {
1514 print $langs->trans("No");
1515 }
1516 print '</td></tr>';
1517 }
1518
1519 // Extrafields
1520 $extrafields->fetch_name_optionals_label("product");
1521 $extralabels = !empty($extrafields->attributes["product"]['label']) ? $extrafields->attributes["product"]['label'] : '';
1522 $extrafield_values = $extrafields->getOptionalsFromPost("product");
1523 $sql = "SELECT";
1524 $sql .= " fk_object";
1525 foreach ($extralabels as $key => $value) {
1526 $sql .= ", ".$key;
1527 }
1528 $sql .= " FROM ".MAIN_DB_PREFIX."product_extrafields";
1529 $sql .= " WHERE fk_object = ".((int) $object->id);
1530 $resql = $db->query($sql);
1531 if ($resql) {
1532 $obj = $db->fetch_object($resql);
1533 foreach ($extralabels as $key => $value) {
1534 if (!empty($extrafields->attributes["product"]['list'][$key]) && ($extrafields->attributes["product"]['list'][$key] == 1 || $extrafields->attributes["product"]['list'][$key] == 3 || ($action == "edit_price" && $extrafields->attributes["product"]['list'][$key] == 4))) {
1535 if (!empty($extrafields->attributes["product"]['langfile'][$key])) {
1536 $langs->load($extrafields->attributes["product"]['langfile'][$key]);
1537 }
1538
1539 print '<tr><td'.($extrafields->attributes["product"]['required'][$key] ? ' class="fieldrequired"' : '').'>';
1540 if (!empty($extrafields->attributes["product"]['help'][$key])) {
1541 print $form->textwithpicto($langs->trans($value), $langs->trans($extrafields->attributes["product"]['help'][$key]));
1542 } else {
1543 print $langs->trans($value);
1544 }
1545
1546 print '<td align="left">'.$extrafields->showOutputField($key, $obj->{$key}, '', 'product')."</td></tr>";
1547 }
1548 }
1549 $db->free($resql);
1550 }
1551}
1552
1553print "</table>\n";
1554
1555print '</div>';
1556print '<div class="clearboth"></div>';
1557
1558
1559print dol_get_fiche_end();
1560
1561
1562
1563/*
1564 * Action bar
1565 */
1566
1567
1568if (!$action || $action == 'delete' || $action == 'showlog_customer_price' || $action == 'showlog_default_price' || $action == 'add_customer_price'
1569 || $action == 'activate_price_by_qty' || $action == 'disable_price_by_qty') {
1570 print "\n".'<div class="tabsAction">'."\n";
1571
1572
1573 $parameters = array();
1574 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1575 if (empty($reshook)) {
1576 if ($object->isVariant()) {
1577 if ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer')) {
1578 print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" href="#" title="' . dol_escape_htmltag($langs->trans("NoEditVariants")) . '">' . $langs->trans("UpdateDefaultPrice") . '</a></div>';
1579 }
1580 } else {
1581 if (!getDolGlobalString('PRODUIT_MULTIPRICES') && !getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && !getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1582 if ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer')) {
1583 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>';
1584 } else {
1585 print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("UpdateDefaultPrice") . '</span></div>';
1586 }
1587 }
1588
1589 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1590 if ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer')) {
1591 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>';
1592 } else {
1593 print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("AddCustomerPrice") . '</span></div>';
1594 }
1595 }
1596
1597 if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1598 if ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer')) {
1599 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>';
1600 } else {
1601 print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("UpdateVAT") . '</span></div>';
1602 }
1603
1604 if ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer')) {
1605 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>';
1606 } else {
1607 print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("UpdateLevelPrices") . '</span></div>';
1608 }
1609 }
1610 }
1611 }
1612
1613 print "\n</div>\n";
1614}
1615
1616
1617
1618/*
1619 * Edit price area
1620 */
1621
1622if ($action == 'edit_vat' && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
1623 print load_fiche_titre($langs->trans("UpdateVAT"), '');
1624
1625 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1626 print '<input type="hidden" name="token" value="'.newToken().'">';
1627 print '<input type="hidden" name="action" value="update_vat">';
1628 print '<input type="hidden" name="id" value="'.$object->id.'">';
1629
1630 print dol_get_fiche_head();
1631
1632 print '<table class="border centpercent">';
1633
1634 // VAT
1635 print '<tr><td>'.$langs->trans("DefaultTaxRate").'</td><td>';
1636 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);
1637 print '</td></tr>';
1638
1639 print '</table>';
1640
1641 print dol_get_fiche_end();
1642
1643 print $form->buttonsSaveCancel();
1644
1645 print '<br></form><br>';
1646}
1647
1648if (($action == 'edit_price' || $action == 'edit_level_price') && $object->getRights()->creer) {
1649 print '<br>';
1650 print load_fiche_titre($langs->trans("NewPrice"), '');
1651
1652 if (!getDolGlobalString('PRODUIT_MULTIPRICES') && $action != 'edit_level_price') {
1653 print '<!-- Edit price -->'."\n";
1654 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1655 print '<input type="hidden" name="token" value="'.newToken().'">';
1656 print '<input type="hidden" name="action" value="update_price">';
1657 print '<input type="hidden" name="id" value="'.$object->id.'">';
1658
1659 print dol_get_fiche_head();
1660
1661 print '<div class="div-table-responsive-no-min">';
1662 print '<table class="border centpercent">';
1663
1664 // VAT
1665 print '<tr><td class="titlefield">'.$langs->trans("DefaultTaxRate").'</td><td>';
1666 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);
1667 print '</td></tr>';
1668
1669 // Price base
1670 print '<tr><td>';
1671 print $langs->trans('PriceBase');
1672 print '</td>';
1673 print '<td>';
1674 print $form->selectPriceBaseType($object->price_base_type, "price_base_type");
1675 print '</td>';
1676 print '</tr>';
1677
1678 // Only show price mode and expression selector if module is enabled
1679 if (isModEnabled('dynamicprices')) {
1680 // Price mode selector
1681 print '<!-- Show price mode of dynamicprices editor -->'."\n";
1682 print '<tr><td>'.$langs->trans("PriceMode").'</td><td>';
1683 print img_picto('', 'dynamicprice', 'class="pictofixedwidth"');
1684 $price_expression = new PriceExpression($db);
1685 $price_expression_list = array(0 => $langs->trans("Numeric").' <span class="opacitymedium">('.$langs->trans("NoDynamicPrice").')</span>'); //Put the numeric mode as first option
1686 foreach ($price_expression->list_price_expression() as $entry) {
1687 $price_expression_list[$entry->id] = $entry->title;
1688 }
1689 $price_expression_preselection = GETPOST('eid') ? GETPOST('eid') : ($object->fk_price_expression ? $object->fk_price_expression : '0');
1690 print $form->selectarray('eid', $price_expression_list, $price_expression_preselection);
1691 print '&nbsp; <a id="expression_editor" class="classlink">'.$langs->trans("PriceExpressionEditor").'</a>';
1692 print '</td></tr>';
1693
1694 // This code hides the numeric price input if is not selected, loads the editor page if editor button is pressed
1695 ?>
1696
1697 <script type="text/javascript">
1698 jQuery(document).ready(function() {
1699 jQuery("#expression_editor").click(function() {
1700 window.location = "<?php echo DOL_URL_ROOT ?>/product/dynamic_price/editor.php?id=<?php echo $id ?>&tab=price&eid=" + $("#eid").val();
1701 });
1702 jQuery("#eid").change(on_change);
1703 on_change();
1704 });
1705 function on_change() {
1706 if ($("#eid").val() == 0) {
1707 jQuery("#price_numeric").show();
1708 } else {
1709 jQuery("#price_numeric").hide();
1710 }
1711 }
1712 </script>
1713 <?php
1714 }
1715
1716 // Price
1717 $product = new Product($db);
1718 $product->fetch($id, $ref, '', 1); //Ignore the math expression when getting the price
1719 print '<tr id="price_numeric"><td>';
1720 $text = $langs->trans('SellingPrice');
1721 print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", getDolGlobalString('MAIN_MAX_DECIMALS_UNIT')), 1, 1);
1722 print '</td><td>';
1723 if ($object->price_base_type == 'TTC') {
1724 print '<input name="price" size="10" value="'.price($product->price_ttc).'">';
1725 } else {
1726 print '<input name="price" size="10" value="'.price($product->price).'">';
1727 }
1728 print '</td></tr>';
1729
1730 // Price minimum
1731 print '<tr><td>';
1732 $text = $langs->trans('MinPrice');
1733 print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", getDolGlobalString('MAIN_MAX_DECIMALS_UNIT')), 1, 1);
1734 print '</td><td>';
1735 if ($object->price_base_type == 'TTC') {
1736 print '<input name="price_min" size="10" value="'.price($object->price_min_ttc).'">';
1737 } else {
1738 print '<input name="price_min" size="10" value="'.price($object->price_min).'">';
1739 }
1740 if (getDolGlobalString('PRODUCT_MINIMUM_RECOMMENDED_PRICE')) {
1741 print ' &nbsp; '.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().'</td>';
1742 }
1743 print '</td>';
1744 print '</tr>';
1745
1746 // Price Label
1747 print '<tr><td>';
1748 print $langs->trans('PriceLabel');
1749 print '</td><td>';
1750 print '<input name="price_label" maxlength="255" class="minwidth300 maxwidth400onsmartphone" value="'.$object->price_label.'">';
1751 print '</td>';
1752 print '</tr>';
1753
1754 // Extrafields
1755 $extrafields->fetch_name_optionals_label("product");
1756 $extralabels = !empty($extrafields->attributes["product"]['label']) ? $extrafields->attributes["product"]['label'] : '';
1757 $extrafield_values = $extrafields->getOptionalsFromPost("product");
1758 if (!empty($extralabels)) {
1759 if (empty($object->id)) {
1760 foreach ($extralabels as $key => $value) {
1761 if (!empty($extrafields->attributes["product"]['list'][$key]) && ($extrafields->attributes["product"]['list'][$key] == 1 || $extrafields->attributes["product"]['list'][$key] == 3 || ($action == "edit_price" && $extrafields->attributes["product"]['list'][$key] == 4))) {
1762 if (!empty($extrafields->attributes["product"]['langfile'][$key])) {
1763 $langs->load($extrafields->attributes["product"]['langfile'][$key]);
1764 }
1765
1766 print '<tr><td'.($extrafields->attributes["product"]['required'][$key] ? ' class="fieldrequired"' : '').'>';
1767 if (!empty($extrafields->attributes["product"]['help'][$key])) {
1768 print $form->textwithpicto($langs->trans($value), $langs->trans($extrafields->attributes["product"]['help'][$key]));
1769 } else {
1770 print $langs->trans($value);
1771 }
1772 print '</td><td>'.$extrafields->showInputField($key, GETPOSTISSET('options_'.$key) ? $extrafield_values['options_'.$key] : '', '', '', '', '', 0, 'product').'</td></tr>';
1773 }
1774 }
1775 } else {
1776 $sql = "SELECT";
1777 $sql .= " fk_object";
1778 foreach ($extralabels as $key => $value) {
1779 $sql .= ", ".$key;
1780 }
1781 $sql .= " FROM ".MAIN_DB_PREFIX."product_extrafields";
1782 $sql .= " WHERE fk_object = ".((int) $object->id);
1783 $resql = $db->query($sql);
1784 if ($resql) {
1785 $obj = $db->fetch_object($resql);
1786 foreach ($extralabels as $key => $value) {
1787 if (!empty($extrafields->attributes["product"]['list'][$key]) && ($extrafields->attributes["product"]['list'][$key] == 1 || $extrafields->attributes["product"]['list'][$key] == 3 || ($action == "edit_price" && $extrafields->attributes["product"]['list'][$key] == 4))) {
1788 if (!empty($extrafields->attributes["product"]['langfile'][$key])) {
1789 $langs->load($extrafields->attributes["product"]['langfile'][$key]);
1790 }
1791
1792 print '<tr><td'.($extrafields->attributes["product"]['required'][$key] ? ' class="fieldrequired"' : '').'>';
1793 if (!empty($extrafields->attributes["product"]['help'][$key])) {
1794 print $form->textwithpicto($langs->trans($value), $langs->trans($extrafields->attributes["product"]['help'][$key]));
1795 } else {
1796 print $langs->trans($value);
1797 }
1798 print '</td><td>'.$extrafields->showInputField($key, GETPOSTISSET('options_'.$key) ? $extrafield_values['options_'.$key] : $obj->{$key}, '', '', '', '', 0, 'product');
1799
1800 print '</td></tr>';
1801 }
1802 }
1803 $db->free($resql);
1804 }
1805 }
1806 }
1807 $parameters = array();
1808 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1809
1810 print '</table>';
1811 print '</div>';
1812
1813 print dol_get_fiche_end();
1814
1815 print $form->buttonsSaveCancel();
1816
1817 print '</form>';
1818 } elseif ($action == 'edit_level_price' && $object->getRights()->creer) {
1819 print '<!-- Edit price per level -->'."\n"; ?>
1820 <script>
1821
1822 var showHidePriceRules = function () {
1823 var otherPrices = $('div.fiche form table tbody tr:not(:first)');
1824 var minPrice1 = $('div.fiche form input[name="price_min[1]"]');
1825
1826 if (jQuery('input#usePriceRules').prop('checked')) {
1827 otherPrices.hide();
1828 minPrice1.hide();
1829 } else {
1830 otherPrices.show();
1831 minPrice1.show();
1832 }
1833 }
1834
1835 jQuery(document).ready(function () {
1836 showHidePriceRules();
1837
1838 jQuery('input#usePriceRules').click(showHidePriceRules);
1839 });
1840 </script>
1841 <?php
1842
1843 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
1844 print '<input type="hidden" name="token" value="'.newToken().'">';
1845 print '<input type="hidden" name="action" value="update_level_price">';
1846 print '<input type="hidden" name="id" value="'.$object->id.'">';
1847
1848 //print dol_get_fiche_head(array(), '', '', -1);
1849
1850 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && getDolGlobalString('PRODUIT_MULTIPRICES_ALLOW_AUTOCALC_PRICELEVEL')) {
1851 print $langs->trans('UseMultipriceRules').' <input type="checkbox" id="usePriceRules" name="usePriceRules" '.($object->price_autogen ? 'checked' : '').'><br><br>';
1852 }
1853
1854 print '<div class="div-table-responsive-no-min">';
1855 print '<table class="noborder">';
1856 print '<thead><tr class="liste_titre">';
1857
1858 print '<td>'.$langs->trans("PriceLevel").'</td>';
1859
1860 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) {
1861 print '<td style="text-align: center">'.$langs->trans("DefaultTaxRate").'</td>';
1862 } else {
1863 print '<td></td>';
1864 }
1865
1866 print '<td class="center">'.$langs->trans("SellingPrice").'</td>';
1867
1868 print '<td class="center">'.$langs->trans("MinPrice").'</td>';
1869
1870 if (getDolGlobalString('PRODUCT_MINIMUM_RECOMMENDED_PRICE')) {
1871 print '<td></td>';
1872 }
1873
1874 // fetch optionals attributes and labels
1875 $extrafields->fetch_name_optionals_label("product_price");
1876 if ($extrafields->attributes["product_price"] && array_key_exists('label', $extrafields->attributes["product_price"])) {
1877 $extralabels = $extrafields->attributes["product_price"]['label'];
1878 if (!empty($extralabels)) {
1879 foreach ($extralabels as $key => $value) {
1880 // Show field if not hidden
1881 if (!empty($extrafields->attributes["product_price"]['list'][$key]) && $extrafields->attributes["product_price"]['list'][$key] != 3) {
1882 if (!empty($extrafields->attributes["product_price"]['langfile'][$key])) {
1883 $langs->load($extrafields->attributes["product_price"]['langfile'][$key]);
1884 }
1885 if (!empty($extrafields->attributes["product_price"]['help'][$key])) {
1886 $extratitle = $form->textwithpicto($langs->trans($value), $langs->trans($extrafields->attributes["product_price"]['help'][$key]));
1887 } else {
1888 $extratitle = $langs->trans($value);
1889 }
1890 print '<td style="text-align: right">'.$extratitle.'</td>';
1891 }
1892 }
1893 }
1894 }
1895 print '</tr></thead>';
1896
1897 print '<tbody>';
1898
1899 $produit_multiprices_limit = getDolGlobalInt('PRODUIT_MULTIPRICES_LIMIT');
1900 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
1901 print '<tr class="oddeven">';
1902 print '<td>';
1903 $keyforlabel = 'PRODUIT_MULTIPRICES_LABEL'.$i;
1904 $text = $langs->trans('SellingPrice').' '.$i.' - '.getDolGlobalString($keyforlabel);
1905 print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", getDolGlobalString('MAIN_MAX_DECIMALS_UNIT')), 1, 1);
1906 print '</td>';
1907
1908 // VAT
1909 if (!getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) {
1910 print '<td>';
1911 print '<input type="hidden" name="tva_tx['.$i.']" value="'.($object->default_vat_code ? $object->tva_tx.' ('.$object->default_vat_code.')' : $object->tva_tx).'">';
1912 print '<input type="hidden" name="tva_npr['.$i.']" value="'.$object->tva_npr.'">';
1913 print '<input type="hidden" name="localtax1_tx['.$i.']" value="'.$object->localtax1_tx.'">';
1914 print '<input type="hidden" name="localtax1_type['.$i.']" value="'.$object->localtax1_type.'">';
1915 print '<input type="hidden" name="localtax2_tx['.$i.']" value="'.$object->localtax2_tx.'">';
1916 print '<input type="hidden" name="localtax2_type['.$i.']" value="'.$object->localtax2_type.'">';
1917 print '</td>';
1918 } else {
1919 // This option is kept for backward compatibility but has no sense
1920 print '<td style="text-align: center">';
1921 print $form->load_tva("tva_tx[".$i.']', $object->multiprices_tva_tx[$i], $mysoc, '', $object->id, false, $object->type, false, 1);
1922 print '</td>';
1923 }
1924
1925 // Selling price
1926 print '<td style="text-align: center">';
1927 if ($object->multiprices_base_type [$i] == 'TTC') {
1928 print '<input name="price['.$i.']" size="10" value="'.price($object->multiprices_ttc [$i]).'">';
1929 } else {
1930 print '<input name="price['.$i.']" size="10" value="'.price($object->multiprices [$i]).'">';
1931 }
1932 print '&nbsp;'.$form->selectPriceBaseType($object->multiprices_base_type [$i], "multiprices_base_type[".$i."]");
1933 print '</td>';
1934
1935 // Min price
1936 print '<td style="text-align: center">';
1937 if ($object->multiprices_base_type [$i] == 'TTC') {
1938 print '<input name="price_min['.$i.']" size="10" value="'.price($object->multiprices_min_ttc [$i]).'">';
1939 } else {
1940 print '<input name="price_min['.$i.']" size="10" value="'.price($object->multiprices_min [$i]).'">';
1941 }
1942 if (getDolGlobalString('PRODUCT_MINIMUM_RECOMMENDED_PRICE')) {
1943 print '<td class="left">'.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().'</td>';
1944 }
1945 print '</td>';
1946
1947 if (!empty($extralabels)) {
1948 $sql1 = "SELECT rowid";
1949 $sql1 .= " FROM ".$object->db->prefix()."product_price";
1950 $sql1 .= " WHERE entity IN (".getEntity('productprice').")";
1951 $sql1 .= " AND price_level=".((int) $i);
1952 $sql1 .= " AND fk_product = ".((int) $object->id);
1953 $sql1 .= " ORDER BY date_price DESC, rowid DESC";
1954 $sql1 .= " LIMIT 1";
1955 $resql1 = $object->db->query($sql1);
1956 if ($resql1) {
1957 $lineid = $object->db->fetch_object($resql1);
1958 }
1959 if (empty($lineid->rowid)) {
1960 foreach ($extralabels as $key => $value) {
1961 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))) {
1962 if (!empty($extrafields->attributes["product_price"]['langfile'][$key])) {
1963 $langs->load($extrafields->attributes["product_price"]['langfile'][$key]);
1964 }
1965
1966 $extravalue = GETPOSTISSET('options_'.$key) ? $extrafield_values['options_'.$key] : $obj->{$key};
1967 print '<td align="center"><input name="'.$key.'['.$i.']" size="10" value="'.$extravalue.'"></td>';
1968 }
1969 }
1970 } else {
1971 $sql = "SELECT";
1972 $sql .= " fk_object";
1973 foreach ($extralabels as $key => $value) {
1974 $sql .= ", ".$key;
1975 }
1976 $sql .= " FROM ".MAIN_DB_PREFIX."product_price_extrafields";
1977 $sql .= " WHERE fk_object = ".((int) $lineid->rowid);
1978 $resql = $db->query($sql);
1979 if ($resql) {
1980 $obj = $db->fetch_object($resql);
1981 foreach ($extralabels as $key => $value) {
1982 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))) {
1983 if (!empty($extrafields->attributes["product_price"]['langfile'][$key])) {
1984 $langs->load($extrafields->attributes["product_price"]['langfile'][$key]);
1985 }
1986
1987 $extravalue = (GETPOSTISSET('options_'.$key) ? $extrafield_values['options_'.$key] : $obj->{$key} ?? '');
1988 print '<td align="center"><input name="'.$key.'['.$i.']" size="10" value="'.$extravalue.'"></td>';
1989 }
1990 }
1991 $db->free($resql);
1992 }
1993 }
1994 }
1995 print '</tr>';
1996 }
1997
1998 print '</tbody>';
1999
2000 print '</table>';
2001 print '</div>';
2002
2003 //print dol_get_fiche_end();
2004
2005 print $form->buttonsSaveCancel();
2006
2007 print '</form>';
2008 }
2009}
2010
2011// Add area to show/add/edit a price for a dedicated customer
2012if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
2013 $prodcustprice = new ProductCustomerPrice($db);
2014
2015 $limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
2016 $sortfield = GETPOST('sortfield', 'aZ09comma');
2017 $sortorder = GETPOST('sortorder', 'aZ09comma');
2018 $page = (GETPOSTINT("page") ? GETPOSTINT("page") : 0);
2019 if (empty($page) || $page == -1) {
2020 $page = 0;
2021 } // If $page is not defined, or '' or -1
2022 $offset = $limit * $page;
2023 $pageprev = $page - 1;
2024 $pagenext = $page + 1;
2025 if (!$sortorder) {
2026 $sortorder = "ASC";
2027 }
2028 if (!$sortfield) {
2029 $sortfield = "soc.nom";
2030 }
2031
2032 // Build filter to display only concerned lines
2033 $filter = array('t.fk_product' => $object->id);
2034
2035 if (!empty($search_soc)) {
2036 $filter['soc.nom'] = $search_soc;
2037 }
2038
2039 if ($action == 'add_customer_price') {
2040 // Form to add a new customer price
2041 $maxpricesupplier = $object->min_recommended_price();
2042
2043 print '<!-- add_customer_price -->';
2044 print load_fiche_titre($langs->trans('AddCustomerPrice'));
2045
2046 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
2047 print '<input type="hidden" name="token" value="'.newToken().'">';
2048 print '<input type="hidden" name="action" value="add_customer_price_confirm">';
2049 print '<input type="hidden" name="id" value="'.$object->id.'">';
2050
2051 print '<div class="tabBar tabBarWithBottom">';
2052
2053 print '<table class="border centpercent">';
2054 print '<tr>';
2055 print '<td class="fieldrequired">'.$langs->trans('ThirdParty').'</td>';
2056 print '<td>';
2057 $filter = '(s.client:IN:1,2,3)';
2058 print img_picto('', 'company').$form->select_company('', 'socid', $filter, 'SelectThirdParty', 0, 0, array(), 0, 'minwidth300');
2059 print '</td>';
2060 print '</tr>';
2061
2062 // Ref. Customer
2063 print '<tr><td>' . $langs->trans('RefCustomer') . '</td>';
2064 print '<td><input name="ref_customer" size="12"></td></tr>';
2065
2066 // VAT
2067 print '<tr><td class="fieldrequired">'.$langs->trans("DefaultTaxRate").'</td><td>';
2068 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);
2069 print '</td></tr>';
2070
2071 // Price base
2072 print '<tr><td class="fieldrequired">';
2073 print $langs->trans('PriceBase');
2074 print '</td>';
2075 print '<td>';
2076 print $form->selectPriceBaseType($object->price_base_type, "price_base_type");
2077 print '</td>';
2078 print '</tr>';
2079
2080 // Price
2081 print '<tr><td class="fieldrequired">';
2082 $text = $langs->trans('SellingPrice');
2083 print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", getDolGlobalString('MAIN_MAX_DECIMALS_UNIT')), 1, 1);
2084 print '</td><td>';
2085 if ($object->price_base_type == 'TTC') {
2086 print '<input name="price" size="10" value="'.price($object->price_ttc).'">';
2087 } else {
2088 print '<input name="price" size="10" value="'.price($object->price).'">';
2089 }
2090 print '</td></tr>';
2091
2092 // Price minimum
2093 print '<tr><td>';
2094 $text = $langs->trans('MinPrice');
2095 print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", getDolGlobalString('MAIN_MAX_DECIMALS_UNIT')), 1, 1);
2096 if ($object->price_base_type == 'TTC') {
2097 print '<td><input name="price_min" size="10" value="'.price($object->price_min_ttc).'">';
2098 } else {
2099 print '<td><input name="price_min" size="10" value="'.price($object->price_min).'">';
2100 }
2101 if (getDolGlobalString('PRODUCT_MINIMUM_RECOMMENDED_PRICE')) {
2102 print '<td class="left">'.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().'</td>';
2103 }
2104 print '</td></tr>';
2105
2106 // Price Label
2107 print '<tr><td>';
2108 print $langs->trans('PriceLabel');
2109 print '</td><td>';
2110 print '<input name="price_label" maxlength="255" class="minwidth300 maxwidth400onsmartphone" value="'.$object->price_label.'">';
2111 print '</td>';
2112 print '</tr>';
2113
2114 // Extrafields
2115 $extrafields->fetch_name_optionals_label("product_customer_price");
2116 $extralabels = !empty($extrafields->attributes["product_customer_price"]['label']) ? $extrafields->attributes["product_customer_price"]['label'] : '';
2117 $extrafield_values = $extrafields->getOptionalsFromPost("product_customer_price");
2118 if (!empty($extralabels)) {
2119 if (empty($prodcustprice->id)) {
2120 foreach ($extralabels as $key => $value) {
2121 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))) {
2122 if (!empty($extrafields->attributes["product_customer_price"]['langfile'][$key])) {
2123 $langs->load($extrafields->attributes["product_customer_price"]['langfile'][$key]);
2124 }
2125
2126 print '<tr><td'.($extrafields->attributes["product_customer_price"]['required'][$key] ? ' class="fieldrequired"' : '').'>';
2127 if (!empty($extrafields->attributes["product_customer_price"]['help'][$key])) {
2128 print $form->textwithpicto($langs->trans($value), $langs->trans($extrafields->attributes["product_customer_price"]['help'][$key]));
2129 } else {
2130 print $langs->trans($value);
2131 }
2132 print '</td><td>'.$extrafields->showInputField($key, GETPOSTISSET('options_'.$key) ? $extrafield_values['options_'.$key] : '', '', '', '', '', 0, 'product_customer_price').'</td></tr>';
2133 }
2134 }
2135 }
2136 }
2137
2138 print '</table>';
2139
2140 print '</div>';
2141
2142
2143 print '<div class="center">';
2144
2145 // Update all child soc
2146 print '<div class="marginbottomonly">';
2147 print '<input type="checkbox" name="updatechildprice" id="updatechildprice" value="1"> ';
2148 print '<label for="updatechildprice">'.$langs->trans('ForceUpdateChildPriceSoc').'</label>';
2149 print '</div>';
2150
2151 print $form->buttonsSaveCancel();
2152
2153 print '</form>';
2154 } elseif ($action == 'edit_customer_price') {
2155 // Edit mode
2156 $maxpricesupplier = $object->min_recommended_price();
2157
2158 print '<!-- edit_customer_price -->';
2159 print load_fiche_titre($langs->trans('PriceByCustomer'));
2160
2161 $result = $prodcustprice->fetch(GETPOSTINT('lineid'));
2162 if ($result < 0) {
2163 setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
2164 }
2165
2166 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
2167 print '<input type="hidden" name="token" value="'.newToken().'">';
2168 print '<input type="hidden" name="action" value="update_customer_price_confirm">';
2169 print '<input type="hidden" name="lineid" value="'.$prodcustprice->id.'">';
2170
2171 print '<table class="liste centpercent">';
2172 print '<tr>';
2173 print '<td class="titlefield fieldrequired">'.$langs->trans('ThirdParty').'</td>';
2174 $staticsoc = new Societe($db);
2175 $staticsoc->fetch($prodcustprice->fk_soc);
2176 print "<td>".$staticsoc->getNomUrl(1)."</td>";
2177 print '</tr>';
2178
2179 // Ref. Customer
2180 print '<tr><td>' . $langs->trans('RefCustomer') . '</td>';
2181 print '<td><input name="ref_customer" size="12" value="' . dol_escape_htmltag($prodcustprice->ref_customer) . '"></td></tr>';
2182
2183 // VAT
2184 print '<tr><td class="fieldrequired">'.$langs->trans("DefaultTaxRate").'</td><td>';
2185 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);
2186 print '</td></tr>';
2187
2188 // Price base
2189 print '<tr><td class="fieldrequired">';
2190 print $langs->trans('PriceBase');
2191 print '</td>';
2192 print '<td>';
2193 print $form->selectPriceBaseType($prodcustprice->price_base_type, "price_base_type");
2194 print '</td>';
2195 print '</tr>';
2196
2197 // Price
2198 print '<tr><td class="fieldrequired">';
2199 $text = $langs->trans('SellingPrice');
2200 print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", getDolGlobalString('MAIN_MAX_DECIMALS_UNIT')), 1, 1);
2201 print '</td><td>';
2202 if ($prodcustprice->price_base_type == 'TTC') {
2203 print '<input name="price" size="10" value="'.price($prodcustprice->price_ttc).'">';
2204 } else {
2205 print '<input name="price" size="10" value="'.price($prodcustprice->price).'">';
2206 }
2207 print '</td></tr>';
2208
2209 // Price minimum
2210 print '<tr><td>';
2211 $text = $langs->trans('MinPrice');
2212 print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", getDolGlobalString('MAIN_MAX_DECIMALS_UNIT')), 1, 1);
2213 print '</td><td>';
2214 if ($prodcustprice->price_base_type == 'TTC') {
2215 print '<input name="price_min" size="10" value="'.price($prodcustprice->price_min_ttc).'">';
2216 } else {
2217 print '<input name="price_min" size="10" value="'.price($prodcustprice->price_min).'">';
2218 }
2219 print '</td>';
2220 if (getDolGlobalString('PRODUCT_MINIMUM_RECOMMENDED_PRICE')) {
2221 print '<td class="left">'.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().'</td>';
2222 }
2223 print '</tr>';
2224
2225
2226
2227 // Price Label
2228 print '<tr><td>';
2229 print $langs->trans('PriceLabel');
2230 print '</td><td>';
2231 print '<input name="price_label" maxlength="255" class="minwidth300 maxwidth400onsmartphone" value="'.$prodcustprice->price_label.'">';
2232 print '</td>';
2233 print '</tr>';
2234
2235 // Extrafields
2236 $extrafields->fetch_name_optionals_label("product_customer_price");
2237 $extralabels = !empty($extrafields->attributes["product_customer_price"]['label']) ? $extrafields->attributes["product_customer_price"]['label'] : '';
2238 $extrafield_values = $extrafields->getOptionalsFromPost("product_customer_price");
2239 if (!empty($extralabels)) {
2240 if (empty($object->id)) {
2241 foreach ($extralabels as $key => $value) {
2242 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))) {
2243 if (!empty($extrafields->attributes["product_customer_price"]['langfile'][$key])) {
2244 $langs->load($extrafields->attributes["product_customer_price"]['langfile'][$key]);
2245 }
2246
2247 print '<tr><td'.($extrafields->attributes["product_customer_price"]['required'][$key] ? ' class="fieldrequired"' : '').'>';
2248 if (!empty($extrafields->attributes["product_customer_price"]['help'][$key])) {
2249 print $form->textwithpicto($langs->trans($value), $langs->trans($extrafields->attributes["product_customer_price"]['help'][$key]));
2250 } else {
2251 print $langs->trans($value);
2252 }
2253 print '</td><td>'.$extrafields->showInputField($key, GETPOSTISSET('options_'.$key) ? $extrafield_values['options_'.$key] : '', '', '', '', '', 0, 'product_customer_price').'</td></tr>';
2254 }
2255 }
2256 } else {
2257 $sql = "SELECT";
2258 $sql .= " fk_object";
2259 foreach ($extralabels as $key => $value) {
2260 $sql .= ", ".$key;
2261 }
2262 $sql .= " FROM ".MAIN_DB_PREFIX."product_customer_price_extrafields";
2263 $sql .= " WHERE fk_object = ".((int) $prodcustprice->id);
2264 $resql = $db->query($sql);
2265 if ($resql) {
2266 $obj = $db->fetch_object($resql);
2267 foreach ($extralabels as $key => $value) {
2268 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))) {
2269 if (!empty($extrafields->attributes["product_customer_price"]['langfile'][$key])) {
2270 $langs->load($extrafields->attributes["product_customer_price"]['langfile'][$key]);
2271 }
2272
2273 print '<tr><td'.($extrafields->attributes["product_customer_price"]['required'][$key] ? ' class="fieldrequired"' : '').'>';
2274 if (!empty($extrafields->attributes["product_customer_price"]['help'][$key])) {
2275 print $form->textwithpicto($langs->trans($value), $langs->trans($extrafields->attributes["product_customer_price"]['help'][$key]));
2276 } else {
2277 print $langs->trans($value);
2278 }
2279 print '</td><td>'.$extrafields->showInputField($key, GETPOSTISSET('options_'.$key) ? $extrafield_values['options_'.$key] : $obj->{$key}, '', '', '', '', 0, 'product_customer_price');
2280
2281 print '</td></tr>';
2282 }
2283 }
2284 $db->free($resql);
2285 }
2286 }
2287 }
2288
2289 print '</table>';
2290
2291 print '<div class="center">';
2292 print '<div class="marginbottomonly">';
2293 print '<input type="checkbox" name="updatechildprice" id="updatechildprice" value="1"> ';
2294 print '<label for="updatechildprice">'.$langs->trans('ForceUpdateChildPriceSoc').'</label>';
2295 print "</div>";
2296
2297 print $form->buttonsSaveCancel();
2298
2299 print '<br></form>';
2300 } elseif ($action == 'showlog_customer_price') {
2301 // List of all log of prices by customers
2302 print '<!-- list of all log of prices per customer -->'."\n";
2303
2304 $filter = array('t.fk_product' => $object->id, 't.fk_soc' => GETPOSTINT('socid'));
2305
2306 // Count total nb of records
2307 $nbtotalofrecords = '';
2308 if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
2309 $nbtotalofrecords = $prodcustprice->fetchAllLog($sortorder, $sortfield, $conf->liste_limit, $offset, $filter);
2310 }
2311
2312 $result = $prodcustprice->fetchAllLog($sortorder, $sortfield, $conf->liste_limit, $offset, $filter);
2313 if ($result < 0) {
2314 setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
2315 }
2316
2317 $option = '&socid='.GETPOSTINT('socid').'&id='.$object->id;
2318
2319 $staticsoc = new Societe($db);
2320 $staticsoc->fetch(GETPOSTINT('socid'));
2321
2322 $title = $langs->trans('PriceByCustomerLog');
2323 $title .= ' - '.$staticsoc->getNomUrl(1);
2324
2325 $backbutton = '<a class="justalink" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">'.$langs->trans("Back").'</a>';
2326
2327 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
2328 print_barre_liste($title, $page, $_SERVER['PHP_SELF'], $option, $sortfield, $sortorder, $backbutton, count($prodcustprice->lines), $nbtotalofrecords, 'title_accountancy.png');
2329
2330 if (count($prodcustprice->lines) > 0) {
2331 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
2332 print '<input type="hidden" name="token" value="'.newToken().'">';
2333 print '<input type="hidden" name="id" value="'.$object->id.'">';
2334
2335 print '<div class="div-table-responsive-no-min">';
2336 print '<table class="liste centpercent">';
2337
2338 print '<tr class="liste_titre">';
2339 print '<td>'.$langs->trans("ThirdParty").'</td>';
2340 print '<td>'.$langs->trans('RefCustomer').'</td>';
2341 print '<td>'.$langs->trans("AppliedPricesFrom").'</td>';
2342 print '<td class="center">'.$langs->trans("PriceBase").'</td>';
2343 print '<td class="right">'.$langs->trans("DefaultTaxRate").'</td>';
2344 print '<td class="right">'.$langs->trans("HT").'</td>';
2345 print '<td class="right">'.$langs->trans("TTC").'</td>';
2346 if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2347 print '<td class="right">'.$langs->trans("INCT").'</td>';
2348 }
2349 print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("HT").'</td>';
2350 print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("TTC").'</td>';
2351 print '<td class="right">'.$langs->trans("PriceLabel").'</td>';
2352 print '<td class="right">'.$langs->trans("ChangedBy").'</td>';
2353 print '<td>&nbsp;</td>';
2354 print '</tr>';
2355
2356 foreach ($prodcustprice->lines as $line) {
2357 // Date
2358 $staticsoc = new Societe($db);
2359 $staticsoc->fetch($line->fk_soc);
2360
2361 $tva_tx = $line->default_vat_code ? $line->tva_tx.' ('.$line->default_vat_code.')' : $line->tva_tx;
2362
2363 // Line for default price
2364 if ($line->price_base_type == 'HT') {
2365 $pu = $line->price;
2366 } else {
2367 $pu = $line->price_ttc;
2368 }
2369
2370 // Local tax is not saved into table of product. We use value linked to VAT code.
2371 $localtaxarray = getLocalTaxesFromRate($line->tva_tx.($line->default_vat_code ? ' ('.$line->default_vat_code.')' : ''), 0, $staticsoc, $mysoc);
2372 // Define part of HT, VAT, TTC
2373 $resultarray = calcul_price_total(1, $pu, 0, $line->tva_tx, 1, 1, 0, $line->price_base_type, $line->recuperableonly, $object->type, $mysoc, $localtaxarray);
2374 // Calcul du total ht sans remise
2375 $total_ht = $resultarray[0];
2376 $total_vat = $resultarray[1];
2377 $total_localtax1 = $resultarray[9];
2378 $total_localtax2 = $resultarray[10];
2379 $total_ttc = $resultarray[2];
2380
2381 print '<tr class="oddeven">';
2382
2383 print '<td class="tdoverflowmax125">'.$staticsoc->getNomUrl(1)."</td>";
2384 print '<td>'.$line->ref_customer.'</td>';
2385 print "<td>".dol_print_date($line->datec, "dayhour", 'tzuserrel')."</td>";
2386 print '<td class="center">'.$langs->trans($line->price_base_type)."</td>";
2387 print '<td class="right">';
2388
2389 $positiverates = '';
2390 if (price2num($line->tva_tx)) {
2391 $positiverates .= ($positiverates ? '/' : '').price2num($line->tva_tx);
2392 }
2393 if (price2num($line->localtax1_type)) {
2394 $positiverates .= ($positiverates ? '/' : '').price2num($line->localtax1_tx);
2395 }
2396 if (price2num($line->localtax2_type)) {
2397 $positiverates .= ($positiverates ? '/' : '').price2num($line->localtax2_tx);
2398 }
2399 if (empty($positiverates)) {
2400 $positiverates = '0';
2401 }
2402
2403 echo vatrate($positiverates.($line->default_vat_code ? ' ('.$line->default_vat_code.')' : ''), true, ($line->tva_npr ? $line->tva_npr : $line->recuperableonly));
2404
2405 //. vatrate($tva_tx, true, $line->recuperableonly) .
2406 print "</td>";
2407 print '<td class="right"><span class="amount">'.price($line->price)."</span></td>";
2408
2409 print '<td class="right"><span class="amount">'.price($line->price_ttc)."</span></td>";
2410 if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2411 print '<td class="right">'.price($resultarray[2]).'</td>';
2412 }
2413
2414 print '<td class="right">'.price($line->price_min).'</td>';
2415 print '<td class="right">'.price($line->price_min_ttc).'</td>';
2416 print '<td class="right">'.$line->price_label.'</td>';
2417
2418 // User
2419 $userstatic = new User($db);
2420 $userstatic->fetch($line->fk_user);
2421 print '<td class="right">';
2422 print $userstatic->getNomUrl(1, '', 0, 0, 24, 0, 'login');
2423 //print $userstatic->getLoginUrl(1);
2424 print '</td>';
2425 print '</tr>';
2426 }
2427 print "</table>";
2428 print '</div>';
2429 } else {
2430 print $langs->trans('None');
2431 }
2432 } elseif ($action != 'showlog_default_price' && $action != 'edit_price' && $action != 'edit_level_price') {
2433 // List of all prices by customers
2434 print '<!-- list of all prices per customer -->'."\n";
2435
2436 // Count total nb of records
2437 $nbtotalofrecords = '';
2438 if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
2439 $nbtotalofrecords = $prodcustprice->fetchAll($sortorder, $sortfield, 0, 0, $filter);
2440 }
2441
2442 $result = $prodcustprice->fetchAll($sortorder, $sortfield, $conf->liste_limit, $offset, $filter);
2443 if ($result < 0) {
2444 setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
2445 }
2446
2447 $option = '&search_soc='.$search_soc.'&id='.$object->id;
2448
2449 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
2450 print_barre_liste($langs->trans('PriceByCustomer'), $page, $_SERVER ['PHP_SELF'], $option, $sortfield, $sortorder, '', count($prodcustprice->lines), $nbtotalofrecords, 'title_accountancy.png');
2451
2452 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
2453 print '<input type="hidden" name="token" value="'.newToken().'">';
2454 print '<input type="hidden" name="id" value="'.$object->id.'">';
2455
2456 print '<!-- List of prices per customer -->'."\n";
2457 print '<div class="div-table-responsive-no-min">'."\n";
2458 print '<table class="liste centpercent">'."\n";
2459
2460 if (count($prodcustprice->lines) > 0 || $search_soc) {
2461 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
2462 $colspan = 10;
2463 } else {
2464 $colspan = 11;
2465 }
2466 if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2467 $colspan++;
2468 }
2469 if (!empty($price_extralabels) && is_array($price_extralabels)) {
2470 $colspan += count($price_extralabels);
2471 }
2472
2473 print '<tr class="liste_titre">';
2474 print '<td class="liste_titre"><input type="text" class="flat maxwidth125" name="search_soc" value="'.$search_soc.'"></td>';
2475 print '<td class="liste_titre" colspan="'.$colspan.'">&nbsp;</td>';
2476 // Print the search button
2477 print '<td class="liste_titre maxwidthsearch">';
2478 $searchpicto = $form->showFilterAndCheckAddButtons(0);
2479 print $searchpicto;
2480 print '</td>';
2481 print '</tr>';
2482 }
2483
2484 print '<tr class="liste_titre">';
2485 print '<td>'.$langs->trans("ThirdParty").'</td>';
2486 print '<td>'.$langs->trans('RefCustomer').'</td>';
2487 print '<td>'.$langs->trans("AppliedPricesFrom").'</td>';
2488 print '<td class="center">'.$langs->trans("PriceBase").'</td>';
2489 print '<td class="right">'.$langs->trans("DefaultTaxRate").'</td>';
2490 print '<td class="right">'.$langs->trans("HT").'</td>';
2491 print '<td class="right">'.$langs->trans("TTC").'</td>';
2492 if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2493 print '<td class="right">'.$langs->trans("INCT").'</td>';
2494 }
2495 print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("HT").'</td>';
2496 print '<td class="right">'.$langs->trans("MinPrice").' '.$langs->trans("TTC").'</td>';
2497 print '<td class="right">'.$langs->trans("PriceLabel").'</td>';
2498 // fetch optionals attributes and labels
2499 $extrafields->fetch_name_optionals_label("product_customer_price");
2500 if ($extrafields->attributes["product_customer_price"] && array_key_exists('label', $extrafields->attributes["product_customer_price"])) {
2501 $extralabels = $extrafields->attributes["product_customer_price"]['label'];
2502 if (!empty($extralabels)) {
2503 foreach ($extralabels as $key => $value) {
2504 // Show field if not hidden
2505 if (!empty($extrafields->attributes["product_customer_price"]['list'][$key]) && $extrafields->attributes["product_customer_price"]['list'][$key] != 3) {
2506 if (!empty($extrafields->attributes["product_customer_price"]['langfile'][$key])) {
2507 $langs->load($extrafields->attributes["product_customer_price"]['langfile'][$key]);
2508 }
2509 if (!empty($extrafields->attributes["product_customer_price"]['help'][$key])) {
2510 $extratitle = $form->textwithpicto($langs->trans($value), $langs->trans($extrafields->attributes["product_customer_price"]['help'][$key]));
2511 } else {
2512 $extratitle = $langs->trans($value);
2513 }
2514 print '<td style="text-align: right">'.$extratitle.'</td>';
2515 }
2516 }
2517 }
2518 }
2519 print '<td>'.$langs->trans("ChangedBy").'</td>';
2520 print '<td></td>';
2521 print '</tr>';
2522
2523 // Line for default price
2524 if ($object->price_base_type == 'HT') {
2525 $pu = $object->price;
2526 } else {
2527 $pu = $object->price_ttc;
2528 }
2529
2530 // Local tax was not saved into table llx_product on old versions. So we will use the value linked to the VAT code.
2531 $localtaxarray = getLocalTaxesFromRate($object->tva_tx.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), 0, $mysoc, $mysoc);
2532 // Define part of HT, VAT, TTC
2533 $resultarray = calcul_price_total(1, $pu, 0, $object->tva_tx, 1, 1, 0, $object->price_base_type, 0, $object->type, $mysoc, $localtaxarray);
2534 // Calcul du total ht sans remise
2535 $total_ht = $resultarray[0];
2536 $total_vat = $resultarray[1];
2537 $total_localtax1 = $resultarray[9];
2538 $total_localtax2 = $resultarray[10];
2539 $total_ttc = $resultarray[2];
2540
2541 if (!getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
2542 print '<!-- PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES -->'."\n";
2543 print '<tr class="oddeven">';
2544 print '<td colspan="3">' . $langs->trans('Default') . '</td>';
2545
2546 print '<td class="center">'.$langs->trans($object->price_base_type)."</td>";
2547
2548 // VAT Rate
2549 print '<td class="right">';
2550
2551 $positiverates = '';
2552 if (price2num($object->tva_tx)) {
2553 $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx);
2554 }
2555 if (price2num($object->localtax1_type)) {
2556 $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx);
2557 }
2558 if (price2num($object->localtax2_type)) {
2559 $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx);
2560 }
2561 if (empty($positiverates)) {
2562 $positiverates = '0';
2563 }
2564 echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), true, $object->tva_npr);
2565
2566 //print vatrate($object->tva_tx, true, $object->tva_npr);
2567 //print $object->default_vat_code?' ('.$object->default_vat_code.')':'';
2568 print "</td>";
2569
2570 print '<td class="right"><span class="amount">'.price($object->price)."</span></td>";
2571
2572 print '<td class="right"><span class="amount">'.price($object->price_ttc)."</span></td>";
2573 if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2574 //print '<td class="right">' . price($object->price_ttc) . "</td>";
2575 print '<td class="right"><span class="amount">'.price($resultarray[2]).'</span></td>';
2576 }
2577
2578 print '<td class="right">'.price($object->price_min).'</td>';
2579 print '<td class="right">'.price($object->price_min_ttc).'</td>';
2580 print '<td class="right">'.$object->price_label.'</td>';
2581 print '<td class="right"></td>';
2582 if (!empty($extralabels)) {
2583 foreach ($extralabels as $key) {
2584 // Show field if not hidden
2585 if (!empty($extrafields->attributes["product_customer_price"]['list'][$key]) && $extrafields->attributes["product_customer_price"]['list'][$key] != 3) {
2586 print '<td class="right"></td>';
2587 }
2588 }
2589 }
2590 if ($user->hasRight('produit', 'supprimer') || $user->hasRight('service', 'supprimer')) {
2591 print '<td class="nowraponall">';
2592 print '<a class="marginleftonly marginrightonly" href="'.$_SERVER["PHP_SELF"].'?action=showlog_default_price&token='.newToken().'&id='.$object->id.'">';
2593 print img_info($langs->trans('PriceByCustomerLog'));
2594 print '</a>';
2595 print ' ';
2596 print '<a class="marginleftonly marginrightonly editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit_price&token='.newToken().'&id='.$object->id.'">';
2597 print img_edit('default', 0, 'style="vertical-align: middle;"');
2598 print '</a>';
2599 print '</td>';
2600 }
2601 print "</tr>\n";
2602 }
2603
2604 if (count($prodcustprice->lines) > 0) {
2605 foreach ($prodcustprice->lines as $line) {
2606 // Date
2607 $staticsoc = new Societe($db);
2608 $staticsoc->fetch($line->fk_soc);
2609
2610 $tva_tx = $line->default_vat_code ? $line->tva_tx.' ('.$line->default_vat_code.')' : $line->tva_tx;
2611
2612 // Line for default price
2613 if ($line->price_base_type == 'HT') {
2614 $pu = $line->price;
2615 } else {
2616 $pu = $line->price_ttc;
2617 }
2618
2619 // Local tax is not saved into table of product. We use value linked to VAT code.
2620 $localtaxarray = getLocalTaxesFromRate($line->tva_tx.($line->default_vat_code ? ' ('.$line->default_vat_code.')' : ''), 0, $staticsoc, $mysoc);
2621 // Define part of HT, VAT, TTC
2622 $resultarray = calcul_price_total(1, $pu, 0, $line->tva_tx, 1, 1, 0, $line->price_base_type, $line->recuperableonly, $object->type, $mysoc, $localtaxarray);
2623 // Calcul du total ht sans remise
2624 $total_ht = $resultarray[0];
2625 $total_vat = $resultarray[1];
2626 $total_localtax1 = $resultarray[9];
2627 $total_localtax2 = $resultarray[10];
2628 $total_ttc = $resultarray[2];
2629
2630 print '<tr class="oddeven">';
2631
2632 print '<td class="tdoverflowmax125">'.$staticsoc->getNomUrl(1)."</td>";
2633 print '<td>'.dol_escape_htmltag($line->ref_customer).'</td>';
2634 print "<td>".dol_print_date($line->datec, "dayhour", 'tzuserrel')."</td>";
2635 print '<td class="center">'.$langs->trans($line->price_base_type)."</td>";
2636 // VAT Rate
2637 print '<td class="right">';
2638
2639 $positiverates = '';
2640 if (price2num($line->tva_tx)) {
2641 $positiverates .= ($positiverates ? '/' : '').price2num($line->tva_tx);
2642 }
2643 if (price2num($line->localtax1_type)) {
2644 $positiverates .= ($positiverates ? '/' : '').price2num($line->localtax1_tx);
2645 }
2646 if (price2num($line->localtax2_type)) {
2647 $positiverates .= ($positiverates ? '/' : '').price2num($line->localtax2_tx);
2648 }
2649 if (empty($positiverates)) {
2650 $positiverates = '0';
2651 }
2652
2653 echo vatrate($positiverates.($line->default_vat_code ? ' ('.$line->default_vat_code.')' : ''), true, (!empty($line->tva_npr) ? $line->tva_npr : $line->recuperableonly));
2654
2655 print "</td>";
2656
2657 print '<td class="right"><span class="amount">'.price($line->price)."</span></td>";
2658
2659 print '<td class="right"><span class="amount">'.price($line->price_ttc)."</span></td>";
2660 if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2661 //print '<td class="right">' . price($line->price_ttc) . "</td>";
2662 print '<td class="right"><span class="amount">'.price($resultarray[2]).'</span></td>';
2663 }
2664
2665 print '<td class="right">'.price($line->price_min).'</td>';
2666 print '<td class="right">'.price($line->price_min_ttc).'</td>';
2667 print '<td class="right">'.$line->price_label.'</td>';
2668
2669 // Extrafields
2670 $extrafields->fetch_name_optionals_label("product_customer_price");
2671 $extralabels = $extrafields->attributes["product_customer_price"]['label'] ?? array();
2672 if (!empty($extralabels)) {
2673 $sql = "SELECT";
2674 $sql .= " fk_object";
2675 foreach ($extralabels as $key => $value) {
2676 $sql .= ", ".$key;
2677 }
2678 $sql .= " FROM ".MAIN_DB_PREFIX."product_customer_price_extrafields";
2679 $sql .= " WHERE fk_object = ".((int) $line->id);
2680 $resql = $db->query($sql);
2681 if ($resql) {
2682 if ($db->num_rows($resql) != 1) {
2683 foreach ($extralabels as $key => $value) {
2684 if (!empty($extrafields->attributes["product_customer_price"]['list'][$key]) && $extrafields->attributes["product_customer_price"]['list'][$key] != 3) {
2685 print "<td></td>";
2686 }
2687 }
2688 } else {
2689 $obj = $db->fetch_object($resql);
2690 foreach ($extralabels as $key => $value) {
2691 if (!empty($extrafields->attributes["product_customer_price"]['list'][$key]) && $extrafields->attributes["product_customer_price"]['list'][$key] != 3) {
2692 print '<td align="right">'.$extrafields->showOutputField($key, $obj->{$key}, '', 'product_customer_price')."</td>";
2693 }
2694 }
2695 }
2696 $db->free($resql);
2697 }
2698 }
2699
2700 // User
2701 $userstatic = new User($db);
2702 $userstatic->fetch($line->fk_user);
2703 // @TODO Add a cache on $users object
2704 print '<td>';
2705 print $userstatic->getNomUrl(-1, '', 0, 0, 24, 0, 'login');
2706 print '</td>';
2707
2708 // Todo Edit or delete button
2709 // Action
2710 if ($user->hasRight('produit', 'supprimer') || $user->hasRight('service', 'supprimer')) {
2711 print '<td class="right nowraponall">';
2712 print '<a href="'.$_SERVER["PHP_SELF"].'?action=showlog_customer_price&token='.newToken().'&id='.$object->id.'&socid='.$line->fk_soc.'">';
2713 print img_info($langs->trans('PriceByCustomerLog'));
2714 print '</a>';
2715 print ' ';
2716 print '<a class="marginleftonly editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit_customer_price&token='.newToken().'&id='.$object->id.'&lineid='.$line->id.'">';
2717 print img_edit('default', 0, 'style="vertical-align: middle;"');
2718 print '</a>';
2719 print ' ';
2720 print '<a class="marginleftonly" href="'.$_SERVER["PHP_SELF"].'?action=delete_customer_price&token='.newToken().'&id='.$object->id.'&lineid='.$line->id.'">';
2721 print img_delete('default', 'style="vertical-align: middle;"');
2722 print '</a>';
2723 print '</td>';
2724 }
2725
2726 print "</tr>\n";
2727 }
2728 }
2729
2730 print "</table>";
2731 print '</div>';
2732
2733 print "</form>";
2734 }
2735}
2736
2737// List of price changes - log historic (ordered by descending date)
2738
2739if ((!getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || $action == 'showlog_default_price') && !in_array($action, array('edit_price', 'edit_level_price', 'edit_vat'))) {
2740 $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,";
2741 $sql .= " p.price_level, p.price_min, p.price_min_ttc,p.price_by_qty,";
2742 $sql .= " p.date_price as dp, p.fk_price_expression, u.rowid as user_id, u.login";
2743 $sql .= " ,p.price_label";
2744 $sql .= " FROM ".MAIN_DB_PREFIX."product_price as p,";
2745 $sql .= " ".MAIN_DB_PREFIX."user as u";
2746 $sql .= " WHERE fk_product = ".((int) $object->id);
2747 $sql .= " AND p.entity IN (".getEntity('productprice').")";
2748 $sql .= " AND p.fk_user_author = u.rowid";
2749 if (!empty($socid) && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && $soc !== null) {
2750 $sql .= " AND p.price_level = ".((int) $soc->price_level);
2751 }
2752 $sql .= " ORDER BY p.date_price DESC, p.rowid DESC, p.price_level ASC";
2753 // $sql .= $db->plimit();
2754 //print $sql;
2755
2756 $result = $db->query($sql);
2757 if ($result) {
2758 print '<div class="divlogofpreviouscustomerprice">';
2759
2760 $num = $db->num_rows($result);
2761
2762 if (!$num) {
2763 $db->free($result);
2764
2765 // Il doit au moins y avoir la ligne de prix initial.
2766 // On l'ajoute donc pour remettre a niveau (pb vieilles versions)
2767 // We emulate the change of the price from interface with the same value than the one into table llx_product
2768 if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
2769 $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);
2770 } else {
2771 $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));
2772 }
2773
2774 if ($ret < 0) {
2775 dol_print_error($db, $object->error, $object->errors);
2776 } else {
2777 $result = $db->query($sql);
2778 $num = $db->num_rows($result);
2779 }
2780 }
2781
2782 if ($num > 0) {
2783 // Default prices or
2784 // Log of previous customer prices
2785 $backbutton = '<a class="justalink" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">'.$langs->trans("Back").'</a>';
2786
2787 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
2788 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition, PhanPluginSuspiciousParamOrder
2789 print_barre_liste($langs->trans("DefaultPriceLog"), 0, $_SERVER["PHP_SELF"], '', '', '', $backbutton, 0, $num, 'title_accountancy.png');
2790 } else {
2791 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition, PhanPluginSuspiciousParamOrder
2792 print_barre_liste($langs->trans("PriceByCustomerLog"), 0, $_SERVER["PHP_SELF"], '', '', '', '', 0, $num, 'title_accountancy.png');
2793 }
2794
2795 print '<!-- List of log prices -->'."\n";
2796 print '<div class="div-table-responsive">'."\n";
2797 print '<table class="liste centpercent noborder">'."\n";
2798
2799 print '<tr class="liste_titre">';
2800 print '<th>'.$langs->trans("AppliedPricesFrom").'</tg>';
2801
2802 if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
2803 print '<th class="center">'.$langs->trans("PriceLevel").'</th>';
2804 }
2805 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2806 print '<th class="center">'.$langs->trans("Type").'</th>';
2807 }
2808
2809 print '<th class="center">'.$langs->trans("PriceBase").'</th>';
2810 if (!getDolGlobalString('PRODUIT_MULTIPRICES') && !getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2811 print '<th class="right">'.$langs->trans("DefaultTaxRate").'</th>';
2812 }
2813 print '<th class="right">'.$langs->trans("HT").'</th>';
2814 print '<th class="right">'.$langs->trans("TTC").'</th>';
2815 if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2816 print '<th class="right">'.$langs->trans("INCT").'</th>';
2817 }
2818 if (isModEnabled('dynamicprices')) {
2819 print '<th class="right">'.$langs->trans("PriceExpressionSelected").'</th>';
2820 }
2821 print '<th class="right">'.$langs->trans("MinPrice").' '.$langs->trans("HT").'</th>';
2822 print '<th class="right">'.$langs->trans("MinPrice").' '.$langs->trans("TTC").'</th>';
2823 print '<th class="right">'.$langs->trans("Label").'</th>';
2824 print '<th>'.$langs->trans("ChangedBy").'</th>';
2825 if ($user->hasRight('produit', 'supprimer')) {
2826 print '<th class="right">&nbsp;</th>';
2827 }
2828 print '</tr>';
2829
2830 $notfirstlineforlevel = array();
2831
2832 $i = 0;
2833 while ($i < $num) {
2834 $objp = $db->fetch_object($result);
2835
2836 print '<tr class="oddeven">';
2837 // Date
2838 print "<td>".dol_print_date($db->jdate($objp->dp), "dayhour", 'tzuserrel')."</td>";
2839
2840 // Price level
2841 if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
2842 print '<td class="center">'.$objp->price_level."</td>";
2843 }
2844 // Price by quantity
2845 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2846 $type = ($objp->price_by_qty == 1) ? 'PriceByQuantity' : 'Standard';
2847 print '<td class="center">'.$langs->trans($type)."</td>";
2848 }
2849
2850 print '<td class="center">';
2851 if (empty($objp->price_by_qty)) {
2852 print $langs->trans($objp->price_base_type);
2853 }
2854 print "</td>";
2855
2856 if (!getDolGlobalString('PRODUIT_MULTIPRICES') && !getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2857 print '<td class="right">';
2858
2859 if (empty($objp->price_by_qty)) {
2860 $positiverates = '';
2861 if (price2num($objp->tva_tx)) {
2862 $positiverates .= ($positiverates ? '/' : '').price2num($objp->tva_tx);
2863 }
2864 if (price2num($objp->localtax1_type)) {
2865 $positiverates .= ($positiverates ? '/' : '').price2num($objp->localtax1_tx);
2866 }
2867 if (price2num($objp->localtax2_type)) {
2868 $positiverates .= ($positiverates ? '/' : '').price2num($objp->localtax2_tx);
2869 }
2870 if (empty($positiverates)) {
2871 $positiverates = '0';
2872 }
2873 echo vatrate($positiverates.($objp->default_vat_code ? ' ('.$objp->default_vat_code.')' : ''), true, !empty($objp->tva_npr) ? $objp->tva_npr : 0);
2874 /*
2875 if ($objp->default_vat_code)
2876 {
2877 print vatrate($objp->tva_tx, true) . ' ('.$objp->default_vat_code.')';
2878 }
2879 else print vatrate($objp->tva_tx, true, $objp->recuperableonly);*/
2880 }
2881
2882 print "</td>";
2883 }
2884
2885 // Line for default price
2886 if ($objp->price_base_type == 'HT') {
2887 $pu = $objp->price;
2888 } else {
2889 $pu = $objp->price_ttc;
2890 }
2891
2892 // Local tax was not saved into table llx_product on old version. So we will use value linked to VAT code.
2893 $localtaxarray = getLocalTaxesFromRate($objp->tva_tx.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), 0, $mysoc, $mysoc);
2894 // Define part of HT, VAT, TTC
2895 $resultarray = calcul_price_total(1, $pu, 0, $objp->tva_tx, 1, 1, 0, $objp->price_base_type, $objp->recuperableonly, $object->type, $mysoc, $localtaxarray);
2896 // Calcul du total ht sans remise
2897 $total_ht = $resultarray[0];
2898 $total_vat = $resultarray[1];
2899 $total_localtax1 = $resultarray[9];
2900 $total_localtax2 = $resultarray[10];
2901 $total_ttc = $resultarray[2];
2902
2903 // Price
2904 if (!empty($objp->fk_price_expression) && !empty($conf->dynamicprices->enabled)) {
2905 $price_expression = new PriceExpression($db);
2906 $res = $price_expression->fetch($objp->fk_price_expression);
2907 $title = $price_expression->title;
2908 print '<td class="right"></td>';
2909 print '<td class="right"></td>';
2910 if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2911 print '<td class="right"></td>';
2912 }
2913 print '<td class="right">'.$title."</td>";
2914 } else {
2915 // Price HT
2916 print '<td class="right">';
2917 if (empty($objp->price_by_qty)) {
2918 print '<span class="amount">'.price($objp->price).'</span>';
2919 }
2920 print "</td>";
2921 // Price TTC
2922 print '<td class="right">';
2923 if (empty($objp->price_by_qty)) {
2924 $price_ttc = $objp->price_ttc;
2925 print '<span class="amount">'.price($price_ttc).'<span>';
2926 }
2927 print "</td>";
2928 if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") {
2929 print '<td class="right">';
2930 print $resultarray[2];
2931 print '</td>';
2932 }
2933 if (isModEnabled('dynamicprices')) { // Only if module is enabled
2934 print '<td class="right"></td>';
2935 }
2936 }
2937
2938 // Price min
2939 print '<td class="right">';
2940 if (empty($objp->price_by_qty)) {
2941 print price($objp->price_min);
2942 }
2943 print '</td>';
2944
2945 // Price min inc tax
2946 print '<td class="right">';
2947 if (empty($objp->price_by_qty)) {
2948 $price_min_ttc = $objp->price_min_ttc;
2949 print price($price_min_ttc);
2950 }
2951 print '</td>';
2952
2953 // Price Label
2954 print '<td class="right">';
2955 print $objp->price_label;
2956 print '</td>';
2957
2958 // User
2959 print '<td>';
2960 if ($objp->user_id > 0) {
2961 $userstatic = new User($db);
2962 $userstatic->fetch($objp->user_id);
2963 print $userstatic->getNomUrl(-1, '', 0, 0, 24, 0, 'login');
2964 }
2965 print '</td>';
2966
2967
2968 // Action
2969 if ($user->hasRight('produit', 'supprimer')) {
2970 $candelete = 0;
2971 if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
2972 if (empty($notfirstlineforlevel[$objp->price_level])) {
2973 $notfirstlineforlevel[$objp->price_level] = 1;
2974 } else {
2975 $candelete = 1;
2976 }
2977 } elseif ($i > 0) {
2978 $candelete = 1;
2979 }
2980
2981 print '<td class="right">';
2982 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
2983 print '<a href="'.$_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id.'&lineid='.$objp->rowid.'">';
2984 print img_delete();
2985 print '</a>';
2986 } else {
2987 print '&nbsp;'; // Can not delete last price (it's current price)
2988 }
2989 print '</td>';
2990 }
2991
2992 print "</tr>\n";
2993 $i++;
2994 }
2995
2996 $db->free($result);
2997 print "</table>";
2998 print '</div>';
2999 print "<br>";
3000 }
3001
3002 print '</div>';
3003 } else {
3004 dol_print_error($db);
3005 }
3006}
3007
3008// End of page
3009llxFooter();
3010$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).
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.
llxFooter()
Footer empty.
Definition document.php:107
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_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
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:149
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.