Skip to content
Snippets Groups Projects
Commit 6f63c5ec authored by Laurent Destailleur's avatar Laurent Destailleur
Browse files

Work on PDO Sqlite driver

parent fb662a91
No related branches found
No related tags found
No related merge requests found
......@@ -507,7 +507,7 @@ class DoliDBPgsql
// Convert MySQL syntax to PostgresSQL syntax
$query=$this->convertSQLFromMysql($query,$type);
//print "FF\n".$query."<br>\n";
//print "After convertSQLFromMysql:\n".$query."<br>\n";
// Fix bad formed requests. If request contains a date without quotes, we fix this but this should not occurs.
$loop=true;
......@@ -786,7 +786,7 @@ class DoliDBPgsql
return 'DB_ERROR_FAILED_TO_CONNECT';
}
else {
// Constants to convert a MySql error code to a generic Dolibarr error code
// Constants to convert error code to a generic Dolibarr error code
$errorcode_map = array(
1004 => 'DB_ERROR_CANNOT_CREATE',
1005 => 'DB_ERROR_CANNOT_CREATE',
......
......@@ -36,7 +36,7 @@ class DoliDBSqlite
//! Database type
public $type='sqlite';
//! Database label
static $label='Sqlite';
static $label='PDO Sqlite';
//! Charset used to force charset when creating database
static $forcecharset='utf8'; // latin1, utf8
//! Collate used to force collate when creating database
......@@ -148,7 +148,157 @@ class DoliDBSqlite
*/
function convertSQLFromMysql($line,$type='ddl')
{
return $line;
// Removed empty line if this is a comment line for SVN tagging
if (preg_match('/^--\s\$Id/i',$line)) {
return '';
}
// Return line if this is a comment
if (preg_match('/^#/i',$line) || preg_match('/^$/i',$line) || preg_match('/^--/i',$line))
{
return $line;
}
if ($line != "")
{
if ($type == 'auto')
{
if (preg_match('/ALTER TABLE/i',$line)) $type='dml';
else if (preg_match('/CREATE TABLE/i',$line)) $type='dml';
else if (preg_match('/DROP TABLE/i',$line)) $type='dml';
}
if ($type == 'dml')
{
$line=preg_replace('/\s/',' ',$line); // Replace tabulation with space
// we are inside create table statement so lets process datatypes
if (preg_match('/(ISAM|innodb)/i',$line)) { // end of create table sequence
$line=preg_replace('/\)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb);/i',');',$line);
$line=preg_replace('/\)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb);/i',');',$line);
$line=preg_replace('/,$/','',$line);
}
// Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
if (preg_match('/[\s\t\(]*(\w*)[\s\t]+int.*auto_increment/i',$line,$reg)) {
$newline=preg_replace('/([\s\t\(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i','\\1 \\2 SERIAL PRIMARY KEY',$line);
//$line = "-- ".$line." replaced by --\n".$newline;
$line=$newline;
}
// tinyint type conversion
$line=str_replace('tinyint','smallint',$line);
// nuke unsigned
$line=preg_replace('/(int\w+|smallint)\s+unsigned/i','\\1',$line);
// blob -> text
$line=preg_replace('/\w*blob/i','text',$line);
// tinytext/mediumtext -> text
$line=preg_replace('/tinytext/i','text',$line);
$line=preg_replace('/mediumtext/i','text',$line);
// change not null datetime field to null valid ones
// (to support remapping of "zero time" to null
$line=preg_replace('/datetime not null/i','datetime',$line);
$line=preg_replace('/datetime/i','timestamp',$line);
// double -> numeric
$line=preg_replace('/^double/i','numeric',$line);
$line=preg_replace('/(\s*)double/i','\\1numeric',$line);
// float -> numeric
$line=preg_replace('/^float/i','numeric',$line);
$line=preg_replace('/(\s*)float/i','\\1numeric',$line);
// unique index(field1,field2)
if (preg_match('/unique index\s*\((\w+\s*,\s*\w+)\)/i',$line))
{
$line=preg_replace('/unique index\s*\((\w+\s*,\s*\w+)\)/i','UNIQUE\(\\1\)',$line);
}
// We remove end of requests "AFTER fieldxxx"
$line=preg_replace('/AFTER [a-z0-9_]+/i','',$line);
// We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
$line=preg_replace('/ALTER TABLE [a-z0-9_]+ DROP INDEX/i','DROP INDEX',$line);
// Translate order to rename fields
if (preg_match('/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i',$line,$reg))
{
$line = "-- ".$line." replaced by --\n";
$line.= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3];
}
// Translate order to modify field format
if (preg_match('/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i',$line,$reg))
{
$line = "-- ".$line." replaced by --\n";
$newreg3=$reg[3];
$newreg3=preg_replace('/ DEFAULT NULL/i','',$newreg3);
$newreg3=preg_replace('/ NOT NULL/i','',$newreg3);
$newreg3=preg_replace('/ NULL/i','',$newreg3);
$newreg3=preg_replace('/ DEFAULT 0/i','',$newreg3);
$newreg3=preg_replace('/ DEFAULT \'[0-9a-zA-Z_@]*\'/i','',$newreg3);
$line.= "ALTER TABLE ".$reg[1]." ALTER COLUMN ".$reg[2]." TYPE ".$newreg3;
// TODO Add alter to set default value or null/not null if there is this in $reg[3]
}
// alter table add primary key (field1, field2 ...) -> We remove the primary key name not accepted by PostGreSQL
// ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity);
if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\((.*)$/i',$line,$reg))
{
$line = "-- ".$line." replaced by --\n";
$line.= "ALTER TABLE ".$reg[1]." ADD PRIMARY KEY (".$reg[3];
}
// Translate order to drop foreign keys
// ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx;
if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i',$line,$reg))
{
$line = "-- ".$line." replaced by --\n";
$line.= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
}
// alter table add [unique] [index] (field1, field2 ...)
// ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\(([\w,\s]+)\)/i',$line,$reg))
{
$fieldlist=$reg[4];
$idxname=$reg[3];
$tablename=$reg[1];
$line = "-- ".$line." replaced by --\n";
$line.= "CREATE ".(preg_match('/UNIQUE/',$reg[2])?'UNIQUE ':'')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")";
}
}
// To have postgresql case sensitive
$line=str_replace(' LIKE \'',' ILIKE \'',$line);
// Delete using criteria on other table must not declare twice the deleted table
// DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i',$line,$reg))
{
if ($reg[1] == $reg[2]) // If same table, we remove second one
{
$line=preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i','DELETE FROM \\1 USING \\3', $line);
}
}
// Remove () in the tables in FROM if one table
$line=preg_replace('/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i','FROM \\1',$line);
//print $line."\n";
// Remove () in the tables in FROM if two table
$line=preg_replace('/FROM\s*\(([a-z_]+\s+as\s+[a-z_]+)\s*,\s*([a-z_]+\s+as\s+[a-z_]+\s*)\)/i','FROM \\1, \\2',$line);
//print $line."\n";
// Remove () in the tables in FROM if two table
$line=preg_replace('/FROM\s*\(([a-z_]+\s+as\s+[a-z_]+)\s*,\s*([a-z_]+\s+as\s+[a-z_]+\s*),\s*([a-z_]+\s+as\s+[a-z_]+\s*)\)/i','FROM \\1, \\2, \\3',$line);
//print $line."\n";
//print "type=".$type." newline=".$line."<br>\n";
}
return $line;
}
/**
......@@ -188,6 +338,7 @@ class DoliDBSqlite
try {
/*** connect to SQLite database ***/
$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb');
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
......@@ -337,11 +488,16 @@ class DoliDBSqlite
$ret='';
$query = trim($query);
$this->error = 0;
// Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
// Convert MySQL syntax to SQLite syntax
$query=$this->convertSQLFromMysql($query,$type);
//print "After convertSQLFromMysql:\n".$query."<br>\n";
// Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
try {
//$ret = $this->db->exec($query);
$ret = $this->db->query($query);
$ret = $this->db->query($query); // $ret is a PDO object
}
catch(PDOException $e)
{
......@@ -351,12 +507,13 @@ class DoliDBSqlite
if (! preg_match("/^COMMIT/i",$query) && ! preg_match("/^ROLLBACK/i",$query))
{
// Si requete utilisateur, on la sauvegarde ainsi que son resultset
if (! $ret)
if (! is_object($ret) || $this->error)
{
$this->lastqueryerror = $query;
$this->lasterror = $this->error();
$this->lasterrno = $this->errno();
dol_syslog(get_class($this)."::query SQL error: ".$query." ".$this->lasterrno, LOG_WARNING);
if (preg_match('/[0-9]/',$this->lasterrno)) dol_syslog(get_class($this)."::query SQL error: ".$query." ".$this->lasterrno." ".$this->lasterror, LOG_WARNING);
else dol_syslog(get_class($this)."::query SQL error: ".$query." ".$this->lasterrno, LOG_WARNING);
}
$this->lastquery=$query;
$this->results = $ret;
......@@ -424,11 +581,12 @@ class DoliDBSqlite
{
// If resultset not provided, we take the last used by connexion
if (! is_object($resultset)) { $resultset=$this->results; }
return sqlite_num_rows($resultset);
return $resultset->rowCount();
}
/**
* Renvoie le nombre de lignes dans le resultat d'une requete INSERT, DELETE ou UPDATE
*
* @see num_rows
* @param resultset Curseur de la requete voulue
* @return int Nombre de lignes
......@@ -440,7 +598,7 @@ class DoliDBSqlite
if (! is_object($resultset)) { $resultset=$this->results; }
// mysql necessite un link de base pour cette fonction contrairement
// a pqsql qui prend un resultset
return sqlite_affected_rows($this->db);
return $resultset->rowCount();
}
......@@ -454,7 +612,7 @@ class DoliDBSqlite
// If resultset not provided, we take the last used by connexion
if (! is_object($resultset)) { $resultset=$this->results; }
// Si resultset en est un, on libere la memoire
if (is_object($resultset)) sqlite_free_result($resultset);
if (is_object($resultset)) $resultset->closeCursor();
}
......@@ -558,8 +716,9 @@ class DoliDBSqlite
/**
* \brief Renvoie la derniere requete soumise par la methode query()
* \return lastquery
* Renvoie la derniere requete soumise par la methode query()
*
* @return lastquery
*/
function lastquery()
{
......@@ -567,8 +726,9 @@ class DoliDBSqlite
}
/**
* \brief Renvoie la derniere requete en erreur
* \return string lastqueryerror
* Renvoie la derniere requete en erreur
*
* @return string lastqueryerror
*/
function lastqueryerror()
{
......@@ -576,8 +736,9 @@ class DoliDBSqlite
}
/**
* \brief Renvoie le libelle derniere erreur
* \return string lasterror
* Renvoie le libelle derniere erreur
*
* @return string lasterror
*/
function lasterror()
{
......@@ -585,8 +746,9 @@ class DoliDBSqlite
}
/**
* \brief Renvoie le code derniere erreur
* \return string lasterrno
* Renvoie le code derniere erreur
*
* @return string lasterrno
*/
function lasterrno()
{
......@@ -594,8 +756,9 @@ class DoliDBSqlite
}
/**
* \brief Renvoie le code erreur generique de l'operation precedente.
* \return error_num (Exemples: DB_ERROR_TABLE_ALREADY_EXISTS, DB_ERROR_RECORD_ALREADY_EXISTS...)
* Renvoie le code erreur generique de l'operation precedente.
*
* @return string $error_num (Exemples: DB_ERROR_TABLE_ALREADY_EXISTS, DB_ERROR_RECORD_ALREADY_EXISTS...)
*/
function errno()
{
......@@ -604,8 +767,8 @@ class DoliDBSqlite
return 'DB_ERROR_FAILED_TO_CONNECT';
}
else {
// Constants to convert a MySql error code to a generic Dolibarr error code
$errorcode_map = array(
// Constants to convert error code to a generic Dolibarr error code
/*$errorcode_map = array(
1004 => 'DB_ERROR_CANNOT_CREATE',
1005 => 'DB_ERROR_CANNOT_CREATE',
1006 => 'DB_ERROR_CANNOT_CREATE',
......@@ -615,7 +778,7 @@ class DoliDBSqlite
1044 => 'DB_ERROR_ACCESSDENIED',
1046 => 'DB_ERROR_NODBSELECTED',
1048 => 'DB_ERROR_CONSTRAINT',
1050 => 'DB_ERROR_TABLE_ALREADY_EXISTS',
'HY000' => 'DB_ERROR_TABLE_ALREADY_EXISTS',
1051 => 'DB_ERROR_NOSUCHTABLE',
1054 => 'DB_ERROR_NOSUCHFIELD',
1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
......@@ -636,16 +799,28 @@ class DoliDBSqlite
if (isset($errorcode_map[$this->db->errorCode()]))
{
return $errorcode_map[$this->db->errorCode()];
}
}*/
$errno=$this->db->errorCode();
if ($errno=='HY000')
{
if (preg_match('/table.*already exists/i',$this->error)) return 'DB_ERROR_TABLE_ALREADY_EXISTS';
elseif (preg_match('/index.*already exists/i',$this->error)) return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS';
elseif (preg_match('/syntax error/i',$this->error)) return 'DB_ERROR_SYNTAX';
}
if ($errno=='23000')
{
if (preg_match('/column.* not unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS';
elseif (preg_match('/PRIMARY KEY must be unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS';
}
return ($errno?'DB_ERROR_'.$errno:'0');
}
}
/**
* \brief Renvoie le texte de l'erreur mysql de l'operation precedente.
* \return error_text
* Renvoie le texte de l'erreur mysql de l'operation precedente.
*
* @return string $error_text
*/
function error()
{
......
......@@ -45,10 +45,12 @@ $langs->setDefaultLang($setuplang);
$langs->load("admin");
$langs->load("install");
$choix=0;
if ($dolibarr_main_db_type == "mysql") $choix=1;
if ($dolibarr_main_db_type == "mysqli") $choix=1;
if ($dolibarr_main_db_type == "pgsql") $choix=2;
if ($dolibarr_main_db_type == "mssql") $choix=3;
//if (empty($choix)) dol_print_error('','Database type '.$dolibarr_main_db_type.' not supported into etape2.php page');
// Init "forced values" to nothing. "forced values" are used after a Doliwamp install wizard.
$useforcedwizard=false;
......@@ -188,7 +190,7 @@ if ($action == "set")
{
$buffer=preg_replace('/type=innodb/i','ENGINE=innodb',$buffer);
}
// Replace the prefix tables
if ($dolibarr_main_db_prefix != 'llx_')
{
......@@ -337,7 +339,7 @@ if ($action == "set")
{
$buffer=preg_replace('/llx_/i',$dolibarr_main_db_prefix,$buffer);
}
//print "<tr><td>Creation des cles et index de la table $name: '$buffer'</td>";
$requestnb++;
......@@ -547,7 +549,7 @@ if ($action == "set")
{
$buffer=preg_replace('/llx_/i',$dolibarr_main_db_prefix,$buffer);
}
//dolibarr_install_syslog("Request: ".$buffer,LOG_DEBUG);
$resql=$db->query($buffer);
if ($resql)
......
......@@ -291,13 +291,14 @@ if (! empty($force_install_message))
if ($defaultype=='mysqli' && !function_exists('mysqli_connect')) $defaultype = 'mysql';
// Show line into list
if ($type=='mysql') { $testfunction='mysql_connect'; }
if ($type=='mysqli') { $testfunction='mysqli_connect'; }
if ($type=='pgsql') { $testfunction='pg_connect'; }
if ($type=='mssql') { $testfunction='mssql_connect'; }
if ($type=='sqlite') { $testfunction='notyetready'; }
if ($type=='mysql') { $testfunction='mysql_connect'; $testclass=''; }
if ($type=='mysqli') { $testfunction='mysqli_connect'; $testclass=''; }
if ($type=='pgsql') { $testfunction='pg_connect'; $testclass=''; }
if ($type=='mssql') { $testfunction='mssql_connect'; $testclass=''; }
if ($type=='sqlite') { $testfunction=''; $testclass='PDO'; }
$option.='<option value="'.$type.'"'.($defaultype == $type?' selected="selected"':'');
if (! function_exists($testfunction)) $option.=' disabled="disabled"';
if ($testfunction && ! function_exists($testfunction)) $option.=' disabled="disabled"';
if ($testclass && ! class_exists($testclass)) $option.=' disabled="disabled"';
$option.='>';
$option.=$type.'&nbsp; &nbsp;';
if ($note) $option.=' '.$note;
......@@ -321,7 +322,7 @@ if (! empty($force_install_message))
</tr>
<tr>
<tr class="hidesqlite">
<td valign="top" class="label"><b> <?php echo $langs->trans("Server"); ?>
</b></td>
<td valign="top" class="label"><input type="text"
......@@ -335,7 +336,7 @@ if (! empty($force_install_message))
</tr>
<tr>
<tr class="hidesqlite">
<td valign="top" class="label"><?php echo $langs->trans("Port"); ?></td>
<td valign="top" class="label"><input type="text"
name="db_port<?php print ($force_install_noedit==2 && $force_install_port)?'_bis':''; ?>"
......@@ -348,7 +349,7 @@ if (! empty($force_install_message))
</tr>
<tr>
<tr class="hidesqlite">
<td class="label" valign="top"><?php echo $langs->trans("DatabasePrefix"); ?>
</td>
......@@ -358,7 +359,7 @@ if (! empty($force_install_message))
<td class="comment"><?php echo $langs->trans("DatabasePrefix"); ?></td>
</tr>
<tr>
<tr class="hidesqlite">
<td class="label" valign="top"><?php echo $langs->trans("CreateDatabase"); ?>
</td>
......@@ -369,7 +370,7 @@ if (! empty($force_install_message))
</td>
</tr>
<tr>
<tr class="hidesqlite">
<td class="label" valign="top"><b><?php echo $langs->trans("Login"); ?></b>
</td>
<td class="label" valign="top"><input type="text" id="db_user"
......@@ -378,7 +379,7 @@ if (! empty($force_install_message))
<td class="comment"><?php echo $langs->trans("AdminLogin"); ?></td>
</tr>
<tr>
<tr class="hidesqlite">
<td class="label" valign="top"><b><?php echo $langs->trans("Password"); ?></b>
</td>
<td class="label" valign="top"><input type="password" id="db_pass"
......@@ -387,7 +388,7 @@ if (! empty($force_install_message))
<td class="comment"><?php echo $langs->trans("AdminPassword"); ?></td>
</tr>
<tr>
<tr class="hidesqlite">
<td class="label" valign="top"><?php echo $langs->trans("CreateUser"); ?>
</td>
......@@ -404,13 +405,13 @@ if (! empty($force_install_message))
$force_install_databaserootlogin=preg_replace('/__SUPERUSERLOGIN__/','root',$force_install_databaserootlogin);
$force_install_databaserootpass=preg_replace('/__SUPERUSERPASSWORD__/','',$force_install_databaserootpass);
?>
<tr>
<tr class="hidesqlite">
<td colspan="3" class="label" align="center"><br>
<h3><?php echo $langs->trans("DatabaseSuperUserAccess"); ?></h3>
</td>
</tr>
<tr>
<tr class="hidesqlite">
<td class="label" valign="top"><?php echo $langs->trans("Login"); ?></td>
<td class="label" valign="top"><input type="text" id="db_user_root"
name="db_user_root" class="needroot"
......@@ -427,7 +428,7 @@ if (! empty($force_install_message))
</tr>
<tr>
<tr class="hidesqlite">
<td class="label" valign="top"><?php echo $langs->trans("Password"); ?>
</td>
<td class="label" valign="top"><input type="password"
......
......@@ -55,8 +55,8 @@ insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,no
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (74,'19','19272',3,'CORREZE','Corrèze');
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (94,'2A','2A004',3,'CORSE-DU-SUD','Corse-du-Sud');
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (94,'2B','2B033',3,'HAUTE-CORSE','Haute-Corse');
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (26,'21','21231',3,'COTE-D\'OR','Côte-d\'Or');
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (53,'22','22278',4,'COTES-D\'ARMOR','Côtes-d\'Armor');
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (26,'21','21231',3,'COTE-D OR','Côte-d Or');
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (53,'22','22278',4,'COTES-D ARMOR','Côtes-d Armor');
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (74,'23','23096',3,'CREUSE','Creuse');
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (72,'24','24322',3,'DORDOGNE','Dordogne');
insert into llx_c_departements (fk_region, code_departement,cheflieu,tncc,ncc,nom) values (43,'25','25056',2,'DOUBS','Doubs');
......
......@@ -50,6 +50,6 @@ insert into llx_c_chargesociales (id, libelle, deductible, active, code, fk_pays
--
insert into llx_c_chargesociales (id, libelle, deductible, active, code, fk_pays) values (201, 'ONSS', 1,1,'TAXBEONSS' ,'2');
insert into llx_c_chargesociales (id, libelle, deductible, active, code, fk_pays) values (210, 'Precompte professionnel', 1,1,'TAXBEPREPRO' ,'2');
insert into llx_c_chargesociales (id, libelle, deductible, active, code, fk_pays) values (220, 'Prime d\'existence', 1,1,'TAXBEPRIEXI' ,'2');
insert into llx_c_chargesociales (id, libelle, deductible, active, code, fk_pays) values (220, 'Prime existence', 1,1,'TAXBEPRIEXI' ,'2');
insert into llx_c_chargesociales (id, libelle, deductible, active, code, fk_pays) values (230, 'Precompte immobilier', 1,1,'TAXBEPREIMMO','2');
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment