FIX Line of invoices not inserted when using POS module and VAT NPR.

This commit is contained in:
Laurent Destailleur 2017-06-09 15:35:27 +02:00
parent 55120d5e6d
commit 9341d5f448
8 changed files with 125 additions and 111 deletions

View File

@ -34,8 +34,8 @@ if ( $_GET['id'] == 'NOUV' )
// Recuperation, s'il existe, de l'objet contenant les infos de la vente en cours ...
if (isset($_SESSION['serObjFacturation']))
{
$obj_facturation = unserialize($_SESSION['serObjFacturation']);
unset($_SESSION['serObjFacturation']);
$obj_facturation = unserialize($_SESSION['serObjFacturation']);
unset($_SESSION['serObjFacturation']);
}
else
{
@ -43,7 +43,7 @@ else
$obj_facturation = new Facturation();
}
// $obj_facturation contains data for all invoice total + selection of current product
$obj_facturation->calculTotaux(); // Redefine prix_total_ttc, prix_total_ht et montant_tva from $_SESSION['poscart']

View File

@ -99,17 +99,25 @@ class Facturation
$product = new Product($db);
$product->fetch($this->id);
$vatrowid = $this->tva();
$tmp = getTaxesFromId($vatrowid);
$vat_rate = $tmp['rate'];
$txtva = $tmp['rate'].(empty($tmp['code'])?'':' ('.$tmp['code'].')');
$vat_npr = $tmp['npr'];
$localtaxarray = getLocalTaxesFromRate($vatrowid, 0, $societe, $mysoc, 1);
// Clean vat code
$vat_src_code='';
if (preg_match('/\((.*)\)/', $txtva, $reg))
{
$vat_src_code = $reg[1];
$txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
}
// Define part of HT, VAT, TTC
$resultarray=calcul_price_total($this->qte, $this->prix(), $this->remisePercent(), $vat_rate, -1, -1, 0, 'HT', $use_npr, $product->type, $mysoc, $localtaxarray);
$resultarray=calcul_price_total($this->qte, $this->prix(), $this->remisePercent(), $txtva, -1, -1, 0, 'HT', $use_npr, $product->type, $mysoc, $localtaxarray);
// Calcul du total ht sans remise
$total_ht = $resultarray[0];
@ -136,7 +144,7 @@ class Facturation
$newcartarray[$i]['label']=$product->label;
$newcartarray[$i]['price']=$product->price;
$newcartarray[$i]['price_ttc']=$product->price_ttc;
if (! empty($conf->global->PRODUIT_MULTIPRICES))
{
if (isset($product->multiprices[$societe->price_level]))
@ -148,7 +156,7 @@ class Facturation
$newcartarray[$i]['fk_article']=$this->id;
$newcartarray[$i]['qte']=$this->qte();
$newcartarray[$i]['fk_tva']=$this->tva();
$newcartarray[$i]['fk_tva']=$this->tva(); // Vat rowid
$newcartarray[$i]['remise_percent']=$remise_percent;
$newcartarray[$i]['remise']=price2num($montant_remise_ht);
$newcartarray[$i]['total_ht']=price2num($total_ht,'MT');
@ -220,7 +228,7 @@ class Facturation
$this->prix_total_vat = $total_vat;
$this->prix_total_localtax1 = $total_localtax1;
$this->prix_total_localtax2 = $total_localtax2;
$this->montant_tva = $total_ttc - $total_ht;
//print $this->prix_total_ttc.'eeee'; exit;
}

View File

@ -35,7 +35,7 @@
$form=new Form($db);
// Get list of articles (in warehouse '$conf_fkentrepot' if defined and stock module enabled)
if ( GETPOST('filtre') ) {
if ( GETPOST('filtre','alpha') ) {
// Avec filtre
$ret=array(); $i=0;
@ -47,22 +47,23 @@ if ( GETPOST('filtre') ) {
$sql.= " WHERE p.entity IN (".getEntity('product', 1).")";
$sql.= " AND p.tosell = 1";
if(!$conf->global->CASHDESK_SERVICES) $sql.= " AND p.fk_product_type = 0";
$sql.= " AND (p.ref LIKE '%".$db->escape(GETPOST('filtre'))."%' OR p.label LIKE '%".$db->escape(GETPOST('filtre'))."%'";
if (! empty($conf->barcode->enabled)) {
$filtre = GETPOST('filtre');
$sql.= " AND (";
$sql.= "p.ref LIKE '%".$db->escape(GETPOST('filtre'))."%' OR p.label LIKE '%".$db->escape(GETPOST('filtre'))."%'";
if (! empty($conf->barcode->enabled))
{
$filtre = GETPOST('filtre','alpha');
//If the barcode looks like an EAN13 format and the last digit is included in it,
//then whe look for the 12-digit too
//As the twelve-digit string will also hit the 13-digit code, we only look for this one
if (strlen($filtre) == 13) {
$crit_12digit = substr($filtre, 0, 12);
$sql .= " OR p.barcode LIKE '%".$db->escape($crit_12digit)."%')";
$sql .= " OR p.barcode LIKE '%".$db->escape($crit_12digit)."%'";
} else {
$sql.= " OR p.barcode LIKE '%".$db->escape($filtre)."%')";
$sql.= " OR p.barcode LIKE '%".$db->escape($filtre)."%'";
}
}
else $sql.= ")";
$sql.= ")";
$sql.= " ORDER BY label";
dol_syslog("facturation.php", LOG_DEBUG);
@ -154,34 +155,6 @@ global $mysoc;
$ret=array();
$i=0;
$sql = "SELECT t.rowid, t.taux";
$sql.= " FROM ".MAIN_DB_PREFIX."c_tva as t";
$sql.= ", ".MAIN_DB_PREFIX."c_country as c";
$sql.= " WHERE t.fk_pays = c.rowid";
$sql.= " AND t.active = 1";
$sql.= " AND c.code = '".$mysoc->country_code."'";
//print $sql;
$resql = $db->query($sql);
if ($resql)
{
while ( $tab = $db->fetch_array($resql) )
{
foreach ( $tab as $cle => $valeur )
{
$ret[$i][$cle] = $valeur;
}
$i++;
}
$db->free($resql);
}
else
{
dol_print_error($db);
}
$tab_tva = $ret;
// Reinitialisation du mode de paiement, en cas de retour aux achats apres validation
$obj_facturation->getSetPaymentMode('RESET');
$obj_facturation->montantEncaisse('RESET');

View File

@ -32,12 +32,12 @@ $obj_facturation = unserialize($_SESSION['serObjFacturation']);
unset ($_SESSION['serObjFacturation']);
switch ( $_GET['action'] )
switch (GETPOST('action','alpha'))
{
default:
if ( $_POST['hdnSource'] != 'NULL' )
{
$sql = "SELECT p.rowid, p.ref, p.price, p.tva_tx, p.recuperableonly";
$sql = "SELECT p.rowid, p.ref, p.price, p.tva_tx, p.default_vat_code, p.recuperableonly";
if (! empty($conf->stock->enabled) && !empty($conf_fkentrepot)) $sql.= ", ps.reel";
$sql.= " FROM ".MAIN_DB_PREFIX."product as p";
if (! empty($conf->stock->enabled) && !empty($conf_fkentrepot)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps ON p.rowid = ps.fk_product AND ps.fk_entrepot = ".$conf_fkentrepot;
@ -54,7 +54,6 @@ switch ( $_GET['action'] )
}
$result = $db->query($sql);
if ($result)
{
// ... et enregistrement dans l'objet
@ -67,62 +66,90 @@ switch ( $_GET['action'] )
$ret[$key] = $value;
}
// Here $ret['tva_tx'] is vat rate of product but we want to not use the one into table but found by function
$productid = $ret['rowid'];
$product = new Product($db);
$product->fetch($productid);
$prod = $product;
$thirdpartyid = $_SESSION['CASHDESK_ID_THIRDPARTY'];
$societe = new Societe($db);
$societe->fetch($thirdpartyid);
$tva_tx = get_default_tva($mysoc,$societe,$productid);
$tva_npr = get_default_npr($mysoc,$societe,$productid);
// Update if prices fields are defined
$tva_tx = get_default_tva($mysoc, $societe, $product->id);
$tva_npr = get_default_npr($mysoc, $societe, $product->id);
if (empty($tva_tx)) $tva_npr=0;
dol_syslog('tva_tx='.$tva_tx.'-tva_npr='.$tva_npr);
$pu_ht = $prod->price;
$pu_ttc = $prod->price_ttc;
$price_min = $prod->price_min;
$price_base_type = $prod->price_base_type;
// multiprix
if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($societe->price_level))
{
if(isset($product->multiprices[$societe->price_level]))
{
$ret['price'] = $product->multiprices[$societe->price_level];
$ret['price_ttc'] = $product->multiprices_ttc[$societe->price_level];
// $product->multiprices_min[$societe->price_level];
// $product->multiprices_min_ttc[$societe->price_level];
// $product->multiprices_base_type[$societe->price_level];
if (! empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) // using this option is a bug. kept for backward compatibility
{
if (isset($prod->multiprices_tva_tx[$societe->price_level])) $tva_tx=$prod->multiprices_tva_tx[$societe->price_level];
if (isset($prod->multiprices_recuperableonly[$societe->price_level])) $tva_npr=$prod->multiprices_recuperableonly[$societe->price_level];
if (empty($tva_tx)) $tva_npr=0;
}
}
$pu_ht = $prod->multiprices[$societe->price_level];
$pu_ttc = $prod->multiprices_ttc[$societe->price_level];
$price_min = $prod->multiprices_min[$societe->price_level];
$price_base_type = $prod->multiprices_base_type[$societe->price_level];
if (! empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) // using this option is a bug. kept for backward compatibility
{
if (isset($prod->multiprices_tva_tx[$societe->price_level])) $tva_tx=$prod->multiprices_tva_tx[$societe->price_level];
if (isset($prod->multiprices_recuperableonly[$societe->price_level])) $tva_npr=$prod->multiprices_recuperableonly[$societe->price_level];
}
}
elseif (! empty($conf->global->PRODUIT_CUSTOMER_PRICES))
{
require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
$prodcustprice = new Productcustomerprice($db);
$filter = array('t.fk_product' => $prod->id,'t.fk_soc' => $societe->id);
$result = $prodcustprice->fetch_all('', '', 0, 0, $filter);
if ($result >= 0)
{
if (count($prodcustprice->lines) > 0)
{
$pu_ht = price($prodcustprice->lines [0]->price);
$pu_ttc = price($prodcustprice->lines [0]->price_ttc);
$price_base_type = $prodcustprice->lines [0]->price_base_type;
$tva_tx = $prodcustprice->lines [0]->tva_tx;
}
}
else
{
setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
}
}
$tmpvat = price2num(preg_replace('/\s*\(.*\)/', '', $tva_tx));
$tmpprodvat = price2num(preg_replace('/\s*\(.*\)/', '', $prod->tva_tx));
// if price ht is forced (ie: calculated by margin rate and cost price). TODO Why this ?
if (! empty($price_ht)) {
$pu_ht = price2num($price_ht, 'MU');
$pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
}
// On reevalue prix selon taux tva car taux tva transaction peut etre different
// de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur).
elseif ($tmpvat != $tmpprodvat) {
if ($price_base_type != 'HT') {
$pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
} else {
$pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
}
}
$ret['tva_tx'] = $tva_tx;
$ret['tva_npr'] = $tva_npr;
//var_dump('tva_tx='.$ret['tva_tx'].'-tva_npr='.$ret['tva_npr'].'-'.$conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL);exit;
$obj_facturation->id($ret['rowid']);
$obj_facturation->ref($ret['ref']);
$obj_facturation->stock($ret['reel']);
$obj_facturation->prix($ret['price']);
// Use $ret['tva_tx'] / ret['tva_npr'] to find vat id
$vatrowid = null;
$sqlfindvatid = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'c_tva';
$sqlfindvatid.= ' WHERE taux = '.$ret['tva_tx'].' AND recuperableonly = '.(int) $ret['tva_npr'];
$sqlfindvatid.= ' AND fk_pays = '.$mysoc->country_id;
$resqlfindvatid=$db->query($sqlfindvatid);
if ($resqlfindvatid)
{
$obj = $db->fetch_object($resqlfindvatid);
if ($obj) $vatrowid = $obj->rowid;
}
else dol_print_error($db);
dol_syslog("save vatrowid=".$vatrowid);
$obj_facturation->tva($vatrowid); // Save vat it for next use
$vatrate = $tva_tx;
$obj_facturation->vatrate = $vatrate; // Save vat rate (full text vat with code)
// Definition du filtre pour n'afficher que le produit concerne
if ( $_POST['hdnSource'] == 'LISTE' )
@ -168,11 +195,11 @@ switch ( $_GET['action'] )
{
dol_syslog("facturation_verif save vat ".$_POST['selTva']);
$obj_facturation->qte($_POST['txtQte']);
$obj_facturation->tva($_POST['selTva']); // Save VAT selected so we can use it for next product
$obj_facturation->tva($_POST['selTva']); // id of vat. Saved so we can use it for next product
$obj_facturation->remisePercent($_POST['txtRemise']);
$obj_facturation->ajoutArticle(); // This add an entry into $_SESSION['poscart']
// We update prixTotalTtc
}
$redirection = DOL_URL_ROOT.'/cashdesk/affIndex.php?menutpl=facturation';

View File

@ -125,12 +125,12 @@ $langs->load("cashdesk");
<td><input class="texte1_off maxwidth50onsmartphone" type="text" name="txtTotal" value="" disabled /></td><td></td>
<!-- Choix du taux de TVA -->
<td class="select_tva">
<?php //var_dump($tab_tva);
$tva_tx = $obj_facturation->tva(); // Try to get a previously entered VAT rowid. First time, this will return empty.
<?php
$vatrate = $obj_facturation->vatrate; // To get vat rate we just have selected
$buyer = new Societe($db);
if ($_SESSION["CASHDESK_ID_THIRDPARTY"] > 0) $buyer->fetch($_SESSION["CASHDESK_ID_THIRDPARTY"]);
echo $form->load_tva('selTva', (isset($_POST["selTva"])?GETPOST("selTva",'alpha',2):-1), $mysoc, $buyer, 0, 0, '', false, -1);
echo $form->load_tva('selTva', (isset($_POST["selTva"])?GETPOST("selTva",'alpha',2):$vatrate), $mysoc, $buyer, 0, 0, '', false, -1);
?>
</td>
</tr>

View File

@ -165,6 +165,7 @@ switch ($action)
$tmp = getTaxesFromId($tab_liste[$i]['fk_tva']);
$vat_rate = $tmp['rate'];
$vat_npr = $tmp['npr'];
$vat_src_code = $tmp['code'];
$invoiceline=new FactureLigne($db);
$invoiceline->fk_product=$tab_liste[$i]['fk_article'];
@ -173,15 +174,17 @@ switch ($action)
$invoiceline->remise_percent=$tab_liste[$i]['remise_percent'];
$invoiceline->price=$tab_liste[$i]['price'];
$invoiceline->subprice=$tab_liste[$i]['price'];
$invoiceline->tva_tx=empty($vat_rate)?0:$vat_rate; // works even if vat_rate is ''
$invoiceline->info_bits=empty($vat_npr)?0:$vat_npr;
$invoiceline->vat_src_code=$vat_src_code;
$invoiceline->total_ht=$tab_liste[$i]['total_ht'];
$invoiceline->total_ttc=$tab_liste[$i]['total_ttc'];
$invoiceline->total_tva=$tab_liste[$i]['total_vat'];
$invoiceline->total_localtax1=$tab_liste[$i]['total_localtax1'];
$invoiceline->total_localtax2=$tab_liste[$i]['total_localtax2'];
$invoice->lines[]=$invoiceline;
}
@ -205,7 +208,7 @@ switch ($action)
{
$warehouseidtodecrease=(isset($_SESSION["CASHDESK_ID_WAREHOUSE"])?$_SESSION["CASHDESK_ID_WAREHOUSE"]:0);
if (! empty($conf->global->CASHDESK_NO_DECREASE_STOCK)) $warehouseidtodecrease=0; // If a particular stock is defined, we disable choice
$resultvalid=$invoice->validate($user, $obj_facturation->numInvoice(), 0);
if ($warehouseidtodecrease > 0)
@ -245,7 +248,7 @@ switch ($action)
{
$warehouseidtodecrease=(isset($_SESSION["CASHDESK_ID_WAREHOUSE"])?$_SESSION["CASHDESK_ID_WAREHOUSE"]:0);
if (! empty($conf->global->CASHDESK_NO_DECREASE_STOCK)) $warehouseidtodecrease=0; // If a particular stock is defined, we disable choice
$resultvalid=$invoice->validate($user, $obj_facturation->numInvoice(), 0);
if ($warehouseidtodecrease > 0)

View File

@ -519,9 +519,12 @@ class Facture extends CommonInvoice
{
$newinvoiceline=$this->lines[$i];
$newinvoiceline->fk_facture=$this->id;
$newinvoiceline->origin = $this->element; // TODO This seems not used. Here we but origin 'facture' but after
$newinvoiceline->origin_id = $this->lines[$i]->id; // we put an id of object !
if ($result >= 0 && ($newinvoiceline->info_bits & 0x01) == 0) // We keep only lines with first bit = 0
// TODO This seems not used. Here we put origin 'facture' but after, we put an id of object !
$newinvoiceline->origin = $this->element;
$newinvoiceline->origin_id = $this->lines[$i]->id;
if ($result >= 0)
{
// Reset fk_parent_line for no child products and special product
if (($newinvoiceline->product_type != 9 && empty($newinvoiceline->fk_parent_line)) || $newinvoiceline->product_type == 9) {
@ -558,7 +561,7 @@ class Facture extends CommonInvoice
//if (! is_object($line)) $line=json_decode(json_encode($line), FALSE); // convert recursively array into object.
if (! is_object($line)) $line = (object) $line;
if (($line->info_bits & 0x01) == 0) // We keep only lines with first bit = 0
if ($result >= 0)
{
// Reset fk_parent_line for no child products and special product
if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {

View File

@ -300,7 +300,7 @@ if (! defined('NOTOKENRENEWAL'))
{
// roulement des jetons car cree a chaque appel
if (isset($_SESSION['newtoken'])) $_SESSION['token'] = $_SESSION['newtoken'];
// Save in $_SESSION['newtoken'] what will be next token. Into forms, we will add param token = $_SESSION['newtoken']
$token = dol_hash(uniqid(mt_rand(),TRUE)); // Generates a hash of a random number
$_SESSION['newtoken'] = $token;
@ -586,7 +586,7 @@ if (! defined('NOLOGIN'))
// We are already into an authenticated session
$login=$_SESSION["dol_login"];
$entity=$_SESSION["dol_entity"];
dol_syslog("This is an already logged session. _SESSION['dol_login']=".$login." _SESSION['dol_entity']=".$entity, LOG_DEBUG);
dol_syslog("- This is an already logged session. _SESSION['dol_login']=".$login." _SESSION['dol_entity']=".$entity, LOG_DEBUG);
$resultFetchUser=$user->fetch('',$login,'',1,($entity > 0 ? $entity : -1));
if ($resultFetchUser <= 0)
@ -1051,7 +1051,7 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs
$ext='version='.urlencode(DOL_VERSION);
if (GETPOST('version')) $ext='version='.GETPOST('version','int'); // usefull to force no cache on css/js
if (GETPOST('testmenuhider') || ! empty($conf->global->MAIN_TESTMENUHIDER)) $ext='testmenuhider='.GETPOST('testmenuhider','int');
$themeparam='?lang='.$langs->defaultlang.'&amp;theme='.$conf->theme.(GETPOST('optioncss')?'&amp;optioncss='.GETPOST('optioncss','alpha',1):'').'&amp;userid='.$user->id.'&amp;entity='.$conf->entity;
$themeparam.=($ext?'&amp;'.$ext:'');
if (! empty($_SESSION['dol_resetcache'])) $themeparam.='&amp;dol_resetcache='.$_SESSION['dol_resetcache'];
@ -1060,7 +1060,7 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs
if (GETPOST('dol_optimize_smallscreen')) { $themeparam.='&amp;dol_optimize_smallscreen='.GETPOST('dol_optimize_smallscreen','int'); }
if (GETPOST('dol_no_mouse_hover')) { $themeparam.='&amp;dol_no_mouse_hover='.GETPOST('dol_no_mouse_hover','int'); }
if (GETPOST('dol_use_jmobile')) { $themeparam.='&amp;dol_use_jmobile='.GETPOST('dol_use_jmobile','int'); $conf->dol_use_jmobile=GETPOST('dol_use_jmobile','int'); }
if (! defined('DISABLE_JQUERY') && ! $disablejs && $conf->use_javascript_ajax)
{
print '<!-- Includes CSS for JQuery (Ajax library) -->'."\n";
@ -1929,7 +1929,7 @@ if (! function_exists("llxFooter"))
});
</script>' . "\n";
}
// Wrapper to manage dropdown
if ($conf->use_javascript_ajax)
{
@ -1960,7 +1960,7 @@ if (! function_exists("llxFooter"))
console.log("Link has class dropdowncloseonclick, so we close/hide the popup ul");
$(this).parent().parent().hide();
});
$(document).bind(\'click\', function (e) {
var $clicked = $(e.target);
if (!$clicked.parents().hasClass("dropdown")) $(".dropdown dd ul").hide();
@ -1968,7 +1968,7 @@ if (! function_exists("llxFooter"))
});
</script>';
}
// A div for the address popup
print "\n<!-- A div to allow dialog popup -->\n";
print '<div id="dialogforpopup" style="display: none;"></div>'."\n";