S++Business systems language
DEMO SOURCE · SPP / APP / PHYRead the book

cboddeposit-60-accrual.spp

cboddeposit/accrual/cboddeposit-60-accrual.spp

Download original file · Bank deposit source contents

1domain cboddeposit;23Role DepositAccrualPlan {4    int endDate;5    int normalDays;6    int overdraftDays;7    BigDecimal(25, 2) normalIncrement;8    BigDecimal(25, 2) agreementIncrement;9    int principalDays;10    int interestDays;11    BigDecimal(25, 2) overdraftIncrement;12    BigDecimal(25, 2) overdraftInterestIncrement;13}1415atomic check checkAccrualPolicy(DepositAccount, DepositInterestPolicy) {16    require(17        DepositInterestPolicy.normalUnit > 0 && DepositInterestPolicy.overdraftUnit > 0,18        "INVALID_ACCRUAL_UNIT"19    );20    require(DepositAccount.overdraftPrincipal >= 0, "E1155");21}2223atomic calculate prepareAccrualDates(DepositAccrualState, BusinessDay, BankDate start, BankDate end) {24    start.encoded = DepositAccrualState.lastProductDate;25    end.encoded = BusinessDay.date;26}2728atomic calculate prepareNormalAccrualPeriod(DepositAccount, DepositInterestPolicy, InterestPeriod) {29    InterestPeriod.amount = 0;30    if (DepositInterestPolicy.normalEnabled) {31        InterestPeriod.amount = DepositAccount.interestBase;32    }33    InterestPeriod.unit = DepositInterestPolicy.normalUnit;34}3536// CSAPRD4 uses ACT days for overdraft independently of the normal interest calendar.3738atomic calculate calculateAccrual(39    DepositAccount,40    DepositInterestPolicy,41    InterestPeriod,42    InterestProduct,43    BankDate start,44    BankDate end,45    DepositAccrualPlan46) {47    DepositAccrualPlan.endDate = end.encoded;48    DepositAccrualPlan.normalDays = InterestPeriod.days;49    DepositAccrualPlan.overdraftDays = end.epochDay - start.epochDay;50    DepositAccrualPlan.normalIncrement = InterestProduct.product;51    DepositAccrualPlan.overdraftIncrement = roundDown(52        DepositAccount.overdraftPrincipal / DepositInterestPolicy.overdraftUnit,53        054    ) * DepositInterestPolicy.overdraftUnit * DepositAccrualPlan.overdraftDays;55    DepositAccrualPlan.overdraftInterestIncrement = roundDown(56        (DepositAccount.overdraftInterest57            + DepositAccount.collectionInterest)58            / DepositInterestPolicy.overdraftUnit,59        060    ) * DepositInterestPolicy.overdraftUnit * DepositAccrualPlan.overdraftDays;61}6263atomic calculate accumulateAccrual(DepositAccrualState, DepositAccrualPlan) {64    DepositAccrualState.lastProductDate = DepositAccrualPlan.endDate;65    DepositAccrualState.normalProduct += DepositAccrualPlan.normalIncrement;66    DepositAccrualState.overdraftProduct += DepositAccrualPlan.overdraftIncrement;67    DepositAccrualState.overdraftInterestProduct += DepositAccrualPlan.overdraftInterestIncrement;68    DepositAccrualState.actualProduct = DepositAccrualState.normalProduct69        - DepositAccrualState.overdraftProduct;70    DepositAccrualState.overdraftDays += DepositAccrualPlan.principalDays;71    DepositAccrualState.overdraftInterestDays += DepositAccrualPlan.interestDays;72    DepositAccrualState.agreementProduct += DepositAccrualPlan.agreementIncrement;73}7475atomic check checkAccrualDates(76    DepositAccrualState,77    BusinessDay,78    InterestCalendar,79    AgreementTerm,80    AgreementBand[]81) {82    require(83        isGregorianDate(DepositAccrualState.lastProductDate) && isGregorianDate(BusinessDay.date),84        "EE374"85    );86    require(DepositAccrualState.lastProductDate <= BusinessDay.date, "E1175");87    require(88        InterestCalendar.convention == "ACT"89            || InterestCalendar.convention == "360365"90            || InterestCalendar.convention == "360360",91        "EEC28"92    );93    require(AgreementTerm.effectiveDate == 0 || isGregorianDate(AgreementTerm.effectiveDate), "EE374");94    require(AgreementTerm.cancelDate == 0 || isGregorianDate(AgreementTerm.cancelDate), "EE374");95    int expected = 5;96    for (AgreementBand band : AgreementBand[]) {97        require(band.slot == expected && band.threshold >= 0, "INVALID_AGREEMENT_BANDS");98        expected--;99    }100    require(expected == 0, "INVALID_AGREEMENT_BANDS");101}102103// All local mathematical intermediate participants are created in a calculation atom.104105atomic calculate calculateDepositAccrual(106    DepositAccount,107    BusinessDay,108    DepositAccrualState,109    DepositInterestPolicy,110    InterestCalendar,111    AgreementTerm,112    AgreementPolicy,113    AgreementBand[],114    DepositAccrualPlan115) {116    BankDate start = new BankDate();117    BankDate end = new BankDate();118    BankDate clippedStart = new BankDate();119    BankDate clippedEnd = new BankDate();120    InterestPeriod normal = new InterestPeriod();121    InterestPeriod overlap = new InterestPeriod();122    InterestProduct normalProduct = new InterestProduct();123    AgreementProduct products = new AgreementProduct();124    prepareAccrualDates(DepositAccrualState, BusinessDay, start, end);125    decodeBankDate(start);126    decodeBankDate(end);127    prepareNormalAccrualPeriod(DepositAccount, DepositInterestPolicy, normal);128    calculateBankDays(start, end, InterestCalendar, normal);129    AgreementPolicy.enabled = DepositInterestPolicy.normalEnabled && AgreementPolicy.enabled;130    prepareAgreementWindow(131        start,132        end,133        AgreementTerm,134        clippedStart,135        clippedEnd,136        normal,137        overlap,138        AgreementPolicy139    );140    decodeBankDate(clippedStart);141    decodeBankDate(clippedEnd);142    calculateBankDays(clippedStart, clippedEnd, InterestCalendar, overlap);143    calculateAgreementProduct(normal, overlap, AgreementPolicy, AgreementBand[], products);144    calculateInterestProduct(normal, normalProduct);145    calculateAccrual(146        DepositAccount,147        DepositInterestPolicy,148        normal,149        normalProduct,150        start,151        end,152        DepositAccrualPlan153    );154    DepositAccrualPlan.normalIncrement = products.normalProduct;155    DepositAccrualPlan.agreementIncrement = products.bandProduct;156    DepositAccrualPlan.principalDays = 0;157    DepositAccrualPlan.interestDays = 0;158    if (DepositAccount.overdraftPrincipal > 0) {159        DepositAccrualPlan.principalDays = DepositAccrualPlan.overdraftDays;160    }161    if (DepositAccount.overdraftInterest > 0) {162        DepositAccrualPlan.interestDays = DepositAccrualPlan.overdraftDays;163    }164}