Bonjour,
j’ai fait beaucoup de tests avec les fichiers de liens xml pour en comprendre les règles, mais il y a toujours des points qui ne sont pas clairs (j’ai déjà lu la documentation présente ici de multiples fois mais rien ne précise les différentes utilisations des attributs des balises).
Une des fonctions que j’ai essayé de créer plusieurs fois est un import qui va créer les objets dont le code n’est pas présent dans Axelor, mais mettre à jour ceux qui le sont. Ce fichier xml a apporté le meilleur résultat :
<?xml version="1.0" encoding="UTF-8"?>
<csv-inputs xmlns="http://axelor.com/xml/ns/data-import"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/data-import http://axelor.com/xml/ns/data-import/data-import_5.4.xsd">
<input file="produits.csv" separator=";" type="com.axelor.apps.base.db.Product"/>
<input file="produits.csv" separator=";" type="com.axelor.apps.base.db.Product" search="code = :code" update="true"/>
</csv-inputs>
mais le premier tag <input/>
essaye d’ajouter des objets dont le code existe déjà, ce qui pose un problème de contrainte « UNIQUE » SQL pendant l’import et génère des tracebacks qui ralentissent l’import. Existe-t-il un moyen d’obtenir un meilleur résultat?
J’ai aussi un import plus complexe pour les nomenclatures (bill of material) qui pose le même problème : le traceback indique que l’import essaye de créer un produit dont le code est déjà utilisé, cependant, d’après ce que j’ai compris des attributs du tag <input/>
, Axelor ne devrait que mettre à jour les objets existants. Voici le xml en question :
<?xml version="1.0" encoding="UTF-8"?>
<csv-inputs xmlns="http://axelor.com/xml/ns/data-import"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/data-import http://axelor.com/xml/ns/data-import/data-import_5.4.xsd">
<input file="nomenclatures.csv" separator=";" type="com.axelor.apps.production.db.BillOfMaterial">
<bind column="name" to="name"/>
<bind column="name" to="fullName"/>
<bind to="product" search="self.code = :product">
<bind column="product" to="code"/>
</bind>
<bind to="company" search="self.code = :company">
<bind column="company" to="code"/>
</bind>
<bind column="qty" to="qty"/>
<bind to="unit" search="self.name = :unit">
<bind column="unit" to="name"/>
</bind>
<bind column="defineSubBillOfMaterial" to="defineSubBillOfMaterial"/>
<bind eval="3" to="statusSelect"/>
<bind to="prodProcess" if="!prodProcess.empty">
<bind column="prodProcess" to="fullName"/>
<bind column="prodProcess" to="name"/>
<bind column="prodProcess" to="code"/>
<bind to="product" search="self.code = :product">
<bind column="product" to="code"/>
</bind>
<bind to="company" search="self.code = :company">
<bind column="company" to="code"/>
</bind>
<bind to="outsourcing" eval="!subcontractor.empty"/>
<bind eval="3" to="statusSelect"/>
<bind to="subcontractors" search="self.description = :subcontractor"
if="!subcontractor.empty" update="true">
<bind to="isSubcontractor" eval="true"/>
</bind>
<bind to="workshopStockLocation" search="self.name = :stockLocation" if="!stockLocation.empty">
<bind column="stockLocation" to="name"/>
</bind>
<bind to="workshopStockLocation" search="self.name = 'Atelier inconnu'" if="stockLocation.empty">
<bind eval="'Atelier inconnu'" to="name"/>
</bind>
</bind>
<bind to="workshopStockLocation" search="self.name = :stockLocation" if="!stockLocation.empty">
<bind column="stockLocation" to="name"/>
</bind>
<bind to="workshopStockLocation" search="self.name = 'Atelier inconnu'" if="stockLocation.empty">
<bind eval="'Atelier inconnu'" to="name"/>
</bind>
</input>
<input file="nomenclatures.csv" separator=";" type="com.axelor.apps.base.db.Product"
search="self.code = :product" update="defineSubBillOfMaterial.equals('true')">
<bind to="defaultBillOfMaterial" search="self.name = :name" if="defineSubBillOfMaterial.equals('true')"/>
<bind to="unit" search="self.name = :unit">
<bind column="unit" to="name"/>
</bind>
</input>
</csv-inputs>
Je suppose que cette erreur est générée par le fait que defineSubBillOfMaterial.equals("true")
peut être false
, mais la situation <input if="false"/>
n’est pas documentée pour valider cette hypothèse.
EDIT : voici un des tracebacks générés par l’import des nomenclatures ci-dessus :
com.axelor.exception.AxelorException: The line cannot be imported (import : import nomenclatures)
at com.axelor.apps.base.service.imports.listener.ImporterListener.handle(ImporterListener.java:85)
at com.axelor.data.csv.CSVImporter.process(CSVImporter.java:325)
at com.axelor.data.csv.CSVImporter.process(CSVImporter.java:226)
at com.axelor.data.csv.CSVImporter.run(CSVImporter.java:198)
at com.axelor.apps.base.service.imports.importer.ImporterCSV.process(ImporterCSV.java:37)
at com.axelor.apps.base.service.imports.importer.Importer.run(Importer.java:113)
at com.axelor.apps.base.service.imports.importer.Importer.run(Importer.java:120)
at com.axelor.apps.base.service.imports.ImportService.run(ImportService.java:37)
at com.axelor.apps.base.web.ImportConfigurationController.run(ImportConfigurationController.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.axelor.meta.ActionHandler.call(ActionHandler.java:251)
at com.axelor.meta.schema.actions.ActionMethod.evaluate(ActionMethod.java:76)
at com.axelor.meta.schema.actions.Action.execute(Action.java:100)
at com.axelor.meta.schema.actions.Action.wrap(Action.java:109)
at com.axelor.meta.schema.actions.ActionGroup.evaluate(ActionGroup.java:231)
at com.axelor.meta.schema.actions.Action.execute(Action.java:96)
at com.axelor.meta.schema.actions.Action.wrap(Action.java:109)
at com.axelor.meta.ActionHandler.execute(ActionHandler.java:519)
at com.axelor.meta.ActionExecutor.execute(ActionExecutor.java:47)
at com.axelor.meta.ActionExecutor$$EnhancerByGuice$$6c24d2b3.CGLIB$execute$0(<generated>)
at com.axelor.meta.ActionExecutor$$EnhancerByGuice$$6c24d2b3$$FastClassByGuice$$b0883d1e.invoke(<generated>)
at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:76)
at com.axelor.rpc.ResponseInterceptor.invoke(ResponseInterceptor.java:56)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:78)
at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:54)
at com.axelor.meta.ActionExecutor$$EnhancerByGuice$$6c24d2b3.execute(<generated>)
at com.axelor.web.service.ActionService.execute(ActionService.java:107)
at com.axelor.web.service.ActionService$$EnhancerByGuice$$6e3a19da.CGLIB$execute$0(<generated>)
at com.axelor.web.service.ActionService$$EnhancerByGuice$$6e3a19da$$FastClassByGuice$$85164d8.invoke(<generated>)
at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:76)
at com.axelor.rpc.RequestFilter.invoke(RequestFilter.java:55)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:78)
at com.axelor.rpc.ResponseInterceptor.invoke(ResponseInterceptor.java:65)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:78)
at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:54)
at com.axelor.web.service.ActionService$$EnhancerByGuice$$6e3a19da.execute(<generated>)
at sun.reflect.GeneratedMethodAccessor665.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:140)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:294)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:248)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:235)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:398)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:205)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:228)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:89)
at com.axelor.db.tenants.AbstractTenantFilter.doFilter(AbstractTenantFilter.java:70)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
at org.apache.shiro.guice.web.SimpleFilterChain.doFilter(SimpleFilterChain.java:44)
at io.buji.pac4j.filter.SecurityFilter.lambda$doFilter$0(SecurityFilter.java:86)
at org.pac4j.core.engine.DefaultSecurityLogic.perform(DefaultSecurityLogic.java:140)
at com.axelor.auth.pac4j.AuthPac4jModule$AxelorSecurityFilter$1.perform(AuthPac4jModule.java:484)
at com.axelor.auth.pac4j.AuthPac4jModule$AxelorSecurityFilter$1.perform(AuthPac4jModule.java:468)
at io.buji.pac4j.filter.SecurityFilter.doFilter(SecurityFilter.java:84)
at org.apache.shiro.guice.web.SimpleFilterChain.doFilter(SimpleFilterChain.java:41)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
at com.axelor.app.internal.AppFilter.doFilter(AppFilter.java:94)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
at com.google.inject.persist.PersistFilter.doFilter(PersistFilter.java:94)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
at com.axelor.db.tenants.AbstractTenantFilter.doFilter(AbstractTenantFilter.java:70)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
at com.axelor.web.servlet.CorsFilter.doFilter(CorsFilter.java:137)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:121)
at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:196)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:698)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:366)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:639)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:847)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1680)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:147)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1441)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1421)
at com.axelor.db.JPA.persist(JPA.java:128)
at com.axelor.db.JPA.manage(JPA.java:444)
at com.axelor.data.csv.CSVImporter.importRow(CSVImporter.java:397)
at com.axelor.data.csv.CSVImporter.process(CSVImporter.java:308)
... 104 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:112)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3003)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3503)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:89)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:589)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1435)
... 109 more
Caused by: org.postgresql.util.PSQLException: ERREUR: la valeur d'une clé dupliquée rompt la contrainte unique « uk_kmoa50rib71d6kh82rgrd9rpb »
Détail : La clé « (code)=(46658.SOUD) » existe déjà.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2412)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2125)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:297)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:428)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:354)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:169)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:136)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:205)
... 118 more
Note : Quand je cherche le produit 46658.SOUD dans Axelor, il n’existe pas. La nomenclature non-plus d’ailleurs.