Cancellation Plugin
The Cancellation Plugin allows you to add retention charges to invoices during the policy cancellation process.
Retention charges can be specified as positive or negative amounts, providing the flexibility needed to implement minimum earned premium plans, short-rate penalties, fees, or refunds when policies are cancelled.
The Cancellation Plugin is triggered by pricing requests for policy transactions with a transactionCategory of cancellation, as long as certain criteria are met. See the Execution section for more information.
Implementation
Create a new Java class in the src/main/java/com/socotra/deployment/customer folder. All plugin code must be contained within this folder. We named our class CancellationPluginImpl.java in the example below, but you can name your class whatever you’d like.
Implement the CancellationPlugin interface, and override the method corresponding to your target product type.
For example, the following class contains a method that adds a retention charge to invoices when commercial auto policies are cancelled:
public class CancellationPluginImpl implements CancellationPlugin {
private static final Logger log = LoggerFactory.getLogger(CancellationPluginImpl.class);
// Add a retention charge to invoices when commercial auto policies are cancelled
@Override
public CancellationPluginResponse cancel(CommercialAutoRequest commercialAutoRequest) {
CommercialAutoSegment currentSegment = commercialAutoRequest.segment();
return CancellationPluginResponse.builder()
.retentionCharges(
RatingSet.builder()
.ok(true)
.ratingItems(List.of(
RatingItem.builder()
.elementLocator(currentSegment.element().locator())
.chargeType(ChargeType.minimumPremium)
.amount(BigDecimal.valueOf(50))
.build()
))
.build())
.build();
}
}
The method argument contains the following fields:
policy- The policysegment- The current segmenttransaction- The policy transactioncharges- A list of default pro-rated retentionchargescalculated by the system before the Cancellation Plugin was executed. See the Execution section for more information.
The method returns a CancellationPluginResponse object, which contains a list of RatingItem objects. Each RatingItem object represents a retention charge and contains the following fields:
elementLocator- The locator of the element related to the retention chargechargeType- The retention charge typeamount- The retention charge amount
Retention charge types refer to ChargeRef configuration objects with a handling value of retention and an invoicing value of next. ChargeRef names must be included in the list of charges in the ProductRef configuration object for your target policy.
Retention charges can be associated with any element within a policy. Only one charge per retention charge type can be associated with each element.
Here’s an example of a ChargeRef configuration object called MinimumPremium:
{
"category": "premium",
"handling": "retention",
"invoicing": "next"
}
Here’s an example of the charges field in a ProductRef configuration object called CommercialAuto:
{
"charges": ["MinimumPremium"]
}
Data Fetcher
The Data Fetcher can provide additional data required to calculate retention charges. The following methods are especially useful for this purpose:
getTermCharges()- Retrieves all non-zero charges for issued transactions within a termgetTermSubsegmentSummaries()- Retrieves a summary of each segment in a term, including the effective duration, effective charges, and extension data
Execution
The Cancellation Plugin is triggered when policies are cancelled, as long as the following criteria are met:
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
Policies can be cancelled via the Policy Transactions API, or as a result of a delinquency if the delinquency plan has been configured to create a policy transaction with a transactionCategory of cancellation.
The Cancellation Plugin is triggered when stateless invoice previews are generated. This allows you to preview retention charges.
The system begins the cancellation pricing process by first calculating default pro-rated retention charges, then executing the Cancellation Plugin.
After the plugin has executed successfully, the system calculates the final retention charges that will appear on the next invoice containing applicable uninvoiced installments by adding up the default pro-rated retention charges and the retention charges added by the Cancellation Plugin.
Finally, the system persists the calculation results.
If plugin execution fails, or the plugin returns an ok value of false, the cancellation pricing process will stop, cancellation pricing data will not be persisted, and the policy transaction will remain in the validated state. The Cancellation Plugin must be triggered again to restart the cancellation pricing process.
Output Validation
The system automatically performs the following validation checks on each RatingItem object returned by the Cancellation Plugin:
amountis a required field and must be a positive or negative valueAn
amountof0will not result in a retention chargerateandrateDifferencewill be ignored and overwritten by the systemchargeTypemust be included in the list ofchargesin the ProductRef configuration object for your target policy
Plugin Considerations
Minimum earned premium and minimum premium are distinct concepts enforced by different plugins at different points in the policy lifecycle. Minimum earned premiums are enforced via the Cancellation Plugin when policies are cancelled, ensuring that a minimum amount is retained for a policy. Minimum premiums are enforced via the Rating Plugin when policies are issued, ensuring the initial policy premium meets a minimum threshold.
Using the Cancellation Plugin does not guarantee an effective minimum earned premium for a term. 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 enforced by the plugin. For example, a policy cancellation could take effect on the second day of a term and then get reinstated on the last day of the term.
Any minimum earned premium determinations made at the time of plugin execution are subject to change before the cancellation effective date due to the potential creation of flat charges via API requests.
Example
The following example is based on the Prism configuration. Contact your Socotra representative for more information.
// Enforce a minimum earned premium of $100 when a policy is cancelled
public class CancellationPluginImpl implements CancellationPlugin {
private static final Logger log = LoggerFactory.getLogger(CancellationPluginImpl.class);
@Override
public CancellationPluginResponse cancel(CommercialAutoRequest commercialAutoRequest) {
Transaction transaction = commercialAutoRequest.transaction();
CommercialAutoSegment currentSegment = commercialAutoRequest.segment();
Collection<Charge> cancellationCharges = commercialAutoRequest.charges();
if (cancellationCharges == null) {
cancellationCharges = List.of();
}
log.info("All cancellation charges: {}", cancellationCharges);
Map<ULID, Collection<Charge>> termCharges = DataFetcher.getInstance().getTermCharges(commercialAutoRequest.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 totalCancellationPremium = cancellationCharges.stream()
.map(Charge::amount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal earnedPremium = totalPremium.add(totalCancellationPremium);
BigDecimal minimumEarnedPremium = BigDecimal.valueOf(100L);
BigDecimal retentionCharge = minimumEarnedPremium.subtract(earnedPremium);
log.info("Total premium: {}, cancellation premium: {}, earned: {}, retention: {}",
totalPremium,
totalCancellationPremium,
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();
}
}