Payment Funcionality migration strategy

Step 0. Review and adjustments to Payment Layer: 

Summary

We need to ensure that existing Payment Layer functionality can be used by the Social Protection modules. 

 

Great News:

 Bills and Invoices are using generic keys. We should be able to use them with no issues with Social Benefit Packages.

Not so great news:

PaymentPlan and GenericPlan are using benefit_id marked as Products.

  • GenericPlans are using following relation:

     benefit_plan = models.ForeignKey(Product, db_column="BenefitPlanID", on_delete=models.deletion.DO_NOTHING)

   

  • Currently existing calculation rules will not be compatible with the BenefitPlanPackages  (that are actually Products).

  • GenericPlans are not used in calculation rules explicitly (ContributionPlans are used).

 

Possible Approaches

Fastest option: 

One solution could be to mock existing structure in the BenefitPlan. However, it is unintuitive and probably will cost a lot of technical debt.

 

Best Option: 

In the long term, the best option would be to not rely on ORM objects and managers in terms of CalculationRules, but rather python Interfaces (that would free us from anything stored in the database, Interface could be implemented for Products, BenefitPlans and others). Different calculation rules rely on other IMIS objects, like PHs or Insurees. Those also could be resolved by set of Interfaces and model proxies. Downside is that this solution is time consuming. (We would need to check if there's capacity for this - to be checked with Patrick and Seweryn).

 

Other Options: 

In scope of coreMIS integration we can slightly refactor Payment Plans and remove GenericPlan-Product relation. ContributionPlans would still rely on Products but there would be another entity using BenefitPlan instead of Product.

Steps: 

  1. Migrate

benefit_plan field from GenericPlan to PaymentPlan. (It could be a new entity like ProductPlan [used explicitly by Products], using ContributionPlan will be simpler as we wouldn't have to make plenty of changes in CalculationRules).

  1. Do research on what calculation rules match Social Protection requirements.

  1. Create new calculation rules for social protection OR if there are some we can use then generify them with different Benefits if possible (follow approach with interfaces from previous point).  

  1. Create a new PaymentPlan model for the BenefitPlan (could be SocialBenefitPlan).

  • It’s not ideal as we would rather have single “PaymentPlan” interface which would be implemented by proxy models for BenefitPlan and PaymentPlan but currently there are plenty of imports to change and it would be rather big rework for calc rules 

Downside: 

This will obscure how Graphql and Service classes will looks like (we would combine 2 different models under one source and there would be plenty of ifs)

OR

To avoid downside from the previous option we could add a mandatory “Type” field to the PaymentPlan. Currently it could be “InsuranceProduct” or “SocialBenefit”. We still would need to alternate calculation rules and (for now) handle only the “InsuranceProduct” type or implement a solution with an interface. This would allow us to create different types of interfaces for different paymentPlan types. This will require migration from benefit_id from Product reference to generic foreign key. 

 

 

 

Generic Payment Plan: 

code = models.CharField(db_column="Code", max_length=255, blank=True, null=True)

name = models.CharField(db_column="Name", max_length=255, blank=True, null=True)

calculation = models.UUIDField(db_column="calculationUUID", null=False)

benefit_plan = models.ForeignKey(Product, db_column="BenefitPlanID", on_delete=models.deletion.DO_NOTHING)

periodicity = models.IntegerField(db_column="Periodicity", null=False)

benefit_plan_type = models.ForeignKey(ContentType, models.DO_NOTHING, null=False, unique=False)

benefit_plan_id = models.CharField(null=False)  # object is referenced by uuid

benefit_plan = GenericForeignKey('benefit_plan_type', 'benefit_plan_id')

 

Then we need to decide if dispatching data is on CalcRule or Model site: 

If on models site then: 

Create Calculation Rule interface that is used (instead of things like Product.objects.get(uuid=payment_plan.benefit_id).specific_product_field it should be CalculationSubject.get_amount())

And there should be Proxy model for the PaymentPlan with implementation of this interface. E.g. PamentPlanCommisionCalcRule

 

However, as Calculation Rules can be added and should be easily added to the PaymentPlans (not the other way around), then we should add interface on CalcRule module. 

For instance: 

CalculationSubject(): 

   Def get_amount(payment_plan): 

       If payment_plan.type == ‘product’:

           Return product.benefit_plan.ceiling 

      Elif payment_plan.type == ‘benefitplan’: 

           Return payment_plan.json_ext[‘amount’]

    Else:

Raise notImplemented()

Requirements

  • Create Payment Plans for benefit plans

User stories:

As a Payment Plan manager I want to be able to choose Benefit Type in the PaymentPlan view (at the moment Product or BenefitPlan).

As a Payment Plan manager I want to have a dropdown with calculation rules relevant only for a given type of benefit (e.g. fee for service can be available only for the Product).

As a Payment Plan manager I want to have dropdown with Products/Benefit Plans for selected Benefit Type 

 

Use cases: 

Use Case1. Create Payment Plan

  • Actors: Payment Plan Manager, Contribution Plan Module, Product CalculationRule 

  • Preconditions: Modules Installed, Manager has rights to create new Plans 

  • Main Flow:

    1. Payment Plan Manager goes to Legal and Finance -> Payment Plans 

    2. Payment Plan Manager created new Payment Plan 

    3. Payment Plan Manager selects “Product” Benefit Type from dropdown 

      • If only one Benefit Type is available it’s automatically selected

    4. New dropdowns: CalculationRules and Product dropdown appear and contains relevant Calculation Rules and Insurance Products

    5. Payment Plan Manager Selects Calculation rule and Product 

    6. Additional Parameters menu appears 

    7. Payment Plan Manager fills additional parameters menu. 

    8. All required field are filled and Payment Plan can be saved 

    9. Payment Plan Manager saves PaymentPlan and gets confirmation.

      • PaymentPlan is saved as InsureeProductPaymentPlan (type)

  • Alternative course:
    For step 3:

    1. Payment Plan Manager selects “Benefit Plan” Benefit Type from dropdown

    2. New dropdowns: CalculationRules and BenefitPlan dropdown appear and contains relevant Calculation Rules and Insurance Products

    3. Payment Plan Manager Selects Calculation rule and Benefit Plan 

    4. Additional Parameters menu appears 

    5. Payment Plan Manager fills additional parameters menu. 

    6. All required field are filled and Payment Plan can be saved 

    7. Payment Plan Manager saves Payment Plan and gets confirmation.

      • PaymentPlan is saved as SocialBenefitPaymentPlan (type)

  • Postconditions: New PaymentPlan is available and listed 

 

  • List SocialBenefitPaymentPlan Payment Plans

User stories:

As a Payment Plan Manager I want to filter Payment Plans based on type. 

 

 

Questions:

  1. How to determine what Calculation Rules refers to what BenefitType?

  • Additional Array in frontend contribution?

  • Configured on backend calc rule definition and used by frontend?

 

 

 

 

 

 

Step 1. Payment value 

Summary 

Payment value is used to determine what amount will be delivered to the beneficiary assuming that certain criteria are met. This will vary between different benefit plans and should be highly customizable. 

We need to include (on the payment plan level) functionality that will allow us to determine what amount is to be paid for beneficiary in a single batch. 

There is fixed batch (same value for all beneficiaries) and variable amount (based on several rules):

  1. Value can be added to flat-rate amount based on certain conditions 

  2. 2 types of amounts:

    1. One counted up to ceiling, e.g. beneficiary meets plenty of rules that would triple their payment, however maximum they can get is still some predetermined max amount 

    2. One without limitations and don’t count towards the ceiling (because they could be transaction fees and don’t go directly to the beneficiary but are used to perform operations)

  3. Could include a rule when variable amount include previous uncollected payments 

  4. Limits per single transaction payment - flag transaction and take action 

 

Calculations for benefit plans can be done based on calculation rules, however execution is yet to be determined

Under the social protection menu we can add a new View called for example “Payment Cycles” which will allow us to create a new Payment Cycle for a Payment Plan.

 

Possible Approaches 

a) and b) can be implemented using a mix of calculation rules and custom filters. Additional Parameters for BenefitPlan would be an expandable list with input contained of custom filter, type of value and rate. 

Example: 

 

Flat value: 

>=0 (base for all payments)

Max amount: 

>0 and < flat value

Custom filter rule

Count to max False

Fixed Amount 

Custom filter rule

Count to max True

Calculated amount? 

 

c) This could be added as a new parameter in the Additional Parameters

 

Include previous uncollected payments? 

True / False 

 

d)  Transaction limits could be set on the plan level, we don’t have flows at the moment however this will rely on them (waiting for Patrick’s document and development of the multi level approval)

 

Development Note: Calculation Rules shouldn’t be implemented for the ORM Models but for Particular interfaces. This will allow us to handle different types of Benefit plans (group/individual) in scope of single rule and reduce complexity in the Payment Plan setup.   

Flow 

 

@startuml

start

:Trigger Payment Plan Batch;

repeat

  :Fetch BenefitPlanPackage ;

  :payment=PaymentPlan.baseAmount

maxAmount=PaymentPlan.ceiling-payment

userVariableAmount=0;

  repeat

  :Get next Variable Amount Calculation;

  if (BenefitPlanContition not met (custom filter)) then (yes)

  elseif (Does amount apply for limitations) then (no)

:payment += calculatedAmount;

  elseif (userVariableAmount exceed maxAmount) then (no)

:userVariableAmount += calculatedAmount;

endif

repeat while (next BenefitPlanCondition available?) is (yes)

if (maxAmount >= userVariableAmount) then (yes)

:payment += userVariableAmount;

else (no)

:payment += maxAmount;

endif

if (include previous uncollected payments?) then (yes)

  repeat

  :Add uncollected payments;

  note left: Moving invoice from previous payment?

repeat while (previous payment cycle exists)

else (no)

endif

:create new invoice for calculated payment;

if (exceeds payment limit) then (yes)

 :flag invoice to confirmation;

 :set invoice to SUSPENDED;

else (no)

endif

repeat while (next benefit package available?) is (yes)

 

stop

 

@enduml

 

 

Questions: 

How to handle uncollected payments? Simply adding them to paid amount might be unintuitive and it’d be good to keep track of the uncollected payments. 

Requirements 

  • Create Benefit Plan Payment Rules

User stories:

As a Payment Plan manager I want to have the ability to establish rules for calculating payments for beneficiaries based on fixed values and conditional amounts based on filters

As a Payment Plan manager I want to set payment ceiling for conditional amount 

As a Payment Plan manager I want to determine if given conditional amount is used in calculation of ceiling 

As a Payment Plan manager I want to determine payment limit per beneficiary

As a Payment Plan manager I want to determine if previous uncollected payments should be included in the run.

 

[TODO: Add Use Cases]

  • Approve Exceeded Payments 

User stories

As an Accountant I want to list all payments that were suspended due to exceeded payment limit

As an Accountant I want to approve/reject exceeded payments  

 

[TODO: Add Use Cases]

 

 

Note: This point doesn’t cover execution of the given payment plan. Execution will be done as a Payment Cycle (Payment Cycle can be treated as a Batch execution for a particular payment plan in a particular period). 

Step 2. Payment Cycle 

Summary 

Payment cycle can be treated as an accounting period. It will be created based on the Payment Plan (its calculation rules as well as periodicity).  

Each payment cycle has: 

  • Start date and end date (in coreMIS) - used to flag payments as delivered on time

  • Rebates configuration, 

  • amount to be received per beneficiary in the payroll, 

    • for payrolls using the PPM App, the maximum allocated amount to be carried by the Payment Point Manager

  • Allows rejection of payment cycle 

  • Allows for a maker-checker flow to approve payment cycles before they can be used.

Possible approaches 

As we want to rely on the Payment Layer the Payment Cycle at its current form would serve a different purpose. Most of the setup and configuration will be done in the Payment Plan. Accordingly: 

  • Start and end date - this would be based on the Payment Plan cycle. Payment Plan has periodicity calculated in the number of months. If we would like to keep the same approach then each cycle would be based on the periodicity and start date. We still need to make a decision on how to set the start date. It can be: 

    • First day of month 

    • N-th month day date chosen on the payment plan level

    • Be based on the BenefitPlan definition (starting from Date Valid From and lasts until Date Valid To)

Then creating new Payment Cycles would depend on the consecutive periods calculated on those criteria and already created payment plans. 

For example: 

Payment plan has periodicity = 3 and it’s for payment plan valid from 1st Jan 2020 until 31 Dec. 2022. 

This will allow us to create 8 payment cycles in scope of this project (if cycle was created for e.g. 2 quarter of 2021 it will not be possible to create another one for this period).

  • Rebates would be configured on the Payment Plan level. They will be automatically applied to created invoices during creation of the PaymentCycle

  • Amount to be received will be calculated based on the payment plan definition. 

  • As for maker-checker flow we could create the Payment Cycle in DRAFT state and all Invoices would also be set to DRAFT. Then after approval is done it can be worked on later on.  

 

Questions: 

Should there be any set of rules/conditions that have to be fulfilled before a given payment plan can be moved from the draft state. For instance: no blocked payments? 

 

 

@startuml

actor   Accountant   as A

boundary PaymentCycleView as PPV

control PaymentCycleControler as PC

control PaymentPlanControler as PP

entity  InvoiceORM  as I

collections "Calculation Rules" as CL

 

A --> PPV: Create new payment cycle\n

PPV --> PC: new PaymentCycle(paymentPlan, period)

PC --> PP: triggerBatch(paymentPlan, cycle)

PP --> CL: runBatch(benefitPlan, period)

CL --> I: Create invoices

CL --> PP: Return created invoices

PP --> PC: Success(invoices)

PC --> I: Add invoices to payment cycle

PC --> PPV: Success

PPV --> A: Success

 

@enduml

 

 

Example flow is based on triggering logic implemented in Step 1. and then making a relation between created invoices and newly created PaymentCycle. 

 

Note: If we would like to take an approach when cycles are independent from benefit plans then invoices for benefit plans would become line items in invoices. 

 

Note 2: This solution doesn’t include the possibility to reject payment cycles. We could say that payment cycle can be recreated if it’s not reconciled or that we can freely edit invoices in scope of the particular payment plan. It depends on the reason why given payment plan should be rejected 

Requirements 

  • Create new PaymentCycle

User Stories 

As an accountant I want to be able to create new payment cycle based on the existing Payment Plans 

As an accountant I want to make sure that invoices created for specific periods are not duplicated 

 

[TODO: Add Use Cases]

  • Flow to approve payment cycles before they can be used

User Stories 

As an payment manager I want to be able to approve payment cycle before payments are distributed 

 

[TODO: Add Use Cases]

  • Reject PaymentCycle

Not Applicable at the moment 

 

 

 

Step 3. Payment Points 

Summary 

Payment points are an aggregation method that allows splitting payrolls into smaller subgroups which results in better management of beneficiaries. 

We need to be able to: 

  • Create Payment Points 

  • Use known criteria to create payment points automatically

  • Review the criteria used in creation of subgroups

  • Allows rejection of payment points

  • Approval flow 

Suggested Solution 

Choice will depend on how often criteria change and at which point payment points are determined on business level. We could create Payment Points on several levels: 

  • Global - when Payment Points are independent from the Benefit Plans and can be shared

  • Benefit Plan - when Payment Points are know and fixed during the life of the social project and are shared between multiple payment plans 

  • Payment Plan - when Payment Points  are depending on the Payment Types and are different for multiple payment methods. 

  • Payment Cycle - when each payment cycle has it’s own setup of the Payment Points 

 

Place where Payment Points are set is not blocking as most likely the flow will remain the same. 

 

Payment point manager will create a set of custom filter rules that will assign matching beneficiaries to the particular payment point. If filters are overlapping then either exception is thrown or beneficiary is assigned to the first matching group.

 

We need to confirm if “standard” custom filters will be sufficient or if we have to extend it. For example, we could create groups like: 

 

Location Code

Equals 

R1D1V1

 

And create point for this specific location, but there’s an option that aggregation on property level could be desired: 

 

Aggregation 

Location Code 

 

That would create payment points for each available location code. If we want to use the latter it’ll require additional development as it’s outside of scope for existing filters. 

 

Example Picker for Payment Points: 

 

Payment Points 

 

 

 

Name: PP1

Filter Filed Location Code

Filter Type Equal

Value R1D1V1

 

Filter Filed Age

Filter Type GTE

Value 10

Name: PP2

Filter Filed Location Code

Filter Type Non Equal

Value R1D1V1

 

Filter Filed Age

Filter Type LTE

Value 10

 

Would configure 2 payment points. 

 

If we assume that payment points are stored on PaymentPlan level then Payment Points would be created and managed from PaymentPlan level. 

When a new payment cycle is created then bills and invoices would be assigned to proper payment points by the calculation rule. 

 

How payment points are created :

@startuml

actor   PaymentPointAdministrator   as A

boundary PaymentPlanView as PPV

control PaymentPlanControler as PPC

control PaymentPointControler as PP

control BenefitPlanControler as BF

entity  InvoiceORM  as I

collections "Calculation Rules" as CL

 

A --> PPV: Create new payment point

PPV --> BF: Fetch custom filters for benefit plan

BF --> PPV: Send custom filter options

PPV --> A: give custom filters

loop Create payment points

A --> PPV: Create new PaymentPoint

A --> PPV: Set filters for Payment Point

end

A --> PPV: Save payment points

PPV --> PPC: send payment points

PPC --> PP: createPaymentPoints(payment points, paymentPlan)

PP --> PPC: success

PPC --> PPV: success

PPV --> A: success

@enduml

 

 

How payment points are utilized: 

 

@startuml

control PaymentCycleControler as PCC

participant EventHub as E

control PaymentPointControler as PP

control BenefitPlanControler as BF

entity  InvoiceORM  as I

 

PCC --> E: PaymentCycleCreatedEvent

E --> PP: SendSignal(paymentCycle)

loop for each invoice in paymentCyce

PP --> I: Get invoice

PP --> PP: Get invoice beneficiary

alt Beneficiary matches PaymentPoint criteria

PP--> PP: Add invoice to payment point

else

end

 

end

@enduml

 

 

Requirements 

  • Define Payment Points 

User stories 

As Payment Point Administrator I want to create rules that determine if given payment should be done in scope of specific payment point 

As Payment Point Administrator I want to edit conditions.  

  • Connect Payment Points with payments 

  • Approval flow 

Step 4. Payment managers 

Summary

  • Allows for the creation of payment point managers

  • Allows searching of payment point managers

  • Allows to view details of payment point managers

  • Allows maker checker flow to approve payment point managers

Proposed solution

Add new system role.

Extend payment point picker: 

 

Payment Points 

 

 

 

 

Name: PP1

Filter Filed Location Code

Filter Type Equal

Value R1D1V1

PPM: User A

 

Filter Filed Age

Filter Type GTE

Value 10

 

Name: PP2

Filter Filed Location Code

Filter Type Non Equal

Value R1D1V1

PPM: User A

 

Filter Filed Age

Filter Type LTE

Value 10

 

 

To be checked if PolicyHolder can take this role. 

Questions: 

  • What level of access should PPM have?

  • Does PPM have some specific attributes depending on the type of PaymentPlan (is PPM data different for Urban and Rural payments?)

  • Can we have > 1 PPM for payment points? 

Requirements

  • Add new PPMs 

  • Attach PPMs to the Payment Points 

Step 4. Digital Payments Payroll

Summary

Payroll for digital payments allows creation of payroll that can be paid digitally. 

As in the scope of a single benefit plan we can have beneficiaries that use either digital or on site payments we need to have a way to determine the payment method. 

It should be possible to receive a summary of the invoices included in the payroll and summary of the total and number of unique invoices. 

Invoices can be marked as duplicates. 

Read-only csv of invoices can be downloaded.

Searching for invoices in payroll.

Rejection of payroll. 

Maker-checker flow. 

Feature to create PDF reports of invoices after approval. 

Summary of total invoices and balance from digital account before payment can be started. 

Allow integration with multiple Payment Service Providers 

Report of invoices that were and were not paid successfully.

 

Proposed Solution

Payrolls in openIMIS are defined as all invoices created in scope of the single payment cycle for specific calculation rules. 

In the Additional Attributes menu we will need to add a new section regarding the Payroll Method defined by a set of custom rules. 

Nice to have: Define payment method indicators on benefit plan level and then choose it from dropdown in PaymentPlan instead of creating a new set of rules. 

 

Payment Method Indicator 

Custom filter rule

Filter Type 

Filter Value  

Custom filter rule

Filter Type 

Filter Value  

 

As for the summary of the invoices it can be created in the PaymentCycle view. When we will have access to all invoices created in scope of single Payroll then by clicking on the icon we could display a summary (total number and unique invoices). 

 

Marking duplicates should not be necessary. As we assume that one beneficiary will belong only to one PaymentPlan there should be no duplicates. 

After payroll (by PaymentCycle batch) then all invoices should be in DRAFT state. We could add rejections of the invoices there.

 

Export and search will be done using search criteria.  

 

As payrolls are created by the PaymentCycle batches, rejection of payrolls doesn’t seem to be necessary. 

 

PDF Report can be done using reporting and ReporBro, we need to determine aggregations and fields. 

 

As for making payments via API integration - flow needs to be determined. At which point we want to make the calls? We could use search criteria to determine “batch” which allows us to send particular invoices for payments. 

 

Proposed Flow   

 

@startuml

actor Accountant as A

boundary  PaymentCyclesView as PCVs

boundary  PaymentCycleView as PCV

control   PaymentCycleController as PCC

collections PaymentServiceProvider as PPS

boundary  PaymentLayerAdapter as PLA

boundary ExternalPaymentSystem as EPS

entity InvoiceORM as I

 

A --> PCVs: Select specific payment cycle

PCVs --> PCV: Route to payment cycle

PCV --> A: Return specific payment cycle

A --> PCV: Select invoices for making payments

A --> PCV: Send invoices for payment

PCV --> PCC: Send invoices for payment

 

loop for each invoice

PCC --> PPS: Send Payment for invoice

PPS --> PLA: Send Payment

PLA --> EPS: Send Payment Request

EPS --> PLA: Acknowledge

PLA --> I: Change invoice status to validated

PLA --> PPS: Success

note right

To be checked how statuses

should be affected

end note

PPS --> PCC: Success

end

PCC --> PCV: Success

PCV --> A: Success

 

loop for each invoice

alt Payment successful

EPS --> PLA: Payment confirmation

PLA --> I: Change status to PAID

else Payment unsuccessful

EPS --> PLA: Payment declination

PLA --> I: Change status to CANCELLED

end

PLA --> PCC: Change invoice status to To Be Reconciled

end

 

A --> PCV: Reconcile payment cycle

PCV --> PCC: Reconcile payment cycle

PCC --> PCV: Success

PCV --> A: Success

 

@enduml

 

 

 

 

Questions: 

What data should be displayed in the payroll summary? 

What to do if a beneficiary is assigned by custom filters to more than one payment plan? Should we raise exceptions or assign them to the first available payment plan? 

What are the repercussions for further payments if the invoice is rejected? 

What data should be provided in the csv export? 

What is the relationship between payroll and payment service provider? Is it 1 provider - 1 payment point or 1 provider - 1 payroll?

 

Step 5. Payroll Creation for Payment Point Managers

Summary

The main point of this functionality is to allow the creation of payroll which will be paid by payment point managers. It’s also crucial to introduce actions which can be done at payrolls

Did you encounter a problem or do you have a suggestion?

Please contact our Service Desk



This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. https://creativecommons.org/licenses/by-sa/4.0/