Export Excel et la conservation des types (texte, décimal, etc.)

Export Excel et la conservation des types (texte, décimal, etc.)
0
Tags: #<Tag:0x00007f394d9372d0>

Bonjour,

Je fais un export Excel et tout va “presque bien” :-)… le petit hic c’est que les données de type Décimal (double) dans ma table se retrouve de type texte dans Excel. Je pensais que le format défini dans Simplicité se retrouverait aussi dans Excel…

Ce n’est pas aussi simple que ça?

Merci

Fabrice

Normalement ça devrait. On parle d’un export Excel standard en XLSX ?

Oui les types (text, date et numeric) sont normalement bien supportés dans l’export via Apache POI grâce à des types/styles prédéfinis du classeur.

  • quelle est votre version d’excel ?
  • la langue de Simplicité et celle d’Excel ?
  • et aussi la définition de votre champ (type, taille, précision…) ?

Afin de pouvoir reproduire le problème.

L’import est utilisé sur les versions Excel 2010 et 2013 : même problèmatique
Les champs sont définis Décimal (double) avec une longueur de 11
Simplicité et Excel en français

et le code :

package com.simplicite.commons.domseco;
import com.simplicite.objects.domseco.*;

import java.util.*;
import com.simplicite.util.*;
import com.simplicite.util.tools.*;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Header; 

/**
 * Shared code DomsecoExportHandler
 */
public class DomsecoExportHandler implements java.io.Serializable {
	private static final long serialVersionUID = 1L;
	
	private static final String[] HEADERS = {"numeroPersonne","confidentiel","nomOfficiel","prenomOfficiel","dateNaissance","statutHabitant","typeResidence","typeRepresentant",
			"sexe","etatCivil","dateDebut","activiteExercee","employeur","dateDebutSejour","lieuProvenance","paysProvenance","dateTransfertResidence","dateEtablissement",
			"dateValidite","dateEcheanceSejourSecondaire","lieuDeclarationDomicile","paysDeclarationDomicile","dateFinSejour","causeFinSejour","voieNumero","titre","complement1",
			"complement2","mentionDistribution","numeroPostal","complementNPA","localite","pays","typeAdresse","numeroMenage","numeroContribuable","anneeImposition",
			"etatDossier","cantonPrecedent","date envoi questionnaire","conjoint 1 - nom","conjoint 1 - prenom","conjoint 2 - nom","conjoint 2 - prenom","concubin",
			"anneeFinImposition", "1er - anneeTaxation","1er - montantImposition","2e - anneeTaxation","2e - montantImposition","3e - anneeTaxation","3e - montantImposition",
			"4e - anneeTaxation","4e - montantImposition",	"5e - anneeTaxation", "5e - montantImposition",
			"dateEvenement","typeEvenement","dateEcheance","typeEcheance","dateRemarque","typeRemarque" };
			
	private Grant grant; 
	private DomsecoHabitant habitant;
	
	private ExcelPOITool xls;
	private ExcelPOITool.ExcelSheet sheet ;
	
	private int rowNum = 0;
	
	public DomsecoExportHandler(Grant grant){
		this.grant=grant;
	}
	
	
	public void writeHeader()  throws Exception{	
		
		xls	 = new ExcelPOITool(true); 
		sheet 	 = xls.newSheet("Statistique");
		sheet.defaultCellWidth = 20;
		
		ExcelPOITool.ExcelRow row= xls.newRow(rowNum++);
	  
		for ( int i=0;  i< HEADERS.length; i++){
			ExcelPOITool.ExcelCell cell = xls.newCell(i, HEADERS[i]);	
			row.add( cell );
		}
		sheet.add(row);
	}
	
	public byte[] exportContent() throws Exception{
		
		//Get all habitants
		DomsecoHabitant habitant = (DomsecoHabitant) grant.getTmpObject("DomsecoHabitant");
		habitant.resetFilters();
		List<String[]> habitants = habitant.search();
  
		DomsecoEcheance echeance = (DomsecoEcheance) grant.getTmpObject("DomsecoEcheance");
		DomsecoEvenement evenement = (DomsecoEvenement) grant.getTmpObject("DomsecoEvenement");
		DomsecoRemarque remarque = (DomsecoRemarque) grant.getTmpObject("DomsecoRemarque");
		
		int counter=0;
		for (String[] hab : habitants){
			counter++;
			int columnNum = 0;
			
			ExcelPOITool.ExcelRow row= xls.newRow(rowNum++) ;
			
			//Ignore the last 10 columns
			for (int j=1 ; j<hab.length-9; j++){ 
				
				ExcelPOITool.ExcelCell cell;
				
				//numeroPersonne
				if(j==1){		cell = xls.newCell( columnNum++, hab[j], ExcelPOITool.TYPE_NUMERIC   ) ;}
				
				//confidentiel
				else if(j==2){	cell = xls.newCell( columnNum++, (hab[j].trim().equals("1") ? "oui": "non")) ;}
				
				//date columns 
				else if(j==5 || j==11 || j==14 || j==17 || j==18 || j==19 || j==20 || j==23 || j==40 ){
					cell = xls.newCell( columnNum++,  DomsecoUtil.formatDate ( hab[j] ,"yyyy-MM-dd")) ;
				}
		
				//list columns 
				else if(j==6){	cell = xls.newCell( columnNum++,  DomsecoUtil.getListValueByCode("DOMSECOLIST_HABITANT_StatutHabitant" , hab[j] ,grant)) ;}
				
				else if(j==7){	cell = xls.newCell( columnNum++, DomsecoUtil.getListValueByCode("DOMSECOLIST_HABITANT_TypeResidence" , hab[j] ,grant))  ;}
				
				else if(j==9){	cell = xls.newCell( columnNum++, DomsecoUtil.getListValueByCode("DOMSECOLIST_HABITANT_Sexe" , hab[j] ,grant))   ;}
				
				else if(j==10){	cell = xls.newCell( columnNum++, DomsecoUtil.getListValueByCode("DOMSECOLIST_HABITANT_EtatCivil" , hab[j] ,grant)) ;}

				else if(j==24){	cell = xls.newCell( columnNum++,  DomsecoUtil.getListValueByCode("DOMSECOLIST_HABITANT_CauseFinSejour" , hab[j] ,grant)) ;}

				else if(j==26){	cell = xls.newCell( columnNum++,   DomsecoUtil.getListValueByCode("DOMSECOLIST_HABITANT_Titre" , hab[j] ,grant)) ;}

				else if(j==38){	cell = xls.newCell( columnNum++,   DomsecoUtil.getListValueByCode("DOMSECOLIST_HABITANT_EtatDossier" , hab[j] ,grant)) ;}

				else if(j==45){	cell = xls.newCell( columnNum++,  (hab[j].trim().equals("1") ? "oui": "non")) ;}
				
				else if(j==48){	 	cell = xls.newCell( columnNum++, hab[j] ); 	}
				
				else{
					cell = xls.newCell( columnNum++, hab[j] );
				}
				
				row.add( cell );
			}
		 
	
			String noEvent = grant.simpleQuery("select row_id from T_DomsecoEvenement where Domseco_Evenement_Habitant_FK='"+hab[0]+"' ORDER BY Domseco_Evenement_DateEvenement desc limit 1" );
			if(noEvent!=null && noEvent.length()>0){
				if(evenement.select(noEvent)){
					ExcelPOITool.ExcelCell cell1 = xls.newCell( columnNum++, DomsecoUtil.formatDate ( evenement.getField("DomsecoBoEvenementDateEvenement").getValue() ,"yyyy-MM-dd") );
					ExcelPOITool.ExcelCell cell2 = xls.newCell( columnNum++, DomsecoUtil.getListValueByCode("DOMSECOLIST_EVENEMENT_TypeEvenement" , evenement.getField("DomsecoBoEvenementTypeEvenement").getValue() ,grant) );
					row.add( cell1 );
					row.add( cell2 );
				}
			}else{ columnNum+=2;}

			
			String noEcheance = grant.simpleQuery("select row_id from T_DomsecoEcheance where Domseco_Echeance_Habitant_FK='"+hab[0]+"' ORDER BY Domseco_Echeance_DateEcheance desc limit 1" );
			if(noEcheance!=null && noEcheance.length()>0){
				if(echeance.select(noEcheance)){
					ExcelPOITool.ExcelCell cell1 = xls.newCell( columnNum++, DomsecoUtil.formatDate ( echeance.getField("DomsecoBoEcheanceDateEcheance").getValue() ,"yyyy-MM-dd")  );
					ExcelPOITool.ExcelCell cell2 = xls.newCell( columnNum++, DomsecoUtil.getListValueByCode("DOMSECOLIST_ECHEANCE_TypeEcheance" , echeance.getField("DomsecoBoEcheanceTypeEcheance").getValue() ,grant) );
					row.add( cell1 );
					row.add( cell2 );
				}
			}else{ columnNum+=2;}
			
			String noRemarque = grant.simpleQuery("select row_id from T_DomsecoRemarque where Domseco_Remarque_Habitant_FK='"+hab[0]+"' ORDER BY Domseco_Remarque_DateRemarque desc limit 1" );
			if(noRemarque!=null && noRemarque.length()>0){
				if(remarque.select(noRemarque)){
					ExcelPOITool.ExcelCell cell1 = xls.newCell( columnNum++, DomsecoUtil.formatDate ( remarque.getField("DomsecoBoRemarqueDateRemarque").getValue() ,"yyyy-MM-dd")  );
					ExcelPOITool.ExcelCell cell2 = xls.newCell( columnNum++, remarque.getField("DomsecoBoRemarqueTypeRemarque").getValue());
					row.add( cell1 );
					row.add( cell2 );
				}
			}else{ columnNum+=2;}
			
			sheet.add(row);
			
			//break statement used only during test to limit exported lines of data: TO BE REMOVED IN VALI AND PROD
			//if( counter == 5000) break;
		}
		xls.add(sheet);
		return xls.generateToByteArray();
	}
	
	
}

OK on parle d’un export Excel séecifique, pas des exports Excel standards. Quand vous parlez de code spécifique il faut le préciser et copier/coller le code en question.

En l’ocurrence pour les cellules numériques vous devez utiliser:

new ExcelCell(i, val, CellType.NUMERIC)

ou, mieux:

newCell(i, val);

Pour lequel si val est numérique, (ìnt,long,float,double`) cela générera bien une cellule de type numérique.

Désolé, j’essaierai d’être plus précis dans mes posts. Il s’agit effectivement d’un export spécifique.

D’après ton exemple newCell(i, val); il me semble que le code ci-dessous est correct avec un val numérique dans Simplicité (en l’occurrence il s’agit du n° de personne défini entier, longueur 11):

if(j==1){		cell = xls.newCell( columnNum++, hab[j]  ) ;} 

il devrait se retrouver numérique dans Excel, or il sort comme un texte
image

Non votre variable est un tableau de string: String[] hab, donc hab[j] est un string. Le newCell(int, String) que vous appelez générera donc une cellule textuelle.

Si vous voulez que ce string soit reconnu comme une valeur numérique vous devez la parser explicitement dans le type numérique approprié: Tool.parseInt(hab[j]) ou Tool.parseLong(hab[j]) ou Tool.parseFloat(hab[j]) ou Tool.parseDouble(hab[j]), ainsi vous appellerez un des newCell(int, int|long|float|double) qui générera une cellule numérique.

Sinon pour bénéficier d’une logique “automatique” utilisez plutôt le newCellqui prend un field Simplicité:

newCell(int cellIndex, ObjectField field, String value)

Cette méthode génèrera le type de cellule qui va bien en fonction du type du field.

Ok. donc si j’ai bien compris l’affichage du n° de personne devient :

if(j==1){ cell = xls.newCell( columnNum++, Tool.parseInt(hab[j]) ) ;}

ou pour la logique automatique :

if(j==1){ cell = xls.newCell(int columnNum++, “DomsecoBoHabitantNumeroPersonne”, hab[j])

Oui pour le 1er

Non pour le 2ème, le 2ème argument de cette méthode est, comme indiqué, un ObjectField (pas un String avec le nom d’un field ce qui n’a pas de sens en dehors du contexte d’un objet).

PS: merci d’utiliser la syntaxe Markdown dans vos posts, notamment pour vos copier/coller de code sinon c’est pas très lisible

Je pense que vous avez oublié de spécifier le style pour la cellule. Le type n’est pas suffisant.
Un classeur Excel contient la liste des définitions “pré-cablées” des styles d’affichage (voir les constantes de ExcelPOITool). Exemple pur un numeric sur fond blanc :

row.add(xls.newCell(c++, value, ExcelPOITool.TYPE_NUMERIC, ExcelPOITool.NUMERIC_CELL_WHITE));

J’ai aussi trouvé la liste des constantes de ExcelPOITool, mais le fait de préciser un style d’affichage n’a rien changé… sauf la couleur de la cellule et une bordure, mais le type est resté standard.

Je reproduis effectivement le pb avec un attribut de type integer en P24.

La librairie POI est régulièrement mise à jour, je soupçonne un pb à ce niveau. Je vous tiens au courant.

Bonsoir David,
des utilisateurs me remontent également en P23 des cellules numériques stockées sous forme de texte (export standard Simplicité de tableaux croisés).

Sur l’export de liste pas de soucis en P24, même le rendering “Francs suisse” fonctionne :

Par contre le format ne semble pas le bon (text) en export de tableau croisé de type “count rows” (sans attribut lié à l’agrégat).

C’est le même soucis que l’usage de l’API Excel directe sans passer un ObjectField en paramètre.
Dans certains cas, il y avait un fallback qui générait du string par défaut, ce sera corrigé en P23 et P24. Mais il est préférable de spécifier le champ (ObjectField de l’objet lié à la valeur) quand c’est possible en dernier argument du newCell).

Avec les corrections de @francois je ne vois plus de pb à ce niveau.
Tout a été poussé sur les templates et images Docker. Il ne vous reste donc qu’à vous mettre à jour.

Merci pour vos tests et les infos.

Quand on parle de mise à jour de la P24, il s’agit d’une version beta?

Comme @francois l’a dit la correction a été faite en alpha (P24) mais a aussi été backportée sur la release (P23).

Je ne sais pas où vous en êtes dans la mise en place de vos processus d’upgrade spécifiques mais appliquer une mise à jour de la release devrait une formalité (et, pour rappel, ce n’est pas facultatif, la preuve). Sur les serveurs managés (SIM) connectés à notre repo Git privé les upgrades se font automatiquement.

Merci de nous indiquer la date et la révision de votre instance pour qu’on puise vérifier où vous en êtes (le plus simple pour avoir cette info c’est d’aller dans Exploitation > Accueil ou d’appeler l’URL /health)

Ok merci pour l’astuce URL /health… nous sommes en P23.

Non la version ce n’est pas suffisant pour savoir où vous en êtes car comme indiqué on pousse des corrections régulièrement (donc la P23 d’il y a 2 jour n’est pas la P23 d’aujourd’hui !)

J’ai donc surtout besoin de la révision, exemple tiré du /health, ex:

Version=4.0.P23
BuiltOn=2019-07-16 23:07 (revision 2a2a08a3ec3c45bfa737f109e324e1253d04b252)