How to make product
This section serve as step by step tutorial for making a product
About product
Every product must have
Attributes
- $requiredInCreate - array (multidimensional) of field names required from first step fields (see Fields)
- $requiredInComplete - array (multidimensional) of field names required from third step fields. Can be modified in initialize method to show some fields only if some conditions are met (see Fields)
- $otherUsedFields - array (multidimensional) of field names used which are not required (see Fields)
- $daysToPay - number of days client has to pay for insurance (used in textation)
- $daysToPayForCalculation - number of days client has to pay for insurance (if you need different value to create date to pay)
- $referenceDate - reference date (start of insurance / date of closure) + $daysToPay
Methods
- initialize - used as __construct method (optional)
- isValid - form data validation
- prices - price of insurance calculation
- contract - finishing the product
- documents - attaching documents into product
More informations about each of these method can be found in Product documentation
Step by step
When you already know about product from product documentation from insurance company you can do this steps
- fill $requiredInCreate array with required fields
- set insurance company api endpoints in initialize
- program conditions for product in isValid
- program prices method
- make prepareData method to preprocess data from form to api call (optional, recommended)
- request insurance company api with prepared data
- process response
- return right values
- check if all fields used are in $requiredInCreate or $otherUsedFields
- fill $requiredInComplete array with required fields
- program contract method
- make prepareDataForContract method to preprocess data from form to api call (optional, recommended)
- request insurance company api with prepared data
- process response
- set contract number
- save data about documents from this api request (optional, sometimes api returns data about documents)
- return true/false
- check if all fields used are in $requiredInComplete or $otherUsedFields
- program documents method
- request insurance company api or use saved data from contract
- attach dynamic files only
- return true/false
Examples
initialize
public function initialize()
{
// Set wsdl for WS calls
$this->wsdl = $this->test ? 'url-for-test.wsdl' : 'url-for-production.wsdl';
}
isValid
public function isValid()
{
// Check vehicle type
if ($this->value('type') === false) { // This calls $this->parseType method with value from form
$this->addError('Nepodporovaný typ vozidla'); // This will disabled calling prices method
}
}
parse…
Parse methods are used as helpers to find out how our codelist values are mapped to insurance companies codelist values
They are also used to clean the code and make it more transparent
protected function parseType($type) // Don't type hint method arguments because it can make some errors bacause value might different type or null too
{
// Use custom array map to map values from our form to insurance company codelist
// OUR_CONSTANT => INSURANCE_COMPANY_VALUE
// Return false if there is no map value
return [
VEHICLE_TYPE_M1 => 1,
VEHICLE_TYPE_N1 => 2,
VEHICLE_TYPE_MOTORBIKE => 4,
VEHICLE_TYPE_TRICYCLE => 8
][$type] ?? false;
}
also you can use setParser helper to define custom parsers
Example
protected function initialize()
{
// Set parsers
$this->setParser(Field::HOME_TYPE, 'parseHomeType');
$this->setParser([Field::BLOCK_POLICYHOLDER, Field::BIRTH], 'parseBirth');
}
public function prices()
{
$parsedHomeType = $this->value(Field::HOME_TYPE);
}
public function parseHomeType($homeType)
{
return [
OUR_CONSTANT => self::WS_CONSTANT
][$homeType] ?? false;
}
prices
public function prices()
{
// Prepare data from form
$data = $this->prepareData();
// Try to get price for yearly payment
if ($year = $this->price($data, FREQUENCY_YEAR)) {
// If success return array for each payment frequency + request prices for half and quarter year payment frequency
return [
FREQUENCY_YEAR => $year,
FREQUENCY_HALF => $this->price($data, FREQUENCY_HALF),
FREQUENCY_QUARTER => $this->price($data, FREQUENCY_QUARTER)
];
}
// Not successful request
return false;
}
// Methods prepareData, price need to be done by you
contract
public function contract(): bool
{
// Prepare data
$data = $this->prepareDataForContract();
// Call api
$result = $this->callApi('methodName', $data); // See Product documentation
// Process result
if ($result->neededData ?? false) {
// Set contract number
if ($contractNumber = $result->some->special->data->contractNumber) {
// Have to set contract number in this method
$this->setContractNumber($contractNumber); // See Product documentation
// Everything was ok
return true;
}
}
// Something was wrong
return false;
}
// Method prepareDataForContract need to be done by you
documents
public function documents(): bool
{
// Get documents from WS for example
$data = $this->callApi('documentsMethod', [], 'get');
// Process result
if ($data) {
$this->addDocumentFromContents($data->pdfContents, DOC_TYPE_CONTRACT); // See Product documentation + Constants
return true;
}
// Something was wrong
return false;
}
Debug
If you are going to make REST/API/SOAP request,
it is better to debug your requests first
in some kind of software like SoapUI.
Than you should use our product debug interface
How to get into debug interface
- Fill 1. step validly and submit
- Wait until offers appear and find your product
- Click "bug" icon above insurance company logo
Soap call
- In initialize method
$this->wsdl = 'wsdl url'; - Call (don't use try catch)
$response = $this->callSoap( // Soap function name 'function', // Function parameters [ 'par1' => 'val1', ... ], // Soap call options (optional) [ 'option' => 'val', ... ] );
Process soap call error
If soap call fails, $this->callSoap returns false.
If you need to show error to broker, you have to implement method processSoapError into your product
/**
* Process error of soap call
*
* @param Throwable $e
* @param array $debugData
* @return void
*/
protected function processSoapError(\Throwable $e, array $debugData)
{
// Example of use, Str => use Illuminate\Support\Str;
if (Str::contains(errorMessage($e), 'Správny tvar je 17 znakov')) {
$this->addError('VIN - Správny tvar je 17 znakov', true);
}
/*
$debugData contains indexes
'pid' = product id
'hash' = contract has
'service' = product class
'method' = soap call method
'variant' = actual variant
'options' = soap call options
*/
}
Special situations
Transfer data from prices() to contract()
Methods prices and contract are called in different object instances and use of data obtained in prices method are cannot be used in contract like this
...
public function prices()
{
// This is just example, there is no inherited pricesResultId attribute or id in result
$result = $this->callSoap('method', $data);
$this->pricesResultId = $result->id;
}
...
public function contract()
{
$pricesData = $this->pricesResultId; // Always empty (possible warning throw)
}
So for this situations you have to use helpers setCustom and getCustom
...
public function prices()
{
// This is just example, there is no id in result by default
$result = $this->callSoap('method', $data);
$this->setCustom('pricesResultId', $result->id);
}
...
public function contract()
{
$pricesData = $this->getCustom('pricesResultId'); // Returns real data set in prices
}
Use this only to store small data, like basic strings, integers, don't use for files
Transfer data from contract() to documents()
Methods contract and documents are called in one object instance and use of data obtained in contract method can be used in contract like this
...
public function contract()
{
// This is just example, there is no inherited contractContents attribute or documents in result by default
$result = $this->callSoap('method', $data);
$this->contractContents = $result->documents->contractContents;
}
...
public function documents()
{
// Attach document from contents to contract
$this->addDocumentFromContents($this->contractContents, DOC_TYPE_CONTRACT);
}
All documents have to be attached only in documents method
Conditional reinsurances
If you need to show some reinsurances depending on some conditions, add this method $allValid need to be implemented , if $allValid = true, add all possible reinsurances
/**
* Check if to show reinsurances
*
* @param bool $allValid
* @return void
*/
protected function checkReinsurances(bool $allValid = false)
{
// For example if vehicle type is M1
if ($this->get(Field::VEHICLE_TYPE) == VEHICLE_TYPE_M1 || $allValid) {
$this->reinsurances[] = [
...
]
}
}
Conditional variants
If you need to show some variants depending on some conditions, you have to do it in prepareVariants method
It is important that all $variants are set if no of your conditions are met
There are two possibilies how to do that:
- If you are not sure use $this->allValid to check if should add all variants or not (recommended)
- Or for example if you check type (vehicle type) and type is empty or
nullthat means it is not defined yet what means that product is initialized for some special purpose when is most likely important to show all posibilities.
Both shown down below in example
...
/**
* Prepare dynamic variants
*
* @return void
*/
protected function prepareVariants()
{
$type = $this->get(Field::VEHICLE_TYPE);
// 1. example with $this->allValid
if ($type == VEHICLE_TYPE_M1 || $this->allValid) {
$this->variants[] = [
VARIANT_ID => 1,
VARIANT_NAME => '5% 165e'
];
$this->variants[] = [
VARIANT_ID => 2,
VARIANT_NAME => '10% 165e'
];
}
// 2. example with undefined $type
if ($type == VEHICLE_TYPE_MOTORBIKE || !$type) { {
$this->variants[] = [
VARIANT_ID => 3,
VARIANT_NAME => '10% 330e'
];
}
}
Conditional fields in 3. step
If you need to show some field depending on some conditions, you have to do it in initialize method
This cannot be depending on values from 3rd step
...
protected function initialize()
{
...
if ($someCondition) {
$this->requiredInComplete[] = Field::KEY_COPIES;
}
...
}
Dynamic documents in 4. step
If you need to show dynamic document in 4th step before submitting contract your need to implement method dynamicDocumentsList which returns array with type and method name which generates dynamic document
/**
* Get dynamic document list for this product
*
* @return array
*/
public function dynamicDocumentsList(): array
{
return [
[
'type' => DOC_TYPE_INFO_FOR_PZ_BEFORE,
'fn' => 'addInfoForPzBefore'
]
];
}
Custom validation in 4th step/before confirming
If you need to add custom accepts validation rules for example.
Add $this->validateCustom call before other api/ws calls in contract method.
validateCustom use basic laravel validation
Laravel validation docs
/**
* Complete contract after 4th step
*
* @return bool
*/
public function contract(): bool
{
// Example of required YES for ACCEPT_EL_DOCS
$this->validateCustom([Field::BLOCK_ACCEPTS . '.' . ACCEPT_EL_DOCS => 'in:' . YES]);
// Example of required YES for ACCEPT_EL_DOCS with custom message
$field = Field::BLOCK_ACCEPTS . '.' . ACCEPT_EL_DOCS;
$this->validateCustom(
[$field => 'in:' . YES],
[$field . '.in' => 'Custom error message'] // '.in' is name of rule above, which when not validated should use custom error message
);
....
}