From 3892da76066a96331598d6641872b973940a187d Mon Sep 17 00:00:00 2001
From: phf <phf@atm-consulting.fr>
Date: Tue, 4 Jul 2017 12:09:56 +0200
Subject: [PATCH] Fix update row on xlsx import do not work as csv import

---
 .../modules/import/import_xlsx.modules.php    | 213 +++++++++++++-----
 1 file changed, 152 insertions(+), 61 deletions(-)

diff --git a/htdocs/core/modules/import/import_xlsx.modules.php b/htdocs/core/modules/import/import_xlsx.modules.php
index 917760dc900..eff3b8f8b21 100644
--- a/htdocs/core/modules/import/import_xlsx.modules.php
+++ b/htdocs/core/modules/import/import_xlsx.modules.php
@@ -292,10 +292,11 @@ class ImportXlsx extends ModeleImports
 	 * @param 	Object	$objimport						Object import (contains objimport->array_import_tables, objimport->array_import_fields, objimport->array_import_convertvalue, ...)
 	 * @param	int		$maxfields						Max number of fields to use
 	 * @param	string	$importid						Import key
+	 * @param	array	$updatekeys						Array of keys to use to try to do update
 	 * @return	int										<0 if KO, >0 if OK
 	 */
 	// What is this doing here ? it is common to all imports, is should be in the parent class
-	function import_insert($arrayrecord,$array_match_file_to_database,$objimport,$maxfields,$importid)
+	function import_insert($arrayrecord,$array_match_file_to_database,$objimport,$maxfields,$importid,$updatekeys)
 	{
 		global $langs,$conf,$user;
         global $thirdparty_static;    	// Specific to thirdparty import
@@ -326,13 +327,15 @@ class ImportXlsx extends ModeleImports
 		else
 		{
 			$last_insert_id_array = array(); // store the last inserted auto_increment id for each table, so that dependent tables can be inserted with the appropriate id (eg: extrafields fk_object will be set with the last inserted object's id)
+			$updatedone = false;
+			$insertdone = false;
 			// For each table to insert, me make a separate insert
 			foreach($objimport->array_import_tables[0] as $alias => $tablename)
 			{
 				// Build sql request
 				$sql='';
-				$listfields='';
-				$listvalues='';
+				$listfields=array();
+				$listvalues=array();
 				$i=0;
 				$errorforthistable=0;
 
@@ -372,7 +375,7 @@ class ImportXlsx extends ModeleImports
 						// Make some tests on $newval
 
 						// Is it a required field ?
-						if (preg_match('/\*/',$objimport->array_import_fields[0][$val]) && ((string) $newval == ''))
+						if (preg_match('/\*/',$objimport->array_import_fields[0][$val]) && ((string) $newval==''))
 						{
 							$this->errors[$error]['lib']=$langs->trans('ErrorMissingMandatoryValue',$key);
 							$this->errors[$error]['type']='NOTNULL';
@@ -399,7 +402,7 @@ class ImportXlsx extends ModeleImports
                                     
                                     if ($isidorref == 'ref')    // If value into input import file is a ref, we apply the function defined into descriptor
                                     {
-                                        $file=$objimport->array_import_convertvalue[0][$val]['classfile'];
+                                        $file=(empty($objimport->array_import_convertvalue[0][$val]['classfile'])?$objimport->array_import_convertvalue[0][$val]['file']:$objimport->array_import_convertvalue[0][$val]['classfile']);
                                         $class=$objimport->array_import_convertvalue[0][$val]['class'];
                                         $method=$objimport->array_import_convertvalue[0][$val]['method'];
                                         if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval] != '')
@@ -408,7 +411,12 @@ class ImportXlsx extends ModeleImports
                                         }
                                         else
 										{
-                                            dol_include_once($file);
+                                            $resultload = dol_include_once($file);
+                                            if (empty($resultload))
+                                            {
+                                                dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method);
+                                                break;
+                                            }
                                             $classinstance=new $class($this->db);
                                             // Try the fetch from code or ref
                                             call_user_func_array(array($classinstance, $method),array('', $newval));
@@ -481,6 +489,26 @@ class ImportXlsx extends ModeleImports
                                     }
                                     if (empty($newval)) $arrayrecord[($key-1)]['type']=-1;	// If we get empty value, we will use "null"
                                 }
+                                elseif ($objimport->array_import_convertvalue[0][$val]['rule']=='getrefifauto')
+                                {
+                                    $defaultref='';
+                                    // TODO provide the $modTask (module of generation of ref) as parameter of import_insert function
+                                    $obj = empty($conf->global->PROJECT_TASK_ADDON)?'mod_task_simple':$conf->global->PROJECT_TASK_ADDON;
+                                    if (! empty($conf->global->PROJECT_TASK_ADDON) && is_readable(DOL_DOCUMENT_ROOT ."/core/modules/project/task/".$conf->global->PROJECT_TASK_ADDON.".php"))
+                                    {
+                                        require_once DOL_DOCUMENT_ROOT ."/core/modules/project/task/".$conf->global->PROJECT_TASK_ADDON.'.php';
+                                        $modTask = new $obj;
+                                        $defaultref = $modTask->getNextValue(null,null);
+                                    }
+                                    if (is_numeric($defaultref) && $defaultref <= 0) $defaultref='';
+                                    $newval=$defaultref;
+                                }                                
+                                
+                                
+                                elseif ($objimport->array_import_convertvalue[0][$val]['rule']=='numeric')
+                                {
+                                    $newval = price2num($newval);
+                                }
 
                                 //print 'Val to use as insert is '.$newval.'<br>';
 						    }
@@ -541,42 +569,37 @@ class ImportXlsx extends ModeleImports
 						}
 
 						// Define $listfields and $listvalues to build SQL request
-						if ($listfields) { $listfields.=', '; $listvalues.=', '; }
-						$listfields.=$fieldname;
+						$listfields[] = $fieldname;
 
 						// Note: arrayrecord (and 'type') is filled with ->import_read_record called by import.php page before calling import_insert
-						if (empty($newval) && $arrayrecord[($key-1)]['type'] < 0)       $listvalues.=($newval=='0'?$newval:"null");
-						elseif (empty($newval) && $arrayrecord[($key-1)]['type'] == 0) $listvalues.="''";
-						else															 $listvalues.="'".$this->db->escape($newval)."'";
+						if (empty($newval) && $arrayrecord[($key-1)]['type'] < 0)		 $listvalues[] = ($newval=='0'?$newval:"null");
+						elseif (empty($newval) && $arrayrecord[($key-1)]['type'] == 0)	 $listvalues[] = "''";
+						else															 $listvalues[] = "'".$this->db->escape($newval)."'";
 					}
 					$i++;
 				}
 
 				// We add hidden fields (but only if there is at least one field to add into table)
-				if ($listfields && is_array($objimport->array_import_fieldshidden[0]))
+				if (!empty($listfields) && is_array($objimport->array_import_fieldshidden[0]))
 				{
     				// Loop on each hidden fields to add them into listfields/listvalues
 				    foreach($objimport->array_import_fieldshidden[0] as $key => $val)
     				{
     				    if (! preg_match('/^'.preg_quote($alias).'\./', $key)) continue;    // Not a field of current table
-    				    if ($listfields) { $listfields.=', '; $listvalues.=', '; }
     				    if ($val == 'user->id')
     				    {
-    				        $listfields.=preg_replace('/^'.preg_quote($alias).'\./','',$key);
-    				        $listvalues.=$user->id;
+    				        $listfields[] = preg_replace('/^'.preg_quote($alias).'\./','',$key);
+    				        $listvalues[] = $user->id;
     				    }
     				    elseif (preg_match('/^lastrowid-/',$val))
     				    {
     				        $tmp=explode('-',$val);
     				        $lastinsertid=(isset($last_insert_id_array[$tmp[1]]))?$last_insert_id_array[$tmp[1]]:0;
-    				        $listfields.=preg_replace('/^'.preg_quote($alias).'\./','',$key);
-                            $listvalues.=$lastinsertid;
+							$keyfield = preg_replace('/^'.preg_quote($alias).'\./','',$key);
+    				        $listfields[] = $keyfield;
+                            $listvalues[] = $lastinsertid;
     				        //print $key."-".$val."-".$listfields."-".$listvalues."<br>";exit;
-    				    } else 
-				    {
-					 $listfields.=preg_replace('/^'.preg_quote($alias).'\./','',$key);
-					 $listvalues.=$val;
-				    }
+    				    }
     				}
 				}
 				//print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
@@ -584,49 +607,114 @@ class ImportXlsx extends ModeleImports
 				// If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
 				if (! $errorforthistable)
 				{
-				    //print "$alias/$tablename/$listfields/$listvalues<br>";
-					if ($listfields)
+					//print "$alias/$tablename/$listfields/$listvalues<br>";
+					if (!empty($listfields))
 					{
-					    //var_dump($objimport->array_import_convertvalue); exit;
-
-						// Build SQL request
-						if (empty($tablewithentity_cache[$tablename]))
-						{
-							$sql ='INSERT INTO '.$tablename.'('.$listfields.', import_key';
-							if (! empty($objimport->array_import_tables_creator[0][$alias])) $sql.=', '.$objimport->array_import_tables_creator[0][$alias];
-							$sql.=') VALUES('.$listvalues.", '".$importid."'";
-						}
-						else
-						{
-							$sql ='INSERT INTO '.$tablename.'('.$listfields.', import_key, entity';
-							if (! empty($objimport->array_import_tables_creator[0][$alias])) $sql.=', '.$objimport->array_import_tables_creator[0][$alias];
-							$sql.=') VALUES('.$listvalues.", '".$importid."', ".$conf->entity ;
+						$updatedone = false;
+						$insertdone = false;
+						if (!empty($updatekeys)) {
+							// We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
+							if (empty($lastinsertid)) {
+								$sqlSelect = 'SELECT rowid FROM '.$tablename;
+								
+								$data = array_combine($listfields, $listvalues);
+								$where = array();
+								$filters = array();
+								foreach ($updatekeys as $key) {
+									$col = $objimport->array_import_updatekeys[0][$key];
+									$key=preg_replace('/^.*\./i','',$key);
+									$where[] = $key.' = '.$data[$key];
+									$filters[] = $col.' = '.$data[$key];
+								}
+								$sqlSelect.= ' WHERE '.implode(' AND ', $where);
+								
+								$resql=$this->db->query($sqlSelect);
+								if($resql) {
+									$res = $this->db->fetch_object($resql);
+									if($resql->num_rows == 1) {
+										$lastinsertid = $res->rowid;
+										$last_insert_id_array[$tablename] = $lastinsertid;
+									} else if($resql->num_rows > 1) {
+										$this->errors[$error]['lib']=$langs->trans('MultipleRecordFoundWithTheseFilters', implode($filters, ', '));
+										$this->errors[$error]['type']='SQL';
+										$error++;
+									} else {
+										// No record found with filters, insert will be tried below
+									}
+								}
+								else
+								{
+									//print 'E';
+									$this->errors[$error]['lib']=$this->db->lasterror();
+									$this->errors[$error]['type']='SQL';
+									$error++;
+								}
+							}
+							
+							if (!empty($lastinsertid)) {
+								// Build SQL UPDATE request
+								$sqlstart = 'UPDATE '.$tablename;
+								
+								$data = array_combine($listfields, $listvalues);
+								$set = array();
+								foreach ($data as $key => $val) {
+									$set[] = $key.' = '.$val;
+								}
+								$sqlstart.= ' SET '.implode(', ', $set);
+								
+								if(empty($keyfield)) $keyfield = 'rowid';
+								$sqlend = ' WHERE '.$keyfield.' = '.$lastinsertid;
+								
+								$sql = $sqlstart.$sqlend;
+								
+								// Run update request
+								$resql=$this->db->query($sql);
+								if($resql) {
+									// No error, update has been done. $this->db->db->affected_rows can be 0 if data hasn't changed
+									$updatedone = true;
+								}
+								else
+								{
+									//print 'E';
+									$this->errors[$error]['lib']=$this->db->lasterror();
+									$this->errors[$error]['type']='SQL';
+									$error++;
+								}
+							}
 						}
-						if (! empty($objimport->array_import_tables_creator[0][$alias])) $sql.=', '.$user->id;
-						$sql.=')';
-                        
-						//print($sql).'<br>';
-						dol_syslog("import_csv.modules", LOG_DEBUG);
-
-						//print '> '.join(',',$arrayrecord);
-						//print 'sql='.$sql;
-						//print '<br>'."\n";
-
-						// Run insert request
-						if ($sql)
-						{
-							$resql=$this->db->query($sql);
-							$last_insert_id_array[$tablename] = $this->db->last_insert_id($tablename); // store the last inserted auto_increment id for each table, so that dependent tables can be inserted with the appropriate id. This must be done just after the INSERT request, else we risk losing the id (because another sql query will be issued somewhere in Dolibarr).
-							if ($resql)
-							{
-								//print '.';
+
+						// Update not done, we do insert
+						if (!$error && !$updatedone) {
+							// Build SQL INSERT request
+							$sqlstart = 'INSERT INTO '.$tablename.'('.implode(', ', $listfields).', import_key';
+							$sqlend = ') VALUES('.implode(', ', $listvalues).", '".$importid."'";
+							if (! empty($tablewithentity_cache[$tablename])) {
+								$sqlstart.= ', entity';
+								$sqlend.= ', '.$conf->entity;
+							} 
+							if (! empty($objimport->array_import_tables_creator[0][$alias])) {
+								$sqlstart.= ', '.$objimport->array_import_tables_creator[0][$alias];
+								$sqlend.=', '.$user->id;
 							}
-							else
+							$sql = $sqlstart.$sqlend.')';
+							dol_syslog("import_xlsx.modules", LOG_DEBUG);
+							
+							// Run insert request
+							if ($sql)
 							{
-								//print 'E';
-								$this->errors[$error]['lib']=$this->db->lasterror();
-								$this->errors[$error]['type']='SQL';
-								$error++;
+								$resql=$this->db->query($sql);
+								if ($resql)
+								{
+								    $last_insert_id_array[$tablename] = $this->db->last_insert_id($tablename); // store the last inserted auto_increment id for each table, so that child tables can be inserted with the appropriate id. This must be done just after the INSERT request, else we risk losing the id (because another sql query will be issued somewhere in Dolibarr).
+								    $insertdone = true;
+								}
+								else
+								{
+									//print 'E';
+									$this->errors[$error]['lib']=$this->db->lasterror();
+									$this->errors[$error]['type']='SQL';
+									$error++;
+								}
 							}
 						}
 					}
@@ -638,6 +726,9 @@ class ImportXlsx extends ModeleImports
 
 			    if ($error) break;
 			}
+
+			if($updatedone) $this->nbupdate++;
+			if($insertdone) $this->nbinsert++;
 		}
 
 		return 1;
-- 
GitLab