|
| 1 | +// |
| 2 | +// Licensed to the Apache Software Foundation (ASF) under one |
| 3 | +// or more contributor license agreements. See the NOTICE file |
| 4 | +// distributed with this work for additional information |
| 5 | +// regarding copyright ownership. The ASF licenses this file |
| 6 | +// to you under the Apache License, Version 2.0 (the |
| 7 | +// "License"); you may not use this file except in compliance |
| 8 | +// with the License. You may obtain a copy of the License at |
| 9 | +// |
| 10 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | +// |
| 12 | +// Unless required by applicable law or agreed to in writing, |
| 13 | +// software distributed under the License is distributed on an |
| 14 | +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | +// KIND, either express or implied. See the License for the |
| 16 | +// specific language governing permissions and limitations |
| 17 | +// under the License. |
| 18 | +// |
| 19 | + |
| 20 | += Working Capital Loan Charge-Off |
| 21 | + |
| 22 | +This documentation describes the Charge-Off feature for Working Capital Loans. |
| 23 | + |
| 24 | +Charge-off marks a loan account as charged off for accounting purposes. In the Working Capital Loan |
| 25 | +module it is modeled as a *pure accounting tag with no portfolio impact*: the loan stays `ACTIVE`, its |
| 26 | +schedule and balance are unchanged, and all other actions and calculations behave exactly as they do on |
| 27 | +a loan that is not charged off. This differs from the Term Loan implementation, whose charge-off carries |
| 28 | +interest-recalculation behaviour — Working Capital Loans have no interest concept, so that machinery does |
| 29 | +not apply here. |
| 30 | + |
| 31 | +[NOTE] |
| 32 | +==== |
| 33 | +Charge-off is an accounting treatment only. It does not change the schedule, balance or delinquency |
| 34 | +data returned by the existing Working Capital Loan APIs; the loan resource only gains the charged-off |
| 35 | +state fields (see <<wc-charge-off-read-model>>). The loan remains `ACTIVE` until its balance is cured, and the |
| 36 | +charged-off tag is never removed automatically — even if the loan is subsequently paid off. It is |
| 37 | +cleared only by an explicit undo. |
| 38 | +==== |
| 39 | + |
| 40 | +== Charge-Off a Loan |
| 41 | + |
| 42 | +Marks the loan account as charged off and creates a non-monetary charge-off transaction. |
| 43 | + |
| 44 | +* *Endpoint*: `POST /working-capital-loans/{loanId}/transactions?command=chargeOff` |
| 45 | +* *Permission*: `CHARGEOFF_WORKINGCAPITALLOAN` |
| 46 | + |
| 47 | +=== Supported Fields |
| 48 | + |
| 49 | +==== Mandatory Fields |
| 50 | + |
| 51 | +* `transactionDate` |
| 52 | +** The charge-off date. It may be backdated but must not be in the future, and must not be earlier than |
| 53 | +the last user transaction date (system transactions such as accrual or discount-fee amortization are ignored). |
| 54 | + |
| 55 | +* `locale` |
| 56 | + |
| 57 | +* `dateFormat` |
| 58 | + |
| 59 | +==== Optional Fields |
| 60 | + |
| 61 | +* `chargeOffReasonId` |
| 62 | +** Code value id from the `ChargeOffReasons` code. |
| 63 | + |
| 64 | +* `note` |
| 65 | +** Free-text note (up to 1000 characters). |
| 66 | + |
| 67 | +* `externalId` |
| 68 | +** External identifier for the charge-off transaction (up to 100 characters). |
| 69 | + |
| 70 | +=== Behaviour |
| 71 | + |
| 72 | +* A non-monetary `CHARGE_OFF` transaction is created for the charge-off amount, which is the outstanding |
| 73 | +balance as of the charge-off date. Because the charge-off date cannot precede the last user transaction, the |
| 74 | +current outstanding balance equals the as-of-date balance. |
| 75 | +* The transaction does *not* move the loan balance and is excluded from transaction replay. |
| 76 | +* The loan is flagged as charged off (`chargedOff = true`) and remains `ACTIVE`. |
| 77 | +* Repayments and payment, waiver or adjustment of *existing* charges remain allowed afterwards, so the |
| 78 | +balance can still be cured. While the loan is charged off, those credits are recognized as recovery |
| 79 | +income and discount-fee amortization is routed to the charge-off expense (see <<wc-charge-off-accounting>>). |
| 80 | +* Goodwill credit and payout refund are not supported while the loan is charged off; posting either one |
| 81 | +is rejected. |
| 82 | + |
| 83 | +.Charge-off request/response flow |
| 84 | +[plantuml,format=svg] |
| 85 | +.... |
| 86 | +@startuml |
| 87 | +actor User |
| 88 | +participant "Transactions API" as API |
| 89 | +participant "ChargeOff Write Service" as SVC |
| 90 | +participant "Accounting Processor" as ACC |
| 91 | +database "m_wc_loan" as DB |
| 92 | +
|
| 93 | +User -> API : POST .../transactions?command=chargeOff |
| 94 | +API -> SVC : chargeOff(loanId, command) |
| 95 | +SVC -> SVC : validate (active, not already charged off, date rules) |
| 96 | +SVC -> DB : mark loan charged off + create CHARGE_OFF txn |
| 97 | +SVC -> ACC : post charge-off journal entries |
| 98 | +SVC --> User : transaction id |
| 99 | +@enduml |
| 100 | +.... |
| 101 | + |
| 102 | +== Undo Charge-Off |
| 103 | + |
| 104 | +Reverses a charge-off that was applied in error. |
| 105 | + |
| 106 | +* *Endpoint*: `POST /working-capital-loans/{loanId}/transactions?command=undoChargeOff` |
| 107 | +* *Permission*: `UNDOCHARGEOFF_WORKINGCAPITALLOAN` |
| 108 | + |
| 109 | +Undo removes the charged-off tag, reverses the charge-off transaction and reverses its journal entries. |
| 110 | +It is only allowed when the charge-off is still the last user transaction, that is, when no user transaction |
| 111 | +has been posted after it (the same restriction as term and progressive loans). System transactions |
| 112 | +(accrual and discount-fee amortization) are not user transactions and therefore do not block undo. |
| 113 | + |
| 114 | +== Charge-Off Template |
| 115 | + |
| 116 | +Returns the data needed to prefill the charge-off form. |
| 117 | + |
| 118 | +* *Endpoint*: `GET /working-capital-loans/{loanId}/template?templateType=chargeOff` |
| 119 | + |
| 120 | +[cols="1,3"] |
| 121 | +|=== |
| 122 | +|*Field* |*Description* |
| 123 | + |
| 124 | +|`chargeOffAmount` |
| 125 | +|Auto-calculated outstanding balance as of the charge-off date. Read-only. |
| 126 | + |
| 127 | +|`chargeOffDate` |
| 128 | +|Suggested charge-off date, defaulting to the current business date. |
| 129 | + |
| 130 | +|`chargeOffReasonOptions` |
| 131 | +|Available `ChargeOffReasons` code values. |
| 132 | + |
| 133 | +|`currency` |
| 134 | +|Loan currency. |
| 135 | +|=== |
| 136 | + |
| 137 | +[#wc-charge-off-read-model] |
| 138 | +== Loan Read Model |
| 139 | + |
| 140 | +The Working Capital Loan resource exposes the charged-off state: |
| 141 | + |
| 142 | +[cols="1,3"] |
| 143 | +|=== |
| 144 | +|*Field* |*Description* |
| 145 | + |
| 146 | +|`chargedOff` |
| 147 | +|`true` when the loan is charged off, otherwise `false`. |
| 148 | + |
| 149 | +|`chargedOffOnDate` |
| 150 | +|The charge-off date. Only present while the loan is charged off. |
| 151 | + |
| 152 | +|`chargeOffReason` |
| 153 | +|The `ChargeOffReasons` code value selected at charge-off time, when one was provided. |
| 154 | +|=== |
| 155 | + |
| 156 | +== Validations |
| 157 | + |
| 158 | +[cols="1,3,2"] |
| 159 | +|=== |
| 160 | +|*Operation* |*Rule* |*Error code* |
| 161 | + |
| 162 | +|Charge-off |The loan must be active. |`error.msg.wc.loan.is.not.active` |
| 163 | +|Charge-off |The loan must not already be charged off. |`error.msg.wc.loan.is.already.charged.off` |
| 164 | +|Charge-off |The charge-off date must not be earlier than the last user transaction date. |`cannot.be.before.last.transaction.date` |
| 165 | +|Charge-off |The charge-off date must not be in the future. |`cannot.be.a.future.date` |
| 166 | +|Add charge |New charges cannot be added once the loan is charged off. |`error.msg.wc.loan.is.charged.off` |
| 167 | +|Undo charge-off |The loan must be charged off. |`error.msg.wc.loan.is.not.charged.off` |
| 168 | +|Undo charge-off |Undo is not allowed if any user transaction was posted after the charge-off. |`error.msg.wc.loan.charge.off.is.not.the.last.user.transaction` |
| 169 | +|=== |
| 170 | + |
| 171 | +[NOTE] |
| 172 | +==== |
| 173 | +A second charge-off on an already charged-off loan, and a second undo on a loan that is not charged off, |
| 174 | +both return a validation error. |
| 175 | +==== |
| 176 | + |
| 177 | +[#wc-charge-off-accounting] |
| 178 | +== Accounting |
| 179 | + |
| 180 | +Charge-off accounting applies to products configured with the *Accrual (deferred revenue amortization)* |
| 181 | +accounting rule. The charge-off transaction writes off the outstanding receivables against the charge-off |
| 182 | +expense. There is no interest leg — Working Capital Loans have no interest concept. |
| 183 | + |
| 184 | +[cols="1,2,2"] |
| 185 | +|=== |
| 186 | +|*Portion* |*Debit* |*Credit* |
| 187 | + |
| 188 | +|Principal |`CHARGE_OFF_EXPENSE` |`LOAN_PORTFOLIO` |
| 189 | +|Fee |`INCOME_FROM_CHARGE_OFF_FEES` |`FEES_RECEIVABLE` |
| 190 | +|Penalty |`INCOME_FROM_CHARGE_OFF_PENALTY` |`PENALTIES_RECEIVABLE` |
| 191 | +|=== |
| 192 | + |
| 193 | +Undo reverses these journal entries. The charge-off General Ledger accounts are configured per product |
| 194 | +through the Working Capital Loan product accounting mapping. |
| 195 | + |
| 196 | +=== While the Loan Is Charged Off |
| 197 | + |
| 198 | +Transactions posted while the loan carries the charged-off tag receive a different accounting |
| 199 | +treatment: credits that would normally reduce the portfolio or receivables are recognized as recovery |
| 200 | +income, and discount-fee amortization is recognized against the charge-off expense instead of |
| 201 | +discount-fee income. |
| 202 | + |
| 203 | +[cols="2,2,3"] |
| 204 | +|=== |
| 205 | +|*Transaction* |*Debit* |*Credit* |
| 206 | + |
| 207 | +|Repayment |
| 208 | +|`FUND_SOURCE` |
| 209 | +|`INCOME_FROM_RECOVERY` for the principal, fee and penalty portions; `OVERPAYMENT` for any overpaid |
| 210 | +excess |
| 211 | + |
| 212 | +|Charge adjustment |
| 213 | +|`INCOME_FROM_RECOVERY` |
| 214 | +|`LOAN_PORTFOLIO` / `FEES_RECEIVABLE` / `PENALTIES_RECEIVABLE` per portion |
| 215 | + |
| 216 | +|Discount-fee amortization |
| 217 | +|`DEFERRED_INCOME_LIABILITY` |
| 218 | +|`CHARGE_OFF_EXPENSE` (instead of `INCOME_FROM_DISCOUNT_FEE`) |
| 219 | +|=== |
| 220 | + |
| 221 | +Charge accrual keeps its regular treatment (receivable against fee/penalty income). Once the |
| 222 | +charge-off is undone, subsequent transactions return to the regular accounting treatment. |
| 223 | + |
| 224 | +== Permissions |
| 225 | + |
| 226 | +[cols="1,1,1"] |
| 227 | +|=== |
| 228 | +|*Code* |*Entity* |*Action* |
| 229 | + |
| 230 | +|`CHARGEOFF_WORKINGCAPITALLOAN` |`WORKINGCAPITALLOAN` |`CHARGEOFF` |
| 231 | +|`UNDOCHARGEOFF_WORKINGCAPITALLOAN` |`WORKINGCAPITALLOAN` |`UNDOCHARGEOFF` |
| 232 | +|=== |
| 233 | + |
| 234 | +== Out of Scope |
| 235 | + |
| 236 | +The following are intentionally not part of the first version: |
| 237 | + |
| 238 | +* Overriding the charge-off expense account per charge-off reason (currently the default |
| 239 | +`CHARGE_OFF_EXPENSE` account is used). |
| 240 | +* Fraud-expense routing (`CHARGE_OFF_FRAUD_EXPENSE`), which depends on the Working Capital Loan fraud |
| 241 | +feature. |
0 commit comments