Quotation

IPM DTO Mapping

This document explains how IOS offers (IbOffer and subclasses) are mapped to IPM DTOs for both new business and policy changes. The key extension points are the following interfaces, which you can implement to provide your own mapping logic.

Interfaces for Mapping

New Business

The NewBusinessDtoMapper maps an IbOffer to a NewBusinessDto (used when creating a new policy in IPM).

public interface NewBusinessDtoMapper {
    NewBusinessDto mapToDto(IbOffer quotation);
}
Change Policy

The ChangePolicyRequestDtoMapper maps an IbOffer to a ChangePolicyRequestDto (used when endorsing or changing an existing policy in IPM).

public interface ChangePolicyRequestDtoMapper {
    ChangePolicyRequestDto mapToDto(IbOffer quotation);
}

By implementing these interfaces, you can provide fully custom transformations from IOS domain objects to the IPM DTOs. The resulting mapper classes are then used by the relevant policy services to submit or change policies in IPM.

Composite Mappers for LOB-Specific Implementations

Different lines of business (LOB) often require distinct mapping logic. Rather than implementing a single mapper for all scenarios across multiple LOBs, you can define individual LOB-specific mappers. A composite mapper then automatically selects the appropriate mapper at runtime based on the LOB identifier (lobId).

This pattern is equally applicable to issuing new policies and handling policy changes. For implementation details, see CompositeNewBusinessDtoMapper and CompositeChangePolicyRequestDtoMapper.

Example: New Business Mapping

CompositeNewBusinessDtoMapper holds a set of NewBusinessDtoMapper implementations, each tied to a particular lobId. When mapToDto is called, it dispatches to the correct mapper based on the offer’s lobId.

To register your mapper for a specific LOB, create a Spring bean using an instance of a CompositeNewBusinessDtoMapper.Registration:

import de.faktorzehn.ios.ipm.shared.MapperRegistrationFactory;

@Configuration
public class FnIosIpmConfiguration {

    @Bean
    CompositeNewBusinessDtoMapper.Registration fnCompositeNewBusinessDtoMapperRegistration(
            NewBusinessMapperRegistrationFactory newBusinessMapperRegistrationFactory,
            FnLobConfig lobConfig,
            @Value("${ipm.tenant:1}") String ipmTenantId
    ) {
        var contractBundleMapper = FnContractBundleToDtoMapper
                .asFunctionWith(ToDtoMappingContext.with(LocaleContextHolder.getLocale()));

        MappingRule<NewBusinessDto> contractBundleWithVariedBaseMappingRule = NewBusinessMappingRules
                .contractBundleWithVariedBaseMappingRule(contractBundleMapper);

        String lobId = lobConfig.getLobId();
        return newBusinessMapperRegistrationFactory.create(lobId, $ -> ipmTenantId,
                                                           List.of(contractBundleWithVariedBaseMappingRule));
    }
}

By defining this bean, the mapper is automatically registered and picked up by the composite mapper at runtime.

Fine-Grained Customization with MappingRules

In many cases, you don’t need to implement an entire mapper from scratch. Instead, you can reuse or combine existing mapping logic through MappingRule implementations. A MappingRule represents a single, reusable mapping step, making it easy to customize or extend mapping logic without duplicating code.

Using MappingRule based Mappers

The following example demonstrates how to use the MappingRuleBasedNewBusinessDtoMapper to assemble custom mappings from multiple mapping rules:

@Bean
CompositeNewBusinessDtoMapper.Registration hmCompositeNewBusinessDtoMapperRegistration(HmLobConfig lobConfig,
                                                                                       @Value("${ipm.tenant:1}") String ipmTenantId) {
    MappingRule<NewBusinessDto> contractBundleMappingRule = (quotation, parentDto) -> {
        parentDto.setLobId(lobConfig.getLobId());
        parentDto.setTenantId(ipmTenantId);

        var contractBundleCopy = (ExtContractBundle)quotation
                .getChosenVariantExisting()
                .getContractBundle().copyAndReplaceProductWithVariedBase();
        var contractBundleDto = new HmContractBundleToDtoMapper()
                .createDto(contractBundleCopy, ToDtoMappingContext.with(LocaleContextHolder.getLocale()));
        parentDto.setContractBundle(contractBundleDto);
    };

    // replace default with lob-specific previous policy info mapper
    MappingRule<NewBusinessDto> previousPolicyInfoMappingMethod = (quotation, dto) -> {
        var previousPolicyInfo = new HmPreviousPolicyInfoToDtoMapper()
                .createDto(quotation.getPreviousPolicyInfo(),
                           ToDtoMappingContext.with(LocaleContextHolder.getLocale()));
        dto.setPreviousPolicyInfo(previousPolicyInfo);
    };

    var newBusinessMapper = new MappingRuleBasedNewBusinessDtoMapper(
            List.of(previousPolicyInfoMappingMethod,
                    MappingRules.correspondenceRecipient(NewBusinessDto::setCorrespondenceRecipient),
                    MappingRules.premiumPayer(NewBusinessDto::setPremiumPayer),
                    MappingRules.intermediary(NewBusinessDto::setIntermediary),
                    MappingRules.applicationData(NewBusinessDto::setApplicationData),
                    MappingRules.issuanceType(NewBusinessDto::setIssuanceType),
                    contractBundleMappingRule));

    return new CompositeNewBusinessDtoMapper.Registration(lobConfig.getLobId(), newBusinessMapper);
}

In this example:

  • Shared mapping logic such as correspondenceRecipient, premiumPayer, intermediary, applicationData, and issuanceType is provided via reusable MappingRules factory methods.

  • Business-specific rules like contractBundleMappingRule (mapping the contract bundle using a LOB-specific DTO mapper) and previousPolicyInfoMappingMethod (using a custom previous policy info mapper) allow for targeted customization per LOB.

This approach offers a powerful yet flexible way to assemble a DTO mapper using a combination of common rules and line-of-business-specific logic.

You can combine this flexibility with structured configuration by registering the rule-based mapper through a CompositeNewBusinessDtoMapper.Registration. This enables automated selection of the appropriate mapper at runtime, based on the lobId, while keeping the mapping logic modular and maintainable.