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