Plan Creation
Before submitting an order, we need to record the client's risk appetite and collect other profile information, as described below.
Saving the client's risk profile
Once the client has accepted the calculated risk profile, we need to save the answers from the questionnaire. By saving the answers, the client's risk profile will also be archived:
payload = JsonConvert.SerializeObject(new
{
BusinessLineId = businessLineVorsorge.Id,
UserId = userId,
Responses = new[]
{
new { ResponseId = response1 },
new { ResponseId = response2 },
new { ResponseId = response3 },
new { ResponseId = response4 }
}
});
_ = await httpClient.PostAsync("api/v1/user-risk-categorizations", new StringContent(payload, Encoding.UTF8, "application/json"));
Saving missing client data
For the next step, it is necessary to save the missing client's data and address.
var nationality = await httpClient.GetFromJsonAsync<NationalityOutputModel>("api/v1/nationalities/code/CH");
var country = await httpClient.GetFromJsonAsync<CountryOutputModel>("api/v1/countries/code/CH");
var pensionSituation = await httpClient.GetFromJsonAsync<PensionSituationOutputModel>("api/v1/pension-situations/code/PENSION-FUND");
var taxLiability = await httpClient.GetFromJsonAsync<TaxLiabilityOutputModel>("api/v1/tax-liabilities/code/CH");
var civilStatus = await httpClient.GetFromJsonAsync<CivilStatusOutputModel>("api/v1/civil-statuses/code/MARRIAGE");
payload = JsonConvert.SerializeObject(new
{
Name = clientName,
Surname = clientSurname,
Email = clientEmail,
PhoneNumberPrefix = "0041",
PhoneNumberNumber = "767676000",
BirthDate = clientBirthDate,
CivilStatusId = civilStatus.Id,
CivilStatusDate = DateTime.Now.AddYears(-5),
GenderId = gender.Id,
LanguageId = language.Id,
Nationality1Id = nationality.Id,
DeliverTaxStatement = true,
TaxLiabilityId = taxLiability.Id,
PensionSituationId = pensionSituation.Id
});
_ = await httpClient.PutAsync($"api/v1/users/user-id/{thirdFactorRegistrationResult.UserId}", new StringContent(payload, Encoding.UTF8, "application/json"));
payload = JsonConvert.SerializeObject(new
{
Street = "Neugasse",
StreetNr = "1",
City = "Baar",
CountryId = country.Id,
Zip = "6340"
});
_ = await httpClient.PutAsync($"api/v1/users/update-address/user-id/{thirdFactorRegistrationResult.UserId}", new StringContent(payload, Encoding.UTF8, "application/json"));
Preparing the contract
Submission of the plan order requires a PDF contract with the client information. The PDF template depends on the asset manager. In the following example, we simulate the preparation of a PDF using Descartes Finance's PDF template. The WMS solution uses a microservice to complete the PDF documents. This microservice is not part of the minimum configuration. In case you wish to use it, you must request its installation. The PDF compiler takes an empty template and sets the respective fields with the values provided:
private async Task GetPdf(IEnumerable placeHolderValues)
{
var payload = new PdfDataInputModel
{
PlaceHolderValues = placeHolderValues.Select(x => new FormField(x.Name, x.Value)).ToList()
};
var byteArray = FileContentHelper.GetFileContent(this.GetType(), "Contract-3A.pdf");
using var httpClient = new HttpClient { BaseAddress = new Uri(_configuration["PdfFillerBaseUrl"]) }; // <== DIFFERENT URL
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json", 1));
httpClient.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("de-DE", 1));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", this.HttpContext.Session.Get("Token"));
var httpContent = HttpHelper.CreateMultipartFormDataHttpContent(payload, byteArray);
var httpResponseMessage = await httpClient.PostAsync("api/v1/pdf-service/fill-pdf-with-data", httpContent);
if (httpResponseMessage.IsSuccessStatusCode)
{
return await httpResponseMessage.Content.ReadAsByteArrayAsync();
}
return default;
}
....
....
var client = await httpClient.GetFromJsonAsync<ClientOutputModel>($"api/v1/users/{this.HttpContext.Session.Get("ClientId")}");
// Collect some (hardcoded) fields...
var fields = new List();
fields.Add(new PdfPlaceHolder("Name", client.Name));
fields.Add(new PdfPlaceHolder("Surname", client.Surname));
fields.Add(new PdfPlaceHolder("Language", "DE"));
fields.Add(new PdfPlaceHolder("Gender", "MALE"));
fields.Add(new PdfPlaceHolder("Street", "Nowhere 0"));
fields.Add(new PdfPlaceHolder("ZipAndCity", "6000 Elsewhere"));
fields.Add(new PdfPlaceHolder("Country", "Zambia"));
fields.Add(new PdfPlaceHolder("Nationality", "Mars"));
fields.Add(new PdfPlaceHolder("Birthdate", "01.01.1990"));
fields.Add(new PdfPlaceHolder("Email", client.Email));
fields.Add(new PdfPlaceHolder("Phone", client.PhoneNumber));
var pdfContractAsByteArray = await this.GetPdf(fields);
Submitting the order
Prior to any plan order, a reservation is required. The reservation returns the IBAN number and plan number associated with the portfolio held at the respective account-holding institution.
Attention
A new reservation is required for each plan creation.
payload = JsonConvert.SerializeObject(new { UserId = thirdFactorRegistrationResult.UserId, InvestmentCategoryId = investmentCategory3A.Id });
httpResponseMessage = await httpClient.PostAsync("api/v1/user-portfolio-orders/reservation", new StringContent(payload, Encoding.UTF8, "application/json"));
var reservationId = UriHelper.GetIdFromLocationUri(httpResponseMessage.Headers.Location);
Attention
The first reservation for each client and INVESTMENT CATEGORY (3a/FZ/3b) requires first name, last name, and date of birth as input parameters. If any of these values change, a new reservation is required.
We can now use the reservation ID to request an investment plan. In the following example, we enter the account-holding institution where the custody account is to be opened (in this example Lienhardt Privatbank). In addition, we need to provide a PDF contract containing client details with the selected investment proposal:
var accountHoldingInstitution = await httpClient.GetFromJsonAsync<AccountHoldingInstitutionOutputModel>("api/v1/account-holding-institutions/code/LIENHARDT");
var orderPortfolioCreationInputModel = new
{
ReservationId = reservationId,
AccountHoldingInstitutionCode = accountHoldingInstitution.Code,
UserId = thirdFactorRegistrationResult.UserId,
InvestmentCategoryId = investmentCategory3A.Id,
ProposalId = proposalSelectedByUser.Id,
Name = "I will be rich soon",
ReasonToChangeProposalResponsesIds = default(List<long>) // In case user agreed with suggested proposal, this list can be left empty
};
var httpContent = HttpHelper.CreateMultipartFormDataHttpContent(orderPortfolioCreationInputModel, pdfContractAsByteArray);
_ = await httpClient.PostAsync("api/v1/user-portfolio-orders/creation", httpContent);
Done. The first client portfolio has been ordered.
The POST request returns, in the HTTP location header, the URL of the newly created portfolio.
As mentioned above, in case the client chooses a different investment strategy than the one proposed, the ReasonToChangeProposalResponsesIds parameter must be filled in with the "reason to change proposal" response ID(s).