lumnik. / scénarios Tous les scénarios · English

Le guichet SOAP du CRM lu service par service sans rien lire deux fois

Objectif Lire les services SOAP d'un vieux CRM, chacun comme il se lit, sans le marteler.

Un CRM des années 2000 expose ses données par des services SOAP sur mesure. Le mot de passe voyage dans l'enveloppe.

manifests/10-actions.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: scenario-siebel-a  connector_type: rest-generic  scopes: [crm]spec:  base_url: http://host.docker.internal:8097  endpoints:    # A custom business service: the actions of one request, one answer, no paging.    - id: actions      kind: soap      path: /eai_enu/start.swe?SWEExtSource=CustomUI&SWEExtCmd=Execute      soap_action: "document/http://siebel.com/CustomUI:getListActions"      header: |        <s1:SessionType xmlns:s1="http://siebel.com/webservices">None</s1:SessionType>        <s2:UsernameToken xmlns:s2="http://siebel.com/webservices">LAB_SVC</s2:UsernameToken>        <s3:PasswordText xmlns:s3="http://siebel.com/webservices">{{secret:SCENARIO_SIEBEL_A_PASSWORD}}</s3:PasswordText>      body: |        <ns2:getListActions_Input xmlns="http://crm.example.com/getListActions/Data" xmlns:ns2="http://siebel.com/CustomUI">          <getListActions>            <ListActions>              <cdTopOuverture>0</cdTopOuverture>              <dtDebutPeriode>01/01/1900</dtDebutPeriode>              <dtFinPeriode>12/31/9999</dtFinPeriode>              <origine>portail-svc-demandes</origine>              <idGRC>40012345</idGRC>              <idDemande>1-7QX2K4A</idDemande>            </ListActions>          </getListActions>        </ns2:getListActions_Input>      pagination:        kind: soap        page_size: 1000        response_path: "$.Body.getListActions_Output.ListActions.Action"      target:        kind: hybrid        table: ext.siebel_actions_a        unique_key: "$.idAction"        promote:          - { name: id_demande, path: "$.idDemande", type: text }          - { name: type_action, path: "$.typeAction", type: text }          - { name: statut, path: "$.statut", type: text }
manifests/20-opportunities.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: scenario-siebel-opp-a  connector_type: rest-generic  scopes: [crm]spec:  base_url: http://host.docker.internal:8097  endpoints:    # A person's opportunities, paged by a 1-based page NUMBER; the page says whether it is the last.    - id: opportunities      kind: soap      path: /eai_enu/start.swe?SWEExtSource=CustomUI&SWEExtCmd=Execute      soap_action: "document/http://siebel.com/CustomUI:getListOpportunity"      header: |        <s1:SessionType xmlns:s1="http://siebel.com/webservices">None</s1:SessionType>        <s2:UsernameToken xmlns:s2="http://siebel.com/webservices">LAB_SVC</s2:UsernameToken>        <s3:PasswordText xmlns:s3="http://siebel.com/webservices">{{secret:SCENARIO_SIEBEL_A_PASSWORD}}</s3:PasswordText>      body: |        <cus:getListOpportunity_Input xmlns:cus="http://siebel.com/CustomUI" xmlns:data="http://crm.example.com/getOpportunity/Data">          <data:getOpportunity>            <data:Opportunity>              <data:refExtPersonne>40012345</data:refExtPersonne>              <data:cdTopStatutOpportunite>0</data:cdTopStatutOpportunite>              <data:origine>portail-svc-demandes</data:origine>              <data:page>{{page}}</data:page>            </data:Opportunity>          </data:getOpportunity>        </cus:getListOpportunity_Input>      pagination:        kind: soap        page_size: 3        last_page_path: "$.Body.getListOpportunity_Output.getOpportunity.lastpage"        response_path: "$.Body.getListOpportunity_Output.getOpportunity.Opportunity"      target:        kind: hybrid        table: ext.siebel_opportunities_a        unique_key: "$.idOpportunite"        promote:          - { name: libelle, path: "$.libelle", type: text }          - { name: statut, path: "$.statut", type: text }
crm-night1.json
{
 "actions": [
  {
   "idAction": "1-7QX3A01",
   "idDemande": "1-7QX2K4A",
   "dtAction": "10/14/2026 09:12:00",
   "typeAction": "Appel entrant",
   "statut": "Terminée",
   "auteur": "conseiller.07",
   "commentaire": "Client signale une facture en double"
  },
  {
   "idAction": "1-7QX3A02",
   "idDemande": "1-7QX2K4A",
   "dtAction": "10/14/2026 09:30:00",
   "typeAction": "Courrier",
   "statut": "Terminée",
   "auteur": "conseiller.07",
   "commentaire": "Accusé de réception envoyé"
  },

… 80 lignes de plus

$ lm connector run scenario-siebel-opp-a
run scheduled: da227b07-7f92-4e1e-9368-5430196271c6

$ lm run get da227b07-7f92-4e1e-9368-5430196271c6
ID        CONNECTOR              ENDPOINT       STATUS     IN  OUT  SKIPPED  DEAD-LETTERS  STARTED           ENDED
da227b07  scenario-siebel-opp-a  opportunities  Completed  7   7    0        0             2026-11-03 16:10  2026-11-03 16:10
$ lm connector run scenario-siebel-a
run scheduled: f5be7458-f869-4a9f-8866-a461fee6c7e5

$ lm run get f5be7458-f869-4a9f-8866-a461fee6c7e5
ID        CONNECTOR          ENDPOINT  STATUS  IN  OUT  SKIPPED  DEAD-LETTERS  STARTED           ENDED
f5be7458  scenario-siebel-a  actions   Failed  0   0    0        0             2026-11-03 16:10  2026-11-03 16:10
✖ run failed: SOAP Fault: Invalid user name or password (SBL-UIF-00348)
crm-night2.json
{
 "actions": [
  {
   "idAction": "1-7QX3A01",
   "idDemande": "1-7QX2K4A",
   "dtAction": "10/14/2026 09:12:00",
   "typeAction": "Appel entrant",
   "statut": "Terminée",
   "auteur": "conseiller.07",
   "commentaire": "Client signale une facture en double"
  },
  {
   "idAction": "1-7QX3A02",
   "idDemande": "1-7QX2K4A",
   "dtAction": "10/14/2026 09:30:00",
   "typeAction": "Courrier",
   "statut": "Terminée",
   "auteur": "conseiller.07",
   "commentaire": "Accusé de réception envoyé"
  },

… 98 lignes de plus

Limites

  • Une lecture SOAP se fait en une passe, en mémoire: lm run cancel n'agit qu'à la fin de la lecture.
  • Le service est appelé pour une demande et un client écrits dans le manifeste ; un appel par demande d'une liste n'est pas couvert.
  • La marque d'un import incrémental voyage dans l'URL, pas dans le corps: un service qui filtre par période dans le corps est relu en entier.
  • CRM simulé ; données synthétiques.

CRM · SOAP

Le CRM parle SOAP.

Des services sur mesure, des années 2000.

CRM simulé, deux services

Le problème

Chaque service se lit à sa façon.

  • Un service rend tout en un appel.
  • Un autre pagine par numéro de page.

Ce qui n'est pas modifié

Le CRM reste tel quel.

  • Ses services, son enveloppe.
  • Un compte de service.

Le piège

Marteler le CRM.

  • Relire la même page en boucle.
  • Réessayer un mot de passe refusé.

Ce qu'il a fallu écrire

<data:page>{{page}}</data:page>

Une ligne.

  • Le numéro de page, là où le service l'attend.
  • L'arrêt sur la dernière page.
  • Deux manifestes, 84 lignes.

Un refus

Le Fault du CRM, tel quel.

  • Sur le run, avec son code.
  • Une seule tentative.

La limite

Une demande, un client, écrits dans le manifeste.

  • Un appel par élément d'une liste n'est pas couvert.

Essayer

Le scénario se rejoue en local.

Chaque étape est publiée avec sa sortie.

Ce scénario tourne sur lumnik Open, gratuit et open source.

Essayer lumnik Open →