wip: updates to accounting documentation

This commit is contained in:
Vishwas Babu AJ
2013-02-18 14:44:39 +05:30
parent abf075a0c0
commit 8975d1ff58
7 changed files with 80 additions and 86 deletions
+58 -66
View File
@@ -8998,7 +8998,7 @@ GET https://DomainName/api/v1/permissions
<td>glCode</td> <td>glCode</td>
</tr> </tr>
<tr> <tr>
<td class=fielddesc>The Ledger code associated with the <td class=fielddesc>The ledger code associated with the
Account<br>These codes are mandatory and should be unique within Account<br>These codes are mandatory and should be unique within
an organization</td> an organization</td>
</tr> </tr>
@@ -9014,17 +9014,17 @@ GET https://DomainName/api/v1/permissions
</tr> </tr>
<tr> <tr>
<td class=fielddesc>Classifies the account into one of the following Types <td class=fielddesc>Classifies the account into one of the following Types
<br/><b>Asset accounts:</b> represent the different types of economic resources <br/><b>Asset:</b> represent the different types of economic resources
owned or controlled by business, common examples of Asset accounts are cash, owned or controlled by business, common examples of Asset accounts are cash,
cash in bank, building, inventory, prepaid rent, goodwill, accounts receivable<br/> cash in bank, building, inventory, prepaid rent, goodwill, accounts receivable<br/>
<b>Liability accounts:</b> represent the different types of economic obligations <b>Liability:</b> represent the different types of economic obligations
by a business, such as accounts payable, bank loan, bonds payable<br/> by a business, such as accounts payable, bank loan, bonds payable<br/>
<b>Income accounts:</b> represent the company's gross earnings and common examples <b>Income:</b> represent the company's gross earnings and common examples
include Interest Income, Sales and Service revenue<br/> include Interest Income, Sales and Service revenue<br/>
<b>Expense accounts:</b> represent the company's expenditures to enable itself to <b>Expense:</b> represent the company's expenditures to enable itself to
operate. Common examples are electricity and water, rentals, depreciation, operate. Common examples are electricity and water, rentals, depreciation,
doubtful accounts, insurance.<br/> doubtful accounts, insurance.<br/>
<b>Equity accounts:</b> represent the residual equity of a business (after <b>Equity:</b> represent the residual equity of a business (after
deducting from Assets all the liabilities) including Retained Earnings deducting from Assets all the liabilities) including Retained Earnings
and Appropriations <br/><br/> and Appropriations <br/><br/>
The options are fully listed in <a href="#glaccounts_template">Retrieve The options are fully listed in <a href="#glaccounts_template">Retrieve
@@ -9036,8 +9036,8 @@ GET https://DomainName/api/v1/permissions
</tr> </tr>
<tr> <tr>
<td class=fielddesc>Determines how the account shall be used<br> <td class=fielddesc>Determines how the account shall be used<br>
"Header" accounts specify the title of a group of accounts. Header accounts are used "Header" accounts specify the title of a group of accounts. They are used
only to group detail accounts that have a similar purpose; that is, detail accounts only for grouping together detail accounts that have a similar purpose; that is, detail accounts
are assigned to specific header accounts are assigned to specific header accounts
<br/> <br/>
"Detail" accounts may have transactions logged against them<br/><br/> "Detail" accounts may have transactions logged against them<br/><br/>
@@ -9049,7 +9049,7 @@ GET https://DomainName/api/v1/permissions
<td>manualEntriesAllowed</td> <td>manualEntriesAllowed</td>
</tr> </tr>
<tr> <tr>
<td class=fielddesc>Specifies if manual adjustments can be made <td class=fielddesc>Specifies if manual entries can be made
against this account using the <a href="#journalentries_create"> against this account using the <a href="#journalentries_create">
Create Journal Entries API</a> </td> Create Journal Entries API</a> </td>
</tr> </tr>
@@ -9074,7 +9074,7 @@ GET https://DomainName/api/v1/permissions
<dd> <dd>
Integer <span>optional</span> Integer <span>optional</span>
</dd> </dd>
<dt>manualAdjustmentsAllowed</dt> <dt>manualEntriesAllowed</dt>
<dd> <dd>
boolean <span>optional</span> boolean <span>optional</span>
</dd> </dd>
@@ -9091,7 +9091,7 @@ GET https://DomainName/api/v1/permissions
<div class=apiClick>glaccounts</div> <div class=apiClick>glaccounts</div>
<br> <br>
<br> <br>
<div class=apiClick>glaccounts?type=1&manualAdjustmentsAllowed=true&usage=1&disabled=false</div> <div class=apiClick>glaccounts?type=1&manualEntriesAllowed=true&usage=1&disabled=false</div>
</div> </div>
<div class="method-example"> <div class="method-example">
<code class="method-declaration"> <code class="method-declaration">
@@ -9266,8 +9266,8 @@ GET https://DomainName/api/v1/glaccounts/{glaccountsId}
<div class="method-description"> <div class="method-description">
<h4>Create a General Ledger Account</h4> <h4>Create a General Ledger Account</h4>
<p> <p>
<b>Note:</b> You can optionally<br> <b>Note:</b> You may optionally
create a Hierarchical Chart of Account by using the "parentId" create Hierarchical Chart of Accounts by using the "parentId"
property of an Account<br> property of an Account<br>
</p> </p>
<table class=matrixHeading> <table class=matrixHeading>
@@ -9275,7 +9275,7 @@ GET https://DomainName/api/v1/glaccounts/{glaccountsId}
<td><div class="mifosXHeading2">Mandatory Fields</div></td> <td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr> </tr>
<tr class=alt> <tr class=alt>
<td>name, glCode, classification, usage and manualEntriesAllowed <td>name, glCode, type, usage and manualEntriesAllowed
</td> </td>
</tr> </tr>
</table> </table>
@@ -9292,7 +9292,7 @@ Request Body:
"name": "Cash at Bangalore", "name": "Cash at Bangalore",
"glCode": "100017", "glCode": "100017",
"manualEntriesAllowed": true, "manualEntriesAllowed": true,
"classification": 1, "type": 1,
"usage": 1, "usage": 1,
"description": "Cash at Bangalore Branch" "description": "Cash at Bangalore Branch"
} }
@@ -9315,16 +9315,19 @@ Request Body:
PUT https://DomainName/api/v1/glaccounts/{glaccountId} PUT https://DomainName/api/v1/glaccounts/{glaccountId}
</code> </code>
<code class="method-request"> <code class="method-request">
PUT glaccounts/1 PUT glaccounts/22
Content-Type: application/json Content-Type: application/json
Request Body: Request Body:
{ {
"name": "Cash at Tumkur" "name": "Cash at Bangalore rural"
} }
</code> </code>
<code class="method-response"> <code class="method-response">
{ {
"resourceId": 1 "resourceId": 22,
"changes": {
"name": "Cash at Bangalore rural"
}
} }
</code> </code>
</div> </div>
@@ -9339,7 +9342,10 @@ Request Body:
</code> </code>
<code class="method-response"> <code class="method-response">
{ {
"resourceId": 1 "resourceId": 1,
"changes": {
"disabled": true
}
} }
</code> </code>
</div> </div>
@@ -9365,7 +9371,8 @@ No Request Body:
</code> </code>
<code class="method-response"> <code class="method-response">
{ {
"resourceId": 1 "resourceId": 1,
"changes": {}
} }
</code> </code>
</div> </div>
@@ -9376,8 +9383,9 @@ No Request Body:
<div class="method-description"> <div class="method-description">
<h3>Accounting Closure</h3> <h3>Accounting Closure</h3>
<p>An accounting closure indicates that no more journal <p>An accounting closure indicates that no more journal
entries may be logged or reversed in the system entries may be logged (or reversed) in the system,
(either manually or via the portfolio) prior to the closure date either manually or via the portfolio with an entry date
prior to the defined closure date
</p> </p>
<table class=matrixHeading> <table class=matrixHeading>
<tr class="matrixHeadingBG"> <tr class="matrixHeadingBG">
@@ -9448,7 +9456,6 @@ GET https://DomainName/api/v1/glclosures
"lastUpdatedByUserId": 1, "lastUpdatedByUserId": 1,
"lastUpdatedByUsername": "mifos", "lastUpdatedByUsername": "mifos",
"comments": "closed", "comments": "closed",
"allowedOffices": []
}, },
{ {
"id": 6, "id": 6,
@@ -9475,7 +9482,6 @@ GET https://DomainName/api/v1/glclosures
"lastUpdatedByUserId": 1, "lastUpdatedByUserId": 1,
"lastUpdatedByUsername": "mifos", "lastUpdatedByUsername": "mifos",
"comments": "hello", "comments": "hello",
"allowedOffices": []
} }
] ]
</code> </code>
@@ -9523,7 +9529,6 @@ GET https://DomainName/api/v1/glclosures/{glclosureId}
"lastUpdatedByUserId": 1, "lastUpdatedByUserId": 1,
"lastUpdatedByUsername": "mifos", "lastUpdatedByUsername": "mifos",
"comments": "closed", "comments": "closed",
"allowedOffices": []
} }
</code> </code>
</div> </div>
@@ -9554,14 +9559,15 @@ Request Body:
{ {
"officeId": 1, "officeId": 1,
"closingDate": "06 December 2012", "closingDate": "06 December 2012",
"comments": "The accountants are heading for a carribean vacation" "comments": "The accountants are heading for a carribean vacation",
"locale": "en" , "locale": "en" ,
"dateFormat": "dd MMMM yyyy" "dateFormat": "dd MMMM yyyy"
} }
</code> </code>
<code class="method-response"> <code class="method-response">
{ {
"resourceId": 1 "officeId": 1,
"resourceId": 9
} }
</code> </code>
</div> </div>
@@ -9571,7 +9577,7 @@ Request Body:
<div class="method-section"> <div class="method-section">
<div class="method-description"> <div class="method-description">
<h4>Update an Accounting closure</h4> <h4>Update an Accounting closure</h4>
<p>Once an accounting closure is created, only the comment associated with it can be edited <p>Once an accounting closure is created, only the comments associated with it may be edited
</p> </p>
</div> </div>
<div class="method-example"> <div class="method-example">
@@ -9588,22 +9594,11 @@ Request Body:
</code> </code>
<code class="method-response"> <code class="method-response">
{ {
"resourceId": 1 "officeId": 1,
} "resourceId": 1,
</code> "changes": {
</div> "comments": "All transactions verified by Johnny Cash"
<div class="method-example"> }
<code class="method-request">
PUT glclosures/1
Content-Type: application/json
Request Body:
{
"disabled": true
}
</code>
<code class="method-response">
{
"resourceId": 1
} }
</code> </code>
</div> </div>
@@ -9612,10 +9607,10 @@ Request Body:
<a id="glclosures_delete" name="glclosures_delete" class="old-syle-anchor">&nbsp;</a> <a id="glclosures_delete" name="glclosures_delete" class="old-syle-anchor">&nbsp;</a>
<div class="method-section"> <div class="method-section">
<div class="method-description"> <div class="method-description">
<h4>Delete An accounting closure</h4> <h4>Delete an accounting closure</h4>
<p> <p>
<b>Note:</b> Only the latest accounting closure <b>Note:</b> Only the latest accounting closure
associated with a branch may be closed. associated with a branch may be deleted.
</p> </p>
</div> </div>
<div class="method-example"> <div class="method-example">
@@ -9629,6 +9624,7 @@ No Request Body:
</code> </code>
<code class="method-response"> <code class="method-response">
{ {
"officeId": 1,
"resourceId": 1 "resourceId": 1
} }
</code> </code>
@@ -9641,7 +9637,7 @@ No Request Body:
<h3>Journal Entries</h3> <h3>Journal Entries</h3>
<p>A journal entry refers to the logging of <p>A journal entry refers to the logging of
transactions against general ledger accounts. A journal transactions against general ledger accounts. A journal
entry can consist of several line items, each of which is either a "debit" or a "credit". The total amount of the entry may consist of several line items, each of which is either a "debit" or a "credit". The total amount of the
debits must equal the total amount of the credits or the debits must equal the total amount of the credits or the
journal entry is said to be "unbalanced" <br/><br/> journal entry is said to be "unbalanced" <br/><br/>
A journal entry directly changes the account balances on A journal entry directly changes the account balances on
@@ -9707,19 +9703,13 @@ No Request Body:
of transactionId and entityId is unique of transactionId and entityId is unique
</td> </td>
</tr> </tr>
<tr class=alt>
<td>entryType</td>
</tr>
<tr>
<td class=fielddesc>Either a Credit(1) or a Debit(2)</td>
</tr>
<tr class=alt> <tr class=alt>
<td>portfolioGenerated</td> <td>portfolioGenerated</td>
</tr> </tr>
<tr> <tr>
<td class=fielddesc>Flag determines if an entry is <td class=fielddesc>Flag determines if an entry is
generated by the portfolio (posted automatically by generated by the portfolio (posted automatically by
the system during lifecycle of loan and saving the system during the lifecycle of loan or saving
products) or manually created by using the <a href=" products) or manually created by using the <a href="
journalentries_create">Create (Balanced) Journal journalentries_create">Create (Balanced) Journal
Entries</a> API Entries</a> API
@@ -9761,7 +9751,7 @@ No Request Body:
</dd> </dd>
<dd>Flag determines if portfolio generated Journal <dd>Flag determines if portfolio generated Journal
Entries (posted automatically by the system Entries (posted automatically by the system
during lifecycle of loan and saving products) during lifecycle of loan or saving products)
shall also be returned <br/> shall also be returned <br/>
Set to "True" by default if not passed in explicity Set to "True" by default if not passed in explicity
</dd> </dd>
@@ -9803,7 +9793,7 @@ GET https://DomainName/api/v1/journalentries?transactionId=PB37X8Y21EQUY4S
"glAccountName": "Something totally else", "glAccountName": "Something totally else",
"glAccountId": 17, "glAccountId": 17,
"glAccountCode": "340098", "glAccountCode": "340098",
"glAccountClassification": { "glAccountType": {
"id": 3, "id": 3,
"code": "accountType.equity", "code": "accountType.equity",
"value": "EQUITY" "value": "EQUITY"
@@ -9837,7 +9827,7 @@ GET https://DomainName/api/v1/journalentries?transactionId=PB37X8Y21EQUY4S
"glAccountName": "Something else", "glAccountName": "Something else",
"glAccountId": 19, "glAccountId": 19,
"glAccountCode": "560050", "glAccountCode": "560050",
"glAccountClassification": { "glAccountType": {
"id": 3, "id": 3,
"code": "accountType.equity", "code": "accountType.equity",
"value": "EQUITY" "value": "EQUITY"
@@ -9879,7 +9869,7 @@ GET https://DomainName/api/v1/journalentries?transactionId=PB37X8Y21EQUY4S
amounts are equal <br/> amounts are equal <br/>
Compound Journal entries may have "n" debits and "m" Compound Journal entries may have "n" debits and "m"
credits where both "m" and "n" are greater than 0 credits where both "m" and "n" are greater than 0
and the sum or all debits and all credits are equal and the net sum or all debits and credits are equal
<br> <br>
</p> </p>
<table class=matrixHeading> <table class=matrixHeading>
@@ -9901,9 +9891,9 @@ GET https://DomainName/api/v1/journalentries?transactionId=PB37X8Y21EQUY4S
in the journal entry. Each credit entry contains in the journal entry. Each credit entry contains
the following items <br/> the following items <br/>
glAccountId: Identifier of the general ledger glAccountId: Identifier of the general ledger
account against which credit entry shall be account against which the credit entry shall be
made <br/> made <br/>
amount: Amount of money involved in the credit amount: Amount of money credited
<br/> <br/>
comments: Optional description associated with comments: Optional description associated with
a credit entry a credit entry
@@ -9918,7 +9908,7 @@ GET https://DomainName/api/v1/journalentries?transactionId=PB37X8Y21EQUY4S
in the journal entry. Each debit entry contains the following items <br/> in the journal entry. Each debit entry contains the following items <br/>
glAccountId: Identifier of the general ledger account against which the debit entry shall be glAccountId: Identifier of the general ledger account against which the debit entry shall be
made <br/> made <br/>
amount: Amount of money involved in the debit amount: Amount of money debited
<br/> <br/>
comments: Optional description associated with comments: Optional description associated with
a debit entry a debit entry
@@ -9955,7 +9945,8 @@ Request Body:
</code> </code>
<code class="method-response"> <code class="method-response">
{ {
"resourceId": C1MAE935K0IAEYA "officeId": 1,
"transactionId": "DNEEMS2LPD0NJ9O"
} }
</code> </code>
</div> </div>
@@ -9979,13 +9970,13 @@ GET https://DomainName/api/v1/journalentries/{entryId}
</code> </code>
<code class="method-response"> <code class="method-response">
{ {
"id": 22, "id": 1,
"officeId": 2, "officeId": 2,
"officeName": "sub branch 1", "officeName": "sub branch 1",
"glAccountName": "Income from interest", "glAccountName": "Income from interest",
"glAccountId": 14, "glAccountId": 14,
"glAccountCode": "400001", "glAccountCode": "400001",
"glAccountClassification": { "glAccountType": {
"id": 4, "id": 4,
"code": "accountType.income", "code": "accountType.income",
"value": "INCOME" "value": "INCOME"
@@ -10024,7 +10015,8 @@ GET https://DomainName/api/v1/journalentries/{entryId}
<p> <p>
<b>Note:</b> A journal entry is reversed by logging debits <b>Note:</b> A journal entry is reversed by logging debits
for all credits that constitute the Journal entry and for all credits that constitute the Journal entry and
vice-versa vice-versa. The transactionId of the "reversal Entry" is returned
as the methods response
</p> </p>
<h5>Arguments</h5> <h5>Arguments</h5>
<dl class="argument-list"> <dl class="argument-list">
@@ -10045,7 +10037,7 @@ Content-Type: application/json
</code> </code>
<code class="method-response"> <code class="method-response">
{ {
"resourceId": C1MAE935K0IAEYA "transactionId": "YFDYMPBVVI9TRJP"
} }
</code> </code>
</div> </div>
@@ -61,6 +61,7 @@ public class GLClosureData {
this.lastUpdatedByUserId = lastUpdatedByUserId; this.lastUpdatedByUserId = lastUpdatedByUserId;
this.lastUpdatedByUsername = lastUpdatedByUsername; this.lastUpdatedByUsername = lastUpdatedByUsername;
this.comments = comments; this.comments = comments;
this.allowedOffices = null;
} }
public List<OfficeLookup> getAllowedOffices() { public List<OfficeLookup> getAllowedOffices() {
@@ -23,7 +23,6 @@ import org.mifosplatform.accounting.closure.api.GLClosureJsonInputParams;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.portfolio.loanaccount.guarantor.GuarantorConstants.GUARANTOR_JSON_INPUT_PARAMS;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
@Entity @Entity
@@ -65,7 +64,7 @@ public class GLClosure extends AbstractAuditableCustom<AppUser, Long> {
public static GLClosure fromJson(Office office, final JsonCommand command) { public static GLClosure fromJson(Office office, final JsonCommand command) {
Date closingDate = command.DateValueOfParameterNamed(GLClosureJsonInputParams.CLOSING_DATE.getValue()); Date closingDate = command.DateValueOfParameterNamed(GLClosureJsonInputParams.CLOSING_DATE.getValue());
String comments = command.stringValueOfParameterNamed(GUARANTOR_JSON_INPUT_PARAMS.COMMENT.getValue()); String comments = command.stringValueOfParameterNamed(GLClosureJsonInputParams.COMMENTS.getValue());
return new GLClosure(office, closingDate, comments); return new GLClosure(office, closingDate, comments);
} }
@@ -80,9 +79,8 @@ public class GLClosure extends AbstractAuditableCustom<AppUser, Long> {
if (command.isChangeInStringParameterNamed(paramName, propertyToBeUpdated)) { if (command.isChangeInStringParameterNamed(paramName, propertyToBeUpdated)) {
final String newValue = command.stringValueOfParameterNamed(paramName); final String newValue = command.stringValueOfParameterNamed(paramName);
actualChanges.put(paramName, newValue); actualChanges.put(paramName, newValue);
propertyToBeUpdated = newValue;
// now update actual property // now update actual property
if (paramName.equals(GUARANTOR_JSON_INPUT_PARAMS.COMMENT.getValue())) { if (paramName.equals(GLClosureJsonInputParams.COMMENTS.getValue())) {
this.comments = newValue; this.comments = newValue;
} }
} }
@@ -102,7 +102,7 @@ public class GLClosureWritePlatformServiceJpaRepositoryImpl implements GLClosure
} }
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withOfficeId(glClosure.getOffice().getId()) return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withOfficeId(glClosure.getOffice().getId())
.withEntityId(glClosure.getId()).build(); .withEntityId(glClosure.getId()).with(changesOnly).build();
} }
@Transactional @Transactional
@@ -121,8 +121,6 @@ public class GLAccount extends AbstractPersistable<Long> {
newValue = command.integerValueOfParameterNamed(paramName); newValue = command.integerValueOfParameterNamed(paramName);
} }
actualChanges.put(paramName, newValue); actualChanges.put(paramName, newValue);
propertyToBeUpdated = newValue;
// now update actual property // now update actual property
if (paramName.equals(GLAccountJsonInputParams.TYPE.getValue())) { if (paramName.equals(GLAccountJsonInputParams.TYPE.getValue())) {
this.type = newValue; this.type = newValue;
@@ -137,8 +135,6 @@ public class GLAccount extends AbstractPersistable<Long> {
if (command.isChangeInStringParameterNamed(paramName, propertyToBeUpdated)) { if (command.isChangeInStringParameterNamed(paramName, propertyToBeUpdated)) {
final String newValue = command.stringValueOfParameterNamed(paramName); final String newValue = command.stringValueOfParameterNamed(paramName);
actualChanges.put(paramName, newValue); actualChanges.put(paramName, newValue);
propertyToBeUpdated = newValue;
// now update actual property // now update actual property
if (paramName.equals(GLAccountJsonInputParams.DESCRIPTION.getValue())) { if (paramName.equals(GLAccountJsonInputParams.DESCRIPTION.getValue())) {
this.description = newValue; this.description = newValue;
@@ -155,8 +151,6 @@ public class GLAccount extends AbstractPersistable<Long> {
if (command.isChangeInLongParameterNamed(paramName, propertyToBeUpdated)) { if (command.isChangeInLongParameterNamed(paramName, propertyToBeUpdated)) {
final Long newValue = command.longValueOfParameterNamed(paramName); final Long newValue = command.longValueOfParameterNamed(paramName);
actualChanges.put(paramName, newValue); actualChanges.put(paramName, newValue);
propertyToBeUpdated = newValue;
// now update actual property // now update actual property
if (paramName.equals(GLAccountJsonInputParams.PARENT_ID.getValue())) { if (paramName.equals(GLAccountJsonInputParams.PARENT_ID.getValue())) {
// do nothing as this is a nested property // do nothing as this is a nested property
@@ -169,8 +163,6 @@ public class GLAccount extends AbstractPersistable<Long> {
if (command.isChangeInBooleanParameterNamed(paramName, propertyToBeUpdated)) { if (command.isChangeInBooleanParameterNamed(paramName, propertyToBeUpdated)) {
final Boolean newValue = command.booleanObjectValueOfParameterNamed(paramName); final Boolean newValue = command.booleanObjectValueOfParameterNamed(paramName);
actualChanges.put(paramName, newValue); actualChanges.put(paramName, newValue);
propertyToBeUpdated = newValue;
// now update actual property // now update actual property
if (paramName.equals(GLAccountJsonInputParams.MANUAL_ENTRIES_ALLOWED.getValue())) { if (paramName.equals(GLAccountJsonInputParams.MANUAL_ENTRIES_ALLOWED.getValue())) {
this.manualEntriesAllowed = newValue; this.manualEntriesAllowed = newValue;
@@ -1106,7 +1106,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
handleDisbursementTransaction(expectedDisbursedOnLocalDate); handleDisbursementTransaction(expectedDisbursedOnLocalDate);
} }
public Map<String, Object> deriveDisbursementData(final CurrencyData currencyData) { public Map<String, Object> deriveDisbursementData(final CurrencyData currencyData, final List<Long> existingTransactionIds) {
final Map<String, Object> accountingBridgeData = new LinkedHashMap<String, Object>(20); final Map<String, Object> accountingBridgeData = new LinkedHashMap<String, Object>(20);
@@ -1119,7 +1119,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
final List<Map<String, Object>> newLoanTransactions = new ArrayList<Map<String, Object>>(); final List<Map<String, Object>> newLoanTransactions = new ArrayList<Map<String, Object>>();
final List<LoanTransaction> disbursementTransactions = findDisbursementTransactions(); final List<LoanTransaction> disbursementTransactions = findDisbursementTransactions();
for (LoanTransaction loanTransaction : disbursementTransactions) { for (LoanTransaction loanTransaction : disbursementTransactions) {
newLoanTransactions.add(loanTransaction.toMapData(currencyData)); if (!existingTransactionIds.contains(loanTransaction.getId())) {
newLoanTransactions.add(loanTransaction.toMapData(currencyData));
}
} }
accountingBridgeData.put("newLoanTransactions", newLoanTransactions); accountingBridgeData.put("newLoanTransactions", newLoanTransactions);
@@ -1150,7 +1152,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} }
public Map<String, Object> disburse(final AppUser currentUser, final JsonCommand command, public Map<String, Object> disburse(final AppUser currentUser, final JsonCommand command,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final ApplicationCurrency currency) { final LoanLifecycleStateMachine loanLifecycleStateMachine, final ApplicationCurrency currency,
final List<Long> existingTransactionIds) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(); final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
@@ -1183,6 +1186,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
if (isRepaymentScheduleRegenerationRequiredForDisbursement(disbursedOn)) { if (isRepaymentScheduleRegenerationRequiredForDisbursement(disbursedOn)) {
regenerateRepaymentSchedule(currency); regenerateRepaymentSchedule(currency);
} }
existingTransactionIds.addAll(findExistingTransactionIds());
} }
return actualChanges; return actualChanges;
@@ -130,7 +130,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode()); final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode());
final Map<String, Object> changes = loan.disburse(currentUser, command, defaultLoanLifecycleStateMachine(), currency); /***
* In cases where an "Undo disbursement is done and the loan is
* disbursed again, we need to ensure the old transactions are entered
* again in accounting
***/
final List<Long> existingTransactionIds = new ArrayList<Long>();
final Map<String, Object> changes = loan.disburse(currentUser, command, defaultLoanLifecycleStateMachine(), currency, existingTransactionIds);
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.loanRepository.save(loan); this.loanRepository.save(loan);
@@ -139,7 +145,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note); this.noteRepository.save(note);
} }
final Map<String, Object> accountingBridgeData = loan.deriveDisbursementData(currency.toData()); final Map<String, Object> accountingBridgeData = loan.deriveDisbursementData(currency.toData(), existingTransactionIds);
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
} }
@@ -271,10 +277,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanTransaction newTransactionDetail = loan.adjustExistingTransaction(transactionDate, transactionAmount, final LoanTransaction newTransactionDetail = loan.adjustExistingTransaction(transactionDate, transactionAmount,
defaultLoanLifecycleStateMachine(), transactionToAdjust); defaultLoanLifecycleStateMachine(), transactionToAdjust);
if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) { if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
this.loanTransactionRepository.save(newTransactionDetail); this.loanTransactionRepository.saveAndFlush(newTransactionDetail);
} }
this.loanRepository.save(loan); this.loanRepository.saveAndFlush(loan);
final String noteText = command.stringValueOfParameterNamed("note"); final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) { if (StringUtils.isNotBlank(noteText)) {