diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 4f2159a200e..c0b592c28f2 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1322,7 +1322,6 @@ class Propal extends CommonObject // Load source object $object->fetch($this->id); - $object->fetch_lines(); $objsoc = new Societe($this->db); @@ -1708,7 +1707,7 @@ class Propal extends CommonObject $sql = 'SELECT d.rowid, d.fk_propal, d.fk_parent_line, d.label as custom_label, d.description, d.price, d.vat_src_code, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.localtax1_type, d.localtax2_type, d.qty, d.fk_remise_except, d.remise_percent, d.subprice, d.fk_product,'; $sql .= ' d.info_bits, d.total_ht, d.total_tva, d.total_localtax1, d.total_localtax2, d.total_ttc, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht, d.special_code, d.rang, d.product_type,'; $sql .= ' d.fk_unit,'; - $sql .= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label, p.tobatch as product_batch,'; + $sql .= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label, p.tobatch as product_tobatch, p.barcode as product_barcode,'; $sql .= ' p.weight, p.weight_units, p.volume, p.volume_units,'; $sql .= ' d.date_start, d.date_end,'; $sql .= ' d.fk_multicurrency, d.multicurrency_code, d.multicurrency_subprice, d.multicurrency_total_ht, d.multicurrency_total_tva, d.multicurrency_total_ttc'; @@ -1770,11 +1769,14 @@ class Propal extends CommonObject $line->fk_product = $objp->fk_product; $line->ref = $objp->product_ref; // deprecated - $line->product_ref = $objp->product_ref; $line->libelle = $objp->product_label; // deprecated + + $line->product_ref = $objp->product_ref; $line->product_label = $objp->product_label; $line->product_desc = $objp->product_desc; // Description produit $line->product_tobatch = $objp->product_tobatch; + $line->product_barcode = $objp->product_barcode; + $line->fk_product_type = $objp->fk_product_type; // deprecated $line->fk_unit = $objp->fk_unit; $line->weight = $objp->weight; @@ -3839,6 +3841,18 @@ class PropaleLigne extends CommonObjectLine */ public $product_desc; + /** + * Product use lot + * @var string + */ + public $product_tobatch; + + /** + * Product barcode + * @var string + */ + public $product_barcode; + public $localtax1_tx; // Local tax 1 public $localtax2_tx; // Local tax 2 public $localtax1_type; // Local tax 1 type diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index 22c512aa0ed..d38dd6d86ed 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -1709,7 +1709,7 @@ if ($action == 'create' && $usercancreate) $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); print $hookmanager->resPrint; if (empty($reshook)) { - if (!empty($conf->global->THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_ORDER)) { + if (!empty($conf->global->THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_ORDER) && !empty($soc->id)) { // copy from thirdparty $tpExtrafields = new Extrafields($db); $tpExtrafieldLabels = $tpExtrafields->fetch_name_optionals_label($soc->table_element); diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index ade778263e9..9de479dcb52 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -2014,7 +2014,7 @@ class Commande extends CommonOrder $sql .= ' l.total_ht, l.total_ttc, l.total_tva, l.total_localtax1, l.total_localtax2, l.date_start, l.date_end,'; $sql .= ' l.fk_unit,'; $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,'; - $sql .= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label, p.tosell as product_tosell, p.tobuy as product_tobuy, p.tobatch as product_tobatch,'; + $sql .= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label, p.tosell as product_tosell, p.tobuy as product_tobuy, p.tobatch as product_tobatch, p.barcode as product_barcode,'; $sql .= ' p.weight, p.weight_units, p.volume, p.volume_units'; $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as l'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (p.rowid = l.fk_product)'; @@ -2073,13 +2073,16 @@ class Commande extends CommonOrder $line->fk_parent_line = $objp->fk_parent_line; $line->ref = $objp->product_ref; - $line->product_ref = $objp->product_ref; $line->libelle = $objp->product_label; + + $line->product_ref = $objp->product_ref; $line->product_label = $objp->product_label; $line->product_desc = $objp->product_desc; $line->product_tosell = $objp->product_tosell; $line->product_tobuy = $objp->product_tobuy; $line->product_tobatch = $objp->product_tobatch; + $line->product_barcode = $objp->product_barcode; + $line->fk_product_type = $objp->fk_product_type; // Produit ou service $line->fk_unit = $objp->fk_unit; diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 101b0aa82e6..a4def0c0b9b 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -3466,7 +3466,7 @@ if ($action == 'create') $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; if (empty($reshook)) { - if (!empty($conf->global->THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_INVOICE)) { + if (!empty($conf->global->THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_INVOICE) && !empty($soc->id)) { // copy from thirdparty $tpExtrafields = new Extrafields($db); $tpExtrafieldLabels = $tpExtrafields->fetch_name_optionals_label($soc->table_element); diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 6d1a6a57cba..1cd873c64c6 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -582,10 +582,13 @@ abstract class CommonDocGenerator $resarray = array( 'line_pos' => $linenumber, 'line_fulldesc'=>doc_getlinedesc($line, $outputlangs), - 'line_product_ref'=>$line->product_ref, - 'line_product_ref_fourn'=>$line->ref_fourn, // for supplier doc lines - 'line_product_label'=>$line->product_label, - 'line_product_type'=>$line->product_type, + + 'line_product_ref'=>(empty($line->product_ref) ? '' : $line->product_ref), + 'line_product_ref_fourn'=>(empty($line->ref_fourn) ? '' : $line->ref_fourn), // for supplier doc lines + 'line_product_label'=>(empty($line->product_label) ? '' :$line->product_label), + 'line_product_type'=>(empty($line->product_type) ? '' : $line->product_type), + 'line_product_barcode'=>(empty($line->product_barcode) ? '' : $line->product_barcode), + 'line_desc'=>$line->desc, 'line_vatrate'=>vatrate($line->tva_tx, true, $line->info_bits), 'line_localtax1_rate'=>vatrate($line->localtax1_tx), diff --git a/htdocs/core/class/commonorder.class.php b/htdocs/core/class/commonorder.class.php index 5062a7016bb..410bf41a601 100644 --- a/htdocs/core/class/commonorder.class.php +++ b/htdocs/core/class/commonorder.class.php @@ -78,6 +78,18 @@ abstract class CommonOrderLine extends CommonObjectLine */ public $product_desc; + /** + * Product use lot + * @var string + */ + public $product_tobatch; + + /** + * Product barcode + * @var string + */ + public $product_barcode; + /** * Quantity * @var float diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index bfa6ec798cd..235c9bcc084 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -4748,19 +4748,19 @@ function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $ * Function to use on each input amount before any numeric test or database insert. A better name for this function * should be roundtext2num(). * - * @param float $amount Amount to convert/clean or round - * @param string $rounding ''=No rounding - * 'MU'=Round to Max unit price (MAIN_MAX_DECIMALS_UNIT) - * 'MT'=Round to Max for totals with Tax (MAIN_MAX_DECIMALS_TOT) - * 'MS'=Round to Max for stock quantity (MAIN_MAX_DECIMALS_STOCK) - * 'CR'=Currency rate - * Numeric = Nb of digits for rounding - * @param int $alreadysqlnb Put 1 if you know that content is already universal format number - * @return string Amount with universal numeric format (Example: '99.99999'). - * If conversion fails, it return text unchanged if $rounding = '' or '0' if $rounding is defined. - * If amount is null or '', it returns '' if $rounding = '' or '0' if $rounding is defined.. + * @param string|float $amount Amount to convert/clean or round + * @param string $rounding ''=No rounding + * 'MU'=Round to Max unit price (MAIN_MAX_DECIMALS_UNIT) + * 'MT'=Round to Max for totals with Tax (MAIN_MAX_DECIMALS_TOT) + * 'MS'=Round to Max for stock quantity (MAIN_MAX_DECIMALS_STOCK) + * 'CR'=Currency rate + * Numeric = Nb of digits for rounding + * @param int $alreadysqlnb Put 1 if you know that content is already universal format number + * @return string Amount with universal numeric format (Example: '99.99999'). + * If conversion fails, it return text unchanged if $rounding = '' or '0' if $rounding is defined. + * If amount is null or '', it returns '' if $rounding = '' or '0' if $rounding is defined.. * - * @see price() Opposite function of price2num + * @see price() Opposite function of price2num */ function price2num($amount, $rounding = '', $alreadysqlnb = 0) { @@ -4777,15 +4777,15 @@ function price2num($amount, $rounding = '', $alreadysqlnb = 0) //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'
"; // Convert value to universal number format (no thousand separator, '.' as decimal separator) - if ($alreadysqlnb != 1) // If not a PHP number or unknown, we change format - { - //print 'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'
'; + if ($alreadysqlnb != 1) { // If not a PHP number or unknown, we change or clean format + print 'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'
'; + if ($thousand == '.' && preg_match('/\.(\d\d\d)$/', (string) $amount)) { // It means the . is used as a thousand separator, not as a decimal separator + $amount = str_replace($thousand, '', $amount); // Replace of thousand before test of is_numeric to avoid pb if thousand is . and there is 3 numbers after + print 'TTTT'.$amount; + } // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup. - if ($thousand == '.') { - $amount = str_replace($thousand, '', $amount); // Replace of thousand before test of is_numeric to avoid pb if thousand is . - } if (is_numeric($amount)) { // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10 @@ -4795,7 +4795,7 @@ function price2num($amount, $rounding = '', $alreadysqlnb = 0) $amount = number_format($amount, $nbofdec, $dec, $thousand); } //print "QQ".$amount.'
'; - + // Now make replace (the main goal of function) if ($thousand != ',' && $thousand != '.') { $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users diff --git a/test/phpunit/FunctionsLibTest.php b/test/phpunit/FunctionsLibTest.php index e24abcf4c0f..f757b00944f 100644 --- a/test/phpunit/FunctionsLibTest.php +++ b/test/phpunit/FunctionsLibTest.php @@ -1260,10 +1260,18 @@ class FunctionsLibTest extends PHPUnit\Framework\TestCase $newlangs2->load("main"); $langs = $newlangs2; - $this->assertEquals(1000, price2num('1.000'), 'Test 1.000 give 1000 with spanish language'); - $this->assertEquals(1000, price2num('1 000'), 'Test 1 000 give 1000 with spanish language'); + // Test with 3 chars after . or , + // If a . is used and there is 3 digits after, it is a thousand separator + $this->assertEquals(1234, price2num('1.234'), 'Test 1.234 give 1234 with spanish language'); + $this->assertEquals(1234, price2num('1 234'), 'Test 1 234 give 1234 with spanish language'); $this->assertEquals(1234, price2num('1.234'), 'Test 1.234 give 1234 with spanish language'); $this->assertEquals(1.234, price2num('1,234'), 'Test 1,234 give 1.234 with spanish language'); + $this->assertEquals(21500123, price2num('21.500.123'), 'Test 21.500.123 give 21500123 with spanish language'); + $this->assertEquals(21500123, price2num('21500.123'), 'Test 21500.123 give 21500123 with spanish language'); + $this->assertEquals(21500.123, price2num('21500,123'), 'Test 21500,123 give 21500.123 with spanish language'); + // Test with 2 digits + $this->assertEquals(21500.12, price2num('21500.12'), 'Test 21500.12 give 21500.12 with spanish language'); + $this->assertEquals(21500.12, price2num('21500,12'), 'Test 21500,12 give 21500.12 with spanish language'); // For french language $newlangs3 = new Translate('', $conf); @@ -1275,6 +1283,10 @@ class FunctionsLibTest extends PHPUnit\Framework\TestCase $this->assertEquals(1000, price2num('1 000'), 'Test 1.000 give 1 with french language'); $this->assertEquals(1.234, price2num('1.234'), 'Test 1.234 give 1.234 with french language'); $this->assertEquals(1.234, price2num('1,234'), 'Test 1,234 give 1.234 with french language'); + $this->assertEquals(21500000, price2num('21500 000'), 'Test 21500 000 give 21500000 with french language'); + $this->assertEquals(21500000, price2num('21 500 000'), 'Test 21 500 000 give 21500000 with french language'); + $this->assertEquals(21500, price2num('21500.00'), 'Test 21500.00 give 21500 with french language'); + $this->assertEquals(21500, price2num('21500,00'), 'Test 21500,00 give 21500 with french language'); $langs = $oldlangs;