Cancellation
Overview
The Cancellation Plugin enables the amount retained at cancellation to be increased or decreased by any amount according to custom business logic, providing the flexibility needed to implement minimum earned premium plans, short rate penalties, or other fee or refund requirements at cancellation.
It allows for the creation of Retention Charges of any positive or negative amounts that represent adjustments to the amount retained at the time of cancellation.
Plugin Execution
The Cancellation Plugin executes automatically during pricing of a cancellation transaction.
Specifically, it is executed after the system calculates the default pro-rated cancellation charges, but before those charges are persisted. This timing allows the plugin to insert additional retention charges into the transaction before finalization.
If plugin execution fails or returns ok
= false
, pricing for the cancellation is halted and the transaction remains in a validated
state with no persisted data.
The plugin will be called for cancellation transactions that meet the following criteria:
The cancellation takes effect during a coverage segment rather than a gap segment, meaning it is not a re-cancellation that takes effect after an existing cancellation
The cancellation is not the re-application of an existing, reversed cancellation for another out-of-sequence, aggregate transaction
The plugin will execute for stateless invoice previews, enabling the preview of expected retention charges.
Plugin Input
The plugin receives the cancellation transaction context, including:
The details of the transaction
The details of the segment
The list of prospective, pro-rated cancellation charges
{
"transaction": PolicyTransactionResponse,
"segment": SegmentResponse,
"charges": [ PolicyChargeResponse ]
}
It may also use the Plugin Data Fetcher to retrieve any additional context required to calculate retention adjustments. The getTermCharges()
method provides all non-zero charges for issued transactions within a given term and can be used to determine the earned premium.
Plugin Output
The plugin should return a retentionCharges
object containing a RatingSet of new retention charges. Each RatingItem
in the set defines a retention charge to be injected into the cancellation transaction.
The amount
represents the increase or decrease in the amount to be retained.
{
"retentionCharges": {
"ok": true,
"RatingItems": [
{
"elementLocator": "<<elementLocator>>",
"chargeType": "<<chargeType>>",
"amount": 25.0,
"tag": "<<note>>"
}
]
}
}
Output Validation
The following validation will apply to any RatingItem
provided in the plugin output:
amount
is required and may be any positive or negative valueamount
of0
will not result in the creation of a retention chargerate
andrateDifference
will be ignored and overwritten by the systemchargeType
must be a retention charge defined within configurationelementLocator
must reference an element defined in configuration that supports association with the specifiedchargeType
Plugin Considerations
Minimum earned premium and minimum premium are distinct concepts enforced by different plugins at different points in the policy lifecycle. Minimum earned premium is enforced at cancellation via the Cancellation Plugin and ensures that a minimum amount is retained for a policy. Minimum premium is enforced at policy issuance via the Rating Plugin and ensures the initial policy premium meets a minimum threshold.
Usage of the Cancellation Plugin does not guarantee an effective minimum earned premium for a term in all scenarios. Depending on how transactions are issued, it is possible for the effective premium for a given term to be less than the minimum earned premium as defined and enforced in the plugin. For example, a policy could be cancelled effective on the second day of a term and then reinstated on the last day of the term.
Any earned premium determination made at the time of Cancellation Plugin execution is subject to change prior to the cancellation effective date due to the potential creation of flat charges via API.
Implementation Example
This example shows how a minimum earned premium of $100 can be enforced on any cancellation transaction, including charges of all types in the earned premium determination:
public class CancellationPluginImpl implements CancellationPlugin {
private static final Logger log = LoggerFactory.getLogger(CancellationPlugin.class);
private static final BigDecimal MINIMUM_EARNED_PREMIUM = BigDecimal.valueOf(100L);
public CancellationPluginResponse cancel(PersonalAutoRequest request) {
Transaction transaction = request.transaction();
PersonalAutoSegment currentSegment = request.segment();
Collection<Charge> cancellationCharges = request.charges();
if (cancellationCharges == null) {
cancellationCharges = List.of();
}
log.info("All cancellation charges {}", cancellationCharges);
Map<ULID, Collection<Charge>> termCharges = DataFetcher.getInstance().getTermCharges(request.policy().latestTermLocator());
log.info("All term charges {}", termCharges);
BigDecimal totalPremium = termCharges.values().stream()
.flatMap(Collection::stream)
.map(Charge::amount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal totalCancellation = cancellationCharges.stream()
.map(Charge::amount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal earnedPremium = totalPremium.add(totalCancellation);
BigDecimal retentionCharge = MINIMUM_EARNED_PREMIUM.subtract(earnedPremium);
log.info("Total premium {}, cancellation premium {}, earned {}, retention {}",
totalPremium,
totalCancellation,
earnedPremium,
retentionCharge);
if (retentionCharge.compareTo(BigDecimal.ZERO) > 0) {
log.info("Adding minimum earned retention charge to transaction {}, segment {}, element {}",
transaction.locator(),
currentSegment.locator(),
currentSegment.element().locator()
);
return CancellationPluginResponse.builder()
.retentionCharges(
RatingSet.builder()
.ok(true)
.ratingItems(List.of(
RatingItem.builder()
.elementLocator(currentSegment.element().locator())
.chargeType(ChargeType.minimumPremium)
.amount(retentionCharge)
.build()
))
.build())
.build();
} else {
return createEmptyRatingSet();
}
}
private static CancellationPluginResponse createEmptyRatingSet() {
return CancellationPluginResponse.builder()
.retentionCharges(
RatingSet.builder().ok(true).ratingItems(List.of()).build())
.build();
}
}