Sélectionner une proposition

Comment suivre ce chapitre

Entrées : Domaine d’activité et catégorie choisis, puis réponses du client.

Étapes et résultat attendu : Résolvez les références, recueillez les identifiants des réponses, calculez le risque et laissez le client choisir une proposition. Transmettez ces valeurs à Ouvrir un portefeuille.

Alternatives et actions ultérieures : La proposition recommandée est le parcours principal. Un choix différent peut exiger des motifs d’écart.

Code source des DTO : BusinessLineOutputModel, InvestmentCategoryOutputModel, ProposalOutputModel, QuestionnaireOutputModel, ReasonToChangeProposalOutputModel, ReasonToChangeProposalResponseOutputModel, RiskCategorizationOutputModel

Les variables affectées dans un bloc précédent sont réutilisées dans les suivants. Les saisies du client proviennent de votre interface. Conservez les identifiants et les valeurs de référence dans le contexte du client ; ne recréez pas ce contexte à chaque étape.

Les exemples utilisent des classes utilitaires communes. Consultez Classes utilitaires communes : code source C# et Java complet avant de copier un exemple.
Prérequis : Un client HTTP configuré. Les références peuvent être lues avec GUEST ; conservez le contexte du client ou administratif pour les écritures.
À conserver pour la suite : Domaine d’activité, catégorie, identifiants de réponse, risque et proposalId choisi.
Le client choisit la catégorie d’investissement souhaitée. Les domaines et catégories usuels figurent ci-dessous. Récupérez les références activées dans l’environnement avant de proposer un produit :
Vorsorge (prévoyance) :
  • Pilier 3a (3a)
  • Libre passage (FZ)
Finance (gestion de fortune) :
  • Invest (3b)

Remarque

Les types d’investissement peuvent être activés ou désactivés selon les besoins de l’entreprise.

Consulter les domaines d’activité

Entrées : Codes du domaine et de la catégorie choisis pour le produit.
Action : Récupérez les références correspondantes.
À conserver / résultat attendu : Conservez businessLineId et investmentCategoryId.
Pour un client intéressé par un portefeuille 3a, récupérez l’identifiant du domaine Vorsorge et celui de la catégorie 3A. Le domaine sélectionne le questionnaire actif et le calcul du risque. La catégorie et l’identifiant du risque calculé servent à obtenir les propositions :
								
var businessLines = await httpClient.GetFromJsonAsync<IList<BusinessLineOutputModel>>("api/v1/business-lines");
var businessLineVorsorge = businessLines.First(x => x.Code == "VORSORGE");
var investmentCategories = await httpClient.GetFromJsonAsync<IList<InvestmentCategoryOutputModel>>("api/v1/investment-categories/business-line-id/" + businessLineVorsorge.Id);
var investmentCategory3A = investmentCategories.First(x => x.Code == "3A");

								
HttpRequest businessLineRequest = HttpRequest.newBuilder()
    .timeout(Duration.ofMinutes(1))
    .uri(Settings.wmsUri("business-lines/code/VORSORGE"))
    .header("Accept-Language", "de-DE")
    .header("Authorization", "Bearer " + Settings.GUEST_TOKEN)
    .header("Content-Type", "application/json")
    .build();

var response = httpClient.send(businessLineRequest, BodyHandlers.ofString());
Api.requireSuccess(response);
BusinessLineOutputModel businessLineOutputModelObj = new Gson().fromJson(response.body(), BusinessLineOutputModel.class);
var businessLineId = businessLineOutputModelObj.Id;

HttpRequest investmentCategoryRequest = HttpRequest.newBuilder()
    .timeout(Duration.ofMinutes(1))
    .uri(Settings.wmsUri("investment-categories/code/3A"))
    .header("Accept-Language", "de-DE")
    .header("Authorization", "Bearer " + Settings.GUEST_TOKEN)
    .header("Content-Type", "application/json")
    .build();

response = httpClient.send(investmentCategoryRequest, BodyHandlers.ofString());
Api.requireSuccess(response);
InvestmentCategoryOutputModel investmentCategoryObj = new Gson().fromJson(response.body(), InvestmentCategoryOutputModel.class);
var investmentCategoryId = investmentCategoryObj.Id;

Réponses au questionnaire

Entrées : businessLineId et réponses choisies par le client.
Action : Récupérez le questionnaire, résolvez les réponses et calculez le risque.
À conserver / résultat attendu : Conservez responseIds et le risque obtenu.
Récupérez le questionnaire du domaine et ses réponses possibles.

Affichez le questionnaire actif et recueillez selectedResponseCodes sur toutes les sections. L’exemple utilise des choix discrets. Pour des réponses numériques, utilisez le schéma adapté et incluez ResponseValue lors de leur sauvegarde. Résolvez les codes en identifiants dans ce questionnaire. L’API valide les réponses obligatoires et l’adéquation ; ne supposez pas de version ou d’ordre fixe des questions :
								
var activeQuestionnaire = await httpClient.GetFromJsonAsync<QuestionnaireOutputModel>($"api/v1/questionnaires/business-line-id/{businessLineVorsorge.Id}/active");
var availableResponses = activeQuestionnaire.Sections.SelectMany(s => s.Questions).SelectMany(q => q.Responses).ToList();
// selectedResponseCodes comes from the client answers to the displayed questionnaire.
var responseIds = selectedResponseCodes.Select(code => availableResponses.Single(r => r.Code == code).Id).ToArray();
var responsesCsv = string.Join(",", responseIds);
var risk = await httpClient.GetFromJsonAsync<RiskCategorizationOutputModel>($"api/v1/risk-categorizations/business-line-id/{businessLineVorsorge.Id}/calculate-risk?csv-response-ids={Uri.EscapeDataString(responsesCsv)}");

								
HttpRequest questionnaireRequest = HttpRequest.newBuilder()
    .uri(Settings.wmsUri("questionnaires/business-line-id/" + businessLineId + "/active"))
    .timeout(Duration.ofMinutes(1))
    .header("Authorization", "Bearer " + Settings.GUEST_TOKEN).GET().build();
var questionnaireResponse = httpClient.send(questionnaireRequest, BodyHandlers.ofString());
Api.requireSuccess(questionnaireResponse);
QuestionnaireOutputModel activeQuestionnaire = new Gson().fromJson(questionnaireResponse.body(), QuestionnaireOutputModel.class);
var availableResponses = activeQuestionnaire.Sections.stream()
    .flatMap(s -> s.Questions.stream()).flatMap(q -> q.Responses.stream()).toList();
// selectedResponseCodes comes from the client answers to the displayed questionnaire.
var responseIds = selectedResponseCodes.stream().map(code -> availableResponses.stream()
    .filter(r -> code.equals(r.Code)).findFirst()
    .orElseThrow(() -> new IllegalArgumentException("Response not in the active questionnaire")).Id).toList();
var responsesCsv = responseIds.stream().map(String::valueOf).collect(java.util.stream.Collectors.joining(","));
HttpRequest riskRequest = HttpRequest.newBuilder()
    .uri(Settings.wmsUri("risk-categorizations/business-line-id/" + businessLineId
    + "/calculate-risk?csv-response-ids=" + java.net.URLEncoder.encode(responsesCsv, StandardCharsets.UTF_8)))
    .timeout(Duration.ofMinutes(1))
    .header("Authorization", "Bearer " + Settings.GUEST_TOKEN).GET().build();
var riskResponse = httpClient.send(riskRequest, BodyHandlers.ofString());
Api.requireSuccess(riskResponse);
RiskCategorizationOutputModel riskCategorizationObj = new Gson().fromJson(riskResponse.body(), RiskCategorizationOutputModel.class);

Obtenir les propositions

Entrées : investmentCategoryId et risque calculé.
Action : Récupérez les propositions et recueillez le choix du client.
À conserver / résultat attendu : Conservez proposalId et les identifiants des motifs d’écart requis.
Avec le risque calculé, récupérez les modèles proposés et laissez le client choisir proposalId parmi les résultats. Si aucune proposition ou référence ne correspond, traitez les données du produit comme indisponibles plutôt que de choisir une valeur par défaut :
								
var proposals = await httpClient.GetFromJsonAsync<List<ProposalOutputModel>>($"api/v1/proposals/investment-category-id/{investmentCategory3A.Id}/risk-id/{risk.Id}");
// The client chooses proposalId from the displayed proposals.
var proposalSelectedByUser = proposals.Single(x => x.Id == proposalId);

								
HttpRequest proposalRequest = HttpRequest.newBuilder()
    .timeout(Duration.ofMinutes(1))
    .uri(Settings.wmsUri("proposals/investment-category-id/" + investmentCategoryId + "/risk-id/" + riskCategorizationObj.Id))
    .header("Accept-Language", "de-DE")
    .header("Authorization", "Bearer " + Settings.GUEST_TOKEN)
    .header("Content-Type", "application/json")
    .build();

response = httpClient.send(proposalRequest, BodyHandlers.ofString());
Api.requireSuccess(response);

Type listType = new TypeToken<ArrayList<ProposalOutputModel>>(){}.getType();
List<ProposalOutputModel> proposalsListObj = new Gson().fromJson(response.body(), listType);

// proposalId is selected by the client from the displayed proposals.
var proposalSelectedByUser = proposalsListObj.stream().filter(x -> x.Id == proposalId)
    .findFirst().orElseThrow(() -> new IllegalArgumentException("Select a displayed proposal"));

La proposition peut être affichée comme suit :
Exemple de proposition d’investissement
Si le client choisit un modèle différent de celui proposé, indiquez les motifs d’écart. Il s’agit d’une liste simple de réponses avec la structure suivante :
									
public class ReasonToChangeProposalResponseOutputModel
{
    public long Id { get; set; }
    public string Code { get; set; }
    public string Description { get; set; }
    public int Order { get; set; }
}

public class ReasonToChangeProposalOutputModel
{
    public long Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public bool IsDeleted { get; set; }
    public IList<ReasonToChangeProposalResponseOutputModel> Responses { get; set; }
}

	
									
import java.util.List;
import java.util.Map;

import com.google.gson.annotations.SerializedName;

public class ReasonToChangeProposalResponseOutputModel {
    @SerializedName("id")
    public long Id;

    @SerializedName("code")
    public String Code;

    @SerializedName("description")
    public String Description;

    @SerializedName("order")
    public int Order;
}

public class ReasonToChangeProposalOutputModel {
    @SerializedName("id")
    public long Id;

    @SerializedName("code")
    public String Code;

    @SerializedName("name")
    public String Name;

    @SerializedName("isDeleted")
    public boolean IsDeleted;

    @SerializedName("responses")
    public List<ReasonToChangeProposalResponseOutputModel> Responses;
}

Récupérez cette liste comme suit :
									
var reasonsToChangeProposal = await httpClient.GetFromJsonAsync<ReasonToChangeProposalOutputModel>($"api/v1/reason-to-change-proposed-proposal/investment-category-id/{investmentCategory3A.Id}/active");

	
									
HttpRequest reasonToChangeRequest = HttpRequest.newBuilder()
    .timeout(Duration.ofMinutes(1))
    .uri(Settings.wmsUri("reason-to-change-proposed-proposal/investment-category-id/" + investmentCategoryId + "/active"))
    .header("Accept-Language", "de-DE")
    .header("Authorization", "Bearer " + Settings.GUEST_TOKEN)
    .header("Content-Type", "application/json")
    .build();

response = httpClient.send(reasonToChangeRequest, BodyHandlers.ofString());
Api.requireSuccess(response);
ReasonToChangeProposalOutputModel reasonToChangeProposalObj = new Gson().fromJson(response.body(), ReasonToChangeProposalOutputModel.class);

En cas d’écart à la proposition recommandée, recueillez les identifiants pertinents dans selectedReasonIds. Utilisez une liste vide si aucun motif n’est requis et ne choisissez pas automatiquement les motifs. Envoyez ces identifiants avec l’ordre d’ouverture, comme indiqué au chapitre suivant.