Absence des boutons Enregistrer et enregistrer et Fermer

Bonjour,

J’ai une gestion par état : Actif, En suspens, Terminé

L’état Terminé est configuré Terminal et en lecture seule

Depuis l’état Terminé il est possible de revenir à un état Actif ou En suspens

Lorsque je crée un enregistrement, l’état est ACTIF par défaut et j’ai la présence des boutons d’enregistrement

Si je passe à l’état En suspens tout est toujours normal (les boutons sont toujours là)

et quand je passe à Terminé les boutons d’enregistrements ne sont plus présents et les champs sont lecture ==>OK

image

Mais si je reviens à un autre état :

  • les champs redeviennent modifiables
  • les boutons d’enregistrements ne reviennent pas

Pouvez-vous me dire ce que je configure faux?

Merci

Fabrice Mouttet

Ou est-ce que le mieux c’est de passer par une méthode qui défini les champs en lecture seule ou en modification selon l’état ?
Mais dans ce cas, comment masquer les boutons Enregistrer et Enregistrer et fermer lorsque l’état terminal est affiché?

Un état “terminal” est un état final définitif dont on est pas sensé revenir

De ce que je comprends votre état “Terminé” dont on peut visiblement revenir n’est pas un état “terminal” mais plutôt un simple état en “lecture seule” :

PS: Merci de toujours indiquer la version exacte x.y.z sur laquelle vous nous sollicitez

Hello David,

Merci pour la réponse.
J’ai pensé que Terminal n’était peut-être pas ce que je voulais. Je suis donc déjà revenu en arrière sur ce point, mais ça n’a rien changé, les boutons ne reviennent pas.

et je travaille avec la v6.2.11

La présence des boutons “Enregistrer” peut être conditionnée par le hook isUpdateEnable.

Le fait que les boutons restent abusivement masqués pas ne nous dit rien. Nous allons faire des tests sur ce point mais si ça se trouve vous avez déjà implémenté des choses dans le hook ci-dessus et/ou sous forme de contraintes ?

PS: @Francois me précise qu’un état “terminal” n’est pas forcément final définitif au sens métier, cette notion sert avant tout à calculer les temps écoulés entre le début et la fin d’un workflow d’état

Je n’ai pas de hook isUpdateEnable mais j’ai des contraintes sur la visibilité de certains champs en fonction des valeurs dans d’autres champs

Les contraintes sur la visibilité des attributs ne jouent pas sur la présence des boutons “Enregistrer”.

Peut être avez vous du code qui joue dynamiquement sur les droits sur l’objet en question (ce qui serait une mauvaise approche) ? Ca pourrait expliquer une “perte” persistante des droits de mise à jour sur l’objet

le code est léger :

public class CourrierSGSEBoCourrier extends ObjectDB {
	private static final long serialVersionUID = 1L;
	
	
	
	public void afficheSuspens(){
			AppLog.info(getClass(), " la fonction afficheSuspens a été appelée", null , getGrant());

			this.setFieldFilter("CourrierSGSEBoCourrierButLibelle", "SUSP");
			this.setFieldFilter("CourrierSGSEBoCourrierRechercheDate", "non");
	}
	
	@Override
	public void initUpdate(){
	
		setToken();
	}

	@Override
	public String postSave() {
			AppLog.info(getClass(), " postSave a été appelée", null , getGrant());
			
			boolean sauvegarde = false;
	
			//renseigne la date de fin si le courrier passe à TERMINE
			if (this.getFieldValue("CourrierSGSEBoCourrierEnOrdre").equals("TER") && this.getFieldValue("CourrierSGSEBoCourrierDateSuspens").equals("") ) {
				    AppLog.info(getClass(), "MAJ de la date de fin", null, getGrant());
					this.getField("CourrierSGSEBoCourrierDateSuspens").setValue(Tool.getCurrentDatetime());
					sauvegarde = true;
			}			
	
			//Efface la date de fin si le statut est ACTIF ou EN SUSPENS
			if ( (this.getFieldValue("CourrierSGSEBoCourrierEnOrdre").equals("ACT") || this.getFieldValue("CourrierSGSEBoCourrierEnOrdre").equals("ENS") ) && !this.getFieldValue("CourrierSGSEBoCourrierDateSuspens").equals("") ) {
				    AppLog.info(getClass(), "Effacement de la date de fin", null, getGrant());
					this.getField("CourrierSGSEBoCourrierDateSuspens").setValue("");
					sauvegarde = true;
			}			
	
			//met le courrier automatiquement à EN SUSPENS si le but du courrier est REPS, REPD ou REPMUN et que l'état est ACTIF
			if (this.getFieldValue("CourrierSGSEBoCourrierEnOrdre").equals("ACT") && (this.getFieldValue("CourrierSGSEBoCourrierButLibelle").equals("REPD") || this.getFieldValue("CourrierSGSEBoCourrierButLibelle").equals("REPS")  || this.getFieldValue("CourrierSGSEBoCourrierButLibelle").equals("REPMUN") )) {
				    AppLog.info(getClass(), "MAJ statut actif vers en suspens", null, getGrant());
					this.getField("CourrierSGSEBoCourrierEnOrdre").setValue("ENS");
					sauvegarde = true;
			}			
	
		  // Sauvegarde si au moins une modification a été faite
		    if (sauvegarde) {
		        try {
		            getTool().validateAndSave();
		        } catch (SaveException | ValidateException e) {
		            AppLog.error(e, getGrant());
		        }
		    }
	
		return super.postSave();
	}
			

	public void setToken(){
		/********************************************************
		Envoi d'une demande de token pour accèder à la GED. Le script paramètre une demande GET via une url (Oauth 2.0, HEADER, Bearer numéro du bearer) 
		Le n° du bearer est transmis par DBAS, il est propre à chaque environnement. 
		L'url est transmise par DBAS, elle est propre à chaque environnement
		Ces deux informations sont dans des paramètres systèmes qui sont récupérés ci-dessous
		**********************************************************/
		
  		AppLog.info(getClass(), " le setToken a été appelé", null ,  getGrant());
    	BufferedReader reader = null;
    	ObjectDB ent = this; //travaillera sur l'objet à l'écran
    
    	try {

	        String paramenv = getGrant().getParameter("VDL_ENV");
	        String env="";
	        if (paramenv.equals("-prod"))
	         env="";
	         else
	         env= paramenv;
	
	  		AppLog.info(getClass(), "Environnement de travail :::::: ", env ,  getGrant());
	  		AppLog.info(getClass(), " Variable Environnement de travail :::::: ", paramenv ,  getGrant());
	
	        // 1re ETAPE : récupérer le bearer et l'url pour l'obtention du token
	        //les informations sont stockées dans les paramètres système
	        
	        String bearer = (getGrant().getParameter("VDL_BEARER_COURRIERSGSE"+paramenv)); // récupération de l'url dans le paramètre système
	  		AppLog.info(getClass(), "BEARER :::::: ", bearer ,  getGrant());
	  		AppLog.info(getClass(), "BEARER 2 :::::: ", "VDL_BEARER_COURRIERSGSE"+paramenv ,  getGrant());

	        //String bearer = "toto"; // récupération de l'url dans le paramètre système
	        URL url = new URL (getGrant().getParameter("VDL_GEDTOKEN_COURRIERSGSE_URL").replace("{env}", env));// récupération de l'url dans le paramètre système
	        
	        AppLog.info(getClass(), "url pour le token : " + url, null ,  getGrant());
			AppLog.info(getClass(), "bearer : " + bearer, null ,  getGrant());
			
			//2e ETAPE : connexion 
	        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
	        
			AppLog.info(getClass(), "step 1 " +conn, null ,  getGrant());
			
			//déclaration HEADER
			conn.setRequestProperty("Content-Type","application/json");
			
			//Ajout des informations pour l'authentification Oauth 2.0 soit "Bearer + n°", le n° est le même pour toutes les requêtes et nous est transmis par DBAS
	        conn.setRequestProperty("Authorization", bearer);
	        
	        conn.setRequestMethod("GET");
	        
	        //3e ETAPE : récupération de la réponse
			//récupération du statut de la demande : 200 = OK
	        int responseCode = conn.getResponseCode();
	       
	       
			AppLog.info(getClass(), "step 1.1 " +responseCode, null ,  getGrant());
			AppLog.info(getClass(), "step 1.2 " +conn.getInputStream(), null ,  getGrant());
			
			//récupération du token
	        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
	        
	        String output=null,line=null;
			AppLog.info(getClass(), "step 2 " , null ,  getGrant());
			
	        while ((line = in.readLine()) != null) {
	            output=line;
	            AppLog.info(getClass(), "step 3 " , null ,  getGrant());
	        }
			
	        in.close();
	       	AppLog.info(getClass(), "reponse : " + output, null ,  getGrant());
	       	
			/**le token est placé dans la rubrique liée au token pour une récupération
	       	dans le javascript pour l'affichage de la GED
			**********************************************************
			!! ADAPTER LE NOM de l'attribut en fonction  de la table */
			setFieldValue("CourrierSGSEBoCourrierToken", output);


    		} catch (Exception e) {
    			AppLog.error(getClass(), "erreur", "Unable to token", e, getGrant());
			
    		}
    		
	}



	@Override
	public  void  initCreate() {
		/** A la création d'une nouvelle fiche, le n° est calculé en tenant compte du dernier n° attribué pour la date du jour.
		 * Chaque jour il recommence à 1
		 * La date du jour est automatiquement saisie
		 * Ces deux valeurs peuvent être surchargées par l'utilisateur
		*/
		try
		{
		AppLog.info(getClass(), " le initCreate a été appelé", null ,  getGrant());
		
		/*Cherche le dernier n° pour la date du jour = la valeur max pour aujourd'hui*/
		String sql = "select max(courrier_sgse_courrier_numero) from t_courriersgse_courrier where courrier_sgse_courrier_date_courrier = DATE(NOW())"; 
		long max = this.getGrant().simpleQueryAsLong(sql);
		
		LocalDateTime currentTime = LocalDateTime.now();
		LocalDate date1 = currentTime.toLocalDate();
		
		

		/*Rempli les champs */
		this.setFieldValue("CourrierSGSEBoCourrierDateCourrier" , date1);
		this.setFieldValue("CourrierSGSEBoCourrierNumero" , max + 1);
//		this.setFieldValue("CourrierSGSEBoCourrierButLibelle","ACT");
	
		
		
		AppLog.info(getClass(), "nb de rec " + max , null ,  getGrant());
		AppLog.info(getClass(), "date du jour  :   " + date1, null ,  getGrant());
		AppLog.info(getClass(), "idCourrier  :   " + this.getFieldValue("CourrierSGSEBoCourrierDateCourrier")+this.getFieldValue("CourrierSGSEBoCourrierNumero"), null ,  getGrant());
		
		
		}  catch (Exception e) {
			AppLog.error(getClass(), "initCreate erreur", null, e, getGrant());
		}
		
	}
	
	public String ajouteLigne() {
		//boucle sur tous les REC pour mettre à jour la rubrique concerne en remplaçant les " $ par des sauts de lignes
		AppLog.info(getClass(), " la fonction ajouteLigne a été appelée", null ,  getGrant());

		
		
		//initialise la liste et le tableau
		List<String> ids  = this.getSelectedIds();
		List<String[]> rows  = new ArrayList<String[]>();

		//AppLog.info(getClass(), " la liste des ids est prête : " + ids, null ,  getGrant());
		
		//rempli le tableau avec les id des lignes
		if( ids!=null && ids.size()>0){
			for (int k = 0; k < ids.size(); k++){
		       if (this.select(ids.get(k))){
						rows.add(this.getValues());
						
		       }
			}
		}else{
			rows = this.search(false);
			
			AppLog.info(getClass(), "postLoad", "Courrier: " + getInstanceName() +" user: this line is geting the selected values" + rows.size(), null);
		}
		
		AppLog.info(getClass(), " la liste des rows est prête : " + rows, null ,  getGrant());
		
		//déclaration de l'objet
	
		ObjectDB Courrier =  getGrant().getTmpObject("CourrierSGSEBoCourrier");
		BusinessObjectTool t = new BusinessObjectTool(Courrier);	
		
			for (String[] row : rows)
			{
				Courrier.setValues(row); //précise sur quel row travailler
				try{
					
				//AppLog.info(getClass(), " row : " + row[12], null ,  getGrant());
				String ancienconcerne = row[6];//la colonne 12 est le "concerne"
				
				Courrier.setFieldValue("CourrierSGSEBoCourrierConcerne",  ancienconcerne.replace(" $ ", "\r\n"));
				//AppLog.info(getClass(), " comm concerne 6 : " + ancienconcerne, null ,  getGrant());
				
				String anciencomm10 = row[10];//la colonne 12 est le "concerne"
				Courrier.setFieldValue("CourrierSGSEBoCourrierCommentaire",  anciencomm10.replace(" $ ", "\r\n"));
				//AppLog.info(getClass(), " comm suivi 10 : " + anciencomm10, null ,  getGrant());
			
				t.validateAndSave();
				}catch(Exception e){
		        	AppLog.warning(getClass(), "refreshData", "Erreur updating Courrier (" + e.getMessage() + ")", e, getGrant());
		        }				

			}

	return "Correction faite " +  " sur " + rows.size() + " courrier-s concernée-s";  
	}	


}

Je n’a i pas l’impression que ça pourrait coincer.

Après des tas de tests, je peux préciser mon point :

Lorsqu’un enregistrement est "Terminé " les champs passent en lecture seule et les boutons Enregistrer et Enregistrer sous ne sont plus visibles.

  1. Je reste sur l’enregistrement et je reviens au statut ACTIF ==> le statut change mais les boutons Enregistrer et Enregistrer sous restent invisibles
  2. Je reviens en vue Liste
  3. J’ouvre de nouveau l’enregistrement ==> cette fois les boutons Enregistrer et Enregistrer sous sont visibles

Bonjour,

C’est potentiellement une boucle infinie, car le postSave faire un save sur lui-même.
pourquoi ne pas juste setter les valeurs au preSave, sans refaire ce validate&save redondant ?
Simplicité détecte les boucle infinies / stack overflow, mais autant faire mieux pour éviter ce risque.

Non c’est lorsque qu’il y a le flag Read only fields sur l’état, et qui laisse la mise à jour possible pour changer d’état.
La notion de Terminal sur un état est métier (pour calculer la durée d’un process) et n’influence rien côté UI. Simplicité autorise à ce qu’un état terminal revienne en arrière via transition.

Merci François.
J’ai corrigé avec le presave, merci.

ça n’a pas d’influence sur le fait que les boutons ne s’affichent pas lorsque je reviens à un état antérieur. Je dois quitter l’enregistrement et revenir dessus pour qu’ils s’affichent.

Mais ce point n’est pas bloquant du coup, Je clos le ticket.

This topic was automatically closed 60 minutes after the last reply. New replies are no longer allowed.