# Installments Plugin



The Installments Plugin allows you to adjust the `generateTime`, `dueTime`, and `autopayTime` of installments generated from [installment lattices](/features/billing/installments-and-installment-lattices) to suit business needs.

For example, installment timing may vary based on product type, first-time payments on new policies, or disruptions to installment schedules.

The Installments Plugin is triggered after installments are generated. Installments are generated from installment lattices after a quote or policy transaction is issued.

Implementation [#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 `InstallmentsPluginImpl.java` in the example below, but you can name your class whatever you'd like.

Implement the `InstallmentsPlugin` interface, and override the method corresponding to your target product type.

For example, the following class contains a method that adjusts installments for commercial auto quotes and policy transactions.

```java
public class InstallmentsPluginImpl implements InstallmentsPlugin {
    private static final Logger log = LoggerFactory.getLogger(InstallmentsPluginImpl.class);

    // Adjusts installments for commercial auto quotes and policy transactions

    @Override
    public InstallmentsPluginResponse updateInstallments(CommercialAutoRequest commercialAutoRequest) {
        Map<String, InstallmentUpdate> installmentUpdates = new HashMap<>();
        return InstallmentsPluginResponse.builder().installmentUpdates(installmentUpdates).build();
    }
}
```

The method argument contains an `InstallmentLattice` object, `Installment` objects, and an `InstallmentsPluginContext` object. The `InstallmentsPluginContext` object contains the following fields:

* `accountLocator` - The account locator
* `quoteLocator` - The quote locator
* `policyLocator` - The policy locator
* `transactionLocator` - The policy transaction locator

The method returns an `InstallmentsPluginResponse` object, which contains a map between installment locators and `InstallmentUpdate` objects. Each `InstallmentUpdate` object contains the following fields:

* `generateTime` - When an invoice for the installment will be generated
* `dueTime` - When the invoice is due
* `autopayTime` - When autopay logic is executed, if the [Autopay Plugin](/configuration/plugins/autopay-and-payment-execution) has been implemented

For each of these fields, if no value is specified, the original value will be used, unless it needs to be adjusted based on the [adjustment rules](#AdjustmentRules).

Installments with the same `generateTime` and `dueTime` will be combined into the same invoice when the `generateTime` is reached.

Additional data can be retrieved using the [Plugin Data Fetcher](/configuration/plugins/overview#PluginDataFetcher).

<span id="AdjustmentRules" />

Adjustment Rules [#adjustment-rules]

The values for the `generateTime`, `dueTime`, and `autopayTime` fields will be automatically adjusted after plugin execution is complete based on the following rules:

* If the `generateTime` is after the `dueTime`, the `generateTime` will be set to the `dueTime`.
* If the `autopayTime` is not between `generateTime` and `dueTime`, the `autopayTime` will be set to either the `generateTime` or one day before the `generateTime`, whichever is later.

Execution [#execution]

The Installments Plugin is triggered after installments are generated. Installments are generated from installment lattices after a quote or policy transaction is issued.

Example [#example]

The following example is based on the Prism configuration. Contact your Socotra representative for more information.

```java
// Adjusts the generate time to the beginning of the next month

@Override
public InstallmentsPluginResponse updateInstallments(CommercialAutoRequest commercialAutoRequest) {
    Map<String, InstallmentUpdate> installmentUpdates = movePastInstallmentsToNextMonth(commercialAutoRequest);
    return InstallmentsPluginResponse.builder().installmentUpdates(installmentUpdates).build();
}

private Map<String, InstallmentUpdate> movePastInstallmentsToNextMonth(CommercialAutoRequest commercialAutoRequest) {
    InstallmentsPluginContext context = commercialAutoRequest.context();
    Collection<Installment> installments = commercialAutoRequest.installments();
    InstallmentLattice installmentLattice = commercialAutoRequest.installmentLattice();

    log.info(
            "Received InstallmentsPlugin request for context: {}, installments: {} and installmentLattice: {}",
            context,
            installments,
            installmentLattice);

    DataFetcher dataFetcher = DataFetcher.getInstance();
    Policy policy = dataFetcher.getPolicy(context.policyLocator().orElseThrow());

    Instant now = Instant.now();
    ZoneId zoneId = ZoneId.of(policy.timezone());
    ZonedDateTime zonedDateTime = now.atZone(zoneId);
    ZonedDateTime nextMonthDayOne = zonedDateTime.plusMonths(1).withDayOfMonth(1).toLocalDate().atStartOfDay(zoneId);
    Instant newGenerateTime = nextMonthDayOne.toInstant();

    Map<String, InstallmentUpdate> installmentUpdates = new HashMap<>();

    for (Installment installment : installments) {
        if (installment.generateTime().isBefore(newGenerateTime)) {
            InstallmentUpdate update =
                    InstallmentUpdate.builder()
                            .generateTime(newGenerateTime)
                            .dueTime(newGenerateTime.plusMillis(Duration.between(installment.generateTime(), installment.dueTime()).toMillis()))
                            .build();

            installmentUpdates.put(installment.locator().toString(), update);

            log.info(
                    "Updated installment {} to new generate time {} and due time {}",
                    installment.locator(),
                    newGenerateTime,
                    update.dueTime());
        } else {
            log.info(
                    "Installment {} was not updated because the old generate time {} is after the new generate time {}",
                    installment.locator(),
                    installment.generateTime(),
                    newGenerateTime);
        }
    }

    log.info("Returning installment updates: {}", installmentUpdates);

    return installmentUpdates;
}
```

Next Steps [#next-steps]

* [Autopay Plugin](/configuration/plugins/autopay-and-payment-execution)

See Also [#see-also]

* [Plugins Overview](/configuration/plugins/overview)
* [Installment Lattices](/features/billing/installments-and-installment-lattices)
* [Installment Settings](/features/billing/installment-settings)
* [Plugin Data Fetcher](/configuration/plugins/overview#PluginDataFetcher)
