Specifies if accounting is enabled for the particular
@@ -10252,7 +10419,7 @@ Content-Type: application/json
Optional Fields |
- | minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, paymentChannelToFundSourceMappings |
+ | minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay, monthDayFormat, paymentChannelToFundSourceMappings |
@@ -10558,6 +10725,23 @@ Content-Type: application/json
|
| lockinPeriodFrequencyType |
| Optional: If provided, used along with lockinPeriodFrequency to indicate the length of time that the savings account is 'locked in' and withdrawals are not allowed. 0=Days, 1=Weeks, 2=Months, 3=Years
e.g. 6 Months |
+
+ | withdrawalFeeAmount |
+ | Optional: If provided, used along with withdrawalFeeType to indicate the amount to be charged on the account for withdrawing. e.g. 5 Flat or 5 % of Amount |
+
+ | withdrawalFeeType |
+ | Optional: If provided, used along with withdrawalFeeAmount to indicate the amount to be charged on the account for withdrawing. 1=Flat, 2=% of Amount, e.g. 5 Flat or 5 % of Amount |
+
+ | annualFeeAmount |
+ | Optional: If provided, used along with annualFeeOnMonthDay to indicate the amount to be charged on the account annually on a given day of month. e.g. 10 on 10 May. monthDayFormat indicates day and month formatting used e.g. "dd MMM" for 10 May
+ |
+
+
+ | annualFeeOnMonthDay |
+
+ | Optional: If provided, used along with annualFeeAmount and monthDayFormat to indicate the amount to be charged on the account annually on a given day of month. e.g. 10 on 10 May. monthDayFormat indicates day and month formatting used e.g. "dd MMM" for 10 May
+ |
+
@@ -10758,7 +10942,9 @@ Content-Type: application/json
Inherited from Product (if not provided) |
- | nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType |
+ | nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
+ lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay |
+
@@ -11240,6 +11426,57 @@ No Request Body:
+
+
+
+
Create Data Table
+
Create a new data table and registers it with the Mifos X Core application
+ table.
+
+
+
+POST https://DomainName/api/v1/datatables
+
+
+POST https://DomainName/api/v1/datatables
+
+Content-Type: application/json
+Request Body:
+{
+ "datatableName": "extra_client_details",
+ "apptableName": "m_client",
+ "columns": [
+ {
+ "name": "Gender",
+ "type": "Dropdown",
+ "code": "Gender"
+ },
+ {
+ "name": "Some Decimal",
+ "type": "Decimal",
+ "mandatory": true
+ },
+ {
+ "name": "Birth Date",
+ "type": "Date"
+ },
+ {
+ "name": "Question 2",
+ "type": "String",
+ "length": 100,
+ "mandatory": false
+ }
+ ]
+}
+
+
+{
+ "resourceIdentifier": "extra_client_details"
+}
+
+
+
@@ -11267,25 +11504,191 @@ No Request Body:
GET https://DomainName/api/v1/datatables
-
+
[
- {
- "applicationTableName": "m_client",
- "registeredTableName": "Additional Client Fields Data"
- },
- {
- "applicationTableName": "m_client",
- "registeredTableName": "Extra Family Details Data"
- },
- {
- "applicationTableName": "m_loan",
- "registeredTableName": "Additional Loan Fields Data"
- }
-]
+ {
+ "applicationTableName": "m_client",
+ "registeredTableName": "extra_client_details",
+ "columnHeaderData": [
+ {
+ "columnName": "client_id",
+ "columnType": "bigint",
+ "columnLength": 0,
+ "columnDisplayType": "INTEGER",
+ "isColumnNullable": false,
+ "isColumnPrimaryKey": true,
+ "columnValues": []
+ },
+ {
+ "columnName": "Gender_cd_Question",
+ "columnType": "int",
+ "columnLength": 0,
+ "columnDisplayType": "INTEGER",
+ "isColumnNullable": true,
+ "isColumnPrimaryKey": false,
+ "columnValues": []
+ },
+ {
+ "columnName": "Some Decimal",
+ "columnType": "decimal",
+ "columnLength": 0,
+ "columnDisplayType": "DECIMAL",
+ "isColumnNullable": true,
+ "isColumnPrimaryKey": false,
+ "columnValues": []
+ },
+ {
+ "columnName": "Birth Date",
+ "columnType": "date",
+ "columnLength": 0,
+ "columnDisplayType": "DATE",
+ "isColumnNullable": true,
+ "isColumnPrimaryKey": false,
+ "columnValues": []
+ }
+ ]
+ }
+]
+
+
+
+
Retrieve Data Table Details
+
Lists a registered data table details and the Mifos X Core
+ application table they are registered to.
+
+
+
+GET https://DomainName/api/v1/datatables/{datatable}
+
+
+{
+ "applicationTableName": "m_client",
+ "registeredTableName": "extra_client_details",
+ "columnHeaderData": [
+ {
+ "columnName": "client_id",
+ "columnType": "bigint",
+ "columnLength": 0,
+ "columnDisplayType": "INTEGER",
+ "isColumnNullable": false,
+ "isColumnPrimaryKey": true,
+ "columnValues": []
+ },
+ {
+ "columnName": "Gender_cd_Question",
+ "columnType": "int",
+ "columnLength": 0,
+ "columnDisplayType": "INTEGER",
+ "isColumnNullable": true,
+ "isColumnPrimaryKey": false,
+ "columnValues": []
+ },
+ {
+ "columnName": "Some Decimal",
+ "columnType": "decimal",
+ "columnLength": 0,
+ "columnDisplayType": "DECIMAL",
+ "isColumnNullable": true,
+ "isColumnPrimaryKey": false,
+ "columnValues": []
+ },
+ {
+ "columnName": "Birth Date",
+ "columnType": "date",
+ "columnLength": 0,
+ "columnDisplayType": "DATE",
+ "isColumnNullable": true,
+ "isColumnPrimaryKey": false,
+ "columnValues": []
+ }
+ ]
+}
+
+
+
+
+
+
+
+
Update Data Table
+
Modifies fields of a data table. If the apptableName parameter is passed,
+ data table is deregistered and registered with the new application table.
+
+
+
+PUT https://DomainName/api/v1/datatables/{datatables}
+
+
+PUT https://DomainName/api/v1/datatables/extra_client_details
+
+Content-Type: application/json
+Request Body:
+{
+ "apptableName": "m_client",
+ "columns": [
+ {
+ "name": "Gender",
+ "type": "Dropdown",
+ "code": "Gender"
+ },
+ {
+ "name": "Some Decimal",
+ "type": "Decimal",
+ "mandatory": true
+ },
+ {
+ "name": "Birth Date",
+ "type": "Date"
+ },
+ {
+ "name": "Question 2",
+ "type": "String",
+ "length": 100,
+ "mandatory": false
+ }
+ ]
+}
+
+
+{
+ "resourceIdentifier": "extra_client_details"
+}
+
+
+
+
+
+
+
+
Delete Data Table
+
Deletes a data table and unregisters it from the Mifos X Core
+ application table.
+
+
+
+DELETE https://DomainName/api/v1/datatables/{datatables}
+
+
+DELETE https://DomainName/api/v1/datatables/extra_client_details
+
+Content-Type: application/json
+No Request Body
+
+
+{
+ "resourceIdentifier": "extra_client_details"
+}
+
+
+
+
@@ -12720,8 +13123,7 @@ GET https://DomainName/api/v1/runreports/{reportName}
-
+
Verify authentication
@@ -12736,24 +13138,60 @@ POST authentication?username=mifos&password=password
Content-Type: application/json
No Request Body
+
Example response of autentication for user that is not linked with any staff.
{
- "username": "mifos",
- "userId": 1,
- "base64EncodedAuthenticationKey": "bWlmb3M6cGFzc3dvcmQ=",
- "authenticated": true,
- "roles": [
- {
- "id": 1,
- "name": "Super user",
- "description": "This role provides all application permissions."
- }
- ],
- "permissions": [
- "ALL_FUNCTIONS"
- ]
+ "username": "mifos",
+ "userId": 1,
+ "base64EncodedAuthenticationKey": "bWlmb3M6cGFzc3dvcmQ=",
+ "authenticated": true,
+ "officeId": 1,
+ "officeName": "Head Office",
+ "roles": [
+ {
+ "id": 1,
+ "name": "Super user",
+ "description": "This role provides all application permissions."
+ }
+ ],
+ "permissions": [
+ "ALL_FUNCTIONS"
+ ]
}
+
Example response of autentication for user that is linked with a staff member and role.
+
+{
+ "username": "mifos",
+ "userId": 1,
+ "base64EncodedAuthenticationKey": "bWlmb3M6cGFzc3dvcmQ=",
+ "authenticated": true,
+ "officeId": 1,
+ "officeName": "Head Office",
+ "staffId": 1,
+ "staffDisplayName": "Director, Program",
+ "organisationalRole": {
+ "id": 100,
+ "code": "staffOrganisationalRoleType.programDirector",
+ "value": "Program Director"
+ },
+ "roles": [
+ {
+ "id": 1,
+ "name": "Super user",
+ "description": "This role provides all application permissions."
+ }
+ ],
+ "permissions": [
+ "ALL_FUNCTIONS"
+ ]
+}
+
+
+
+
+
+
POST authentication?username=mifos&password=fail
Content-Type: application/json
@@ -14534,6 +14972,68 @@ Request Body:
{
"officeId":1,
"transactionId":"RS9MCISID4WK1ZM"
+}
+
+
+POST https://DomainName/api/v1/journalentries
+
+
+POST journalentries
+Content-Type: application/json
+Request Body:
+{
+ "locale": "en",
+ "dateFormat": "dd MMMM yyyy",
+ "officeId": "1",
+ "transactionDate": "23 May 2013",
+ "referenceNumber": "547",
+ "comments": "asdf",
+ "accountingRule": "2",
+ "credits":[{"glAccountId":1,
+ "amount":5000},
+ {"glAccountId":2,
+ "amount":5000}
+ ],
+ "debits":[{"glAccountId":3,
+ "amount":5000},
+ {"glAccountId":4,
+ "amount":5000}
+ ]
+}
+
+
+{
+ "officeId":1,
+ "transactionId":"RS9MCISID4WK1ZM"
+}
+
+
+POST https://DomainName/api/v1/journalentries
+
+
+POST journalentries
+Content-Type: application/json
+Request Body:
+{
+ "locale": "en",
+ "dateFormat": "dd MMMM yyyy",
+ "officeId": "1",
+ "transactionDate": "23 May 2013",
+ "referenceNumber": "547",
+ "comments": "asdf",
+ "accountingRule": "3",
+ "credits":[{"glAccountId":1,
+ "amount":5000},
+ {"glAccountId":2,
+ "amount":5000}
+ ],
+ "amount": "10000"
+}
+
+
+{
+ "officeId":1,
+ "transactionId":"RS9MCISID4WK1ZM"
}
@@ -15286,11 +15786,19 @@ GET https://DomainName/api/v1/search?query=000000111
| Data Table |
datatables |
- |
+ Create Data Table |
List Data Tables |
|
|
+
+ |
+ datatables/{datatable} |
+ |
+ Retrieve Data Table Details |
+ Update Data Table |
+ Delete Data Table |
+
|
datatables/register/{datatable}/{apptable} |
diff --git a/mifosng-db/migrations/core_db/V45__create_acc_rule_tags_table.sql b/mifosng-db/migrations/core_db/V45__create_acc_rule_tags_table.sql
new file mode 100644
index 000000000..b17bc2e01
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V45__create_acc_rule_tags_table.sql
@@ -0,0 +1,11 @@
+create table `acc_rule_tags` (
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+ `acc_rule_id` BIGINT(20) NOT NULL,
+ `tag_id` INT(11) NOT NULL,
+ `acc_type_enum` SMALLINT(5) NOT NULL,
+ primary key(`id`),
+ INDEX `FK_acc_accounting_rule_id` (`acc_rule_id`),
+ INDEX `FK_m_code_value_id` (`tag_id`),
+ CONSTRAINT `FK_acc_accounting_rule_id` FOREIGN KEY (`acc_rule_id`) REFERENCES `acc_accounting_rule` (`id`),
+ CONSTRAINT `FK_m_code_value_id` FOREIGN KEY (`tag_id`) REFERENCES `m_code_value` (`id`)
+);
\ No newline at end of file
diff --git a/mifosng-db/migrations/core_db/V46__extend_datatables_api.sql b/mifosng-db/migrations/core_db/V46__extend_datatables_api.sql
new file mode 100644
index 000000000..5bd0a585e
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V46__extend_datatables_api.sql
@@ -0,0 +1,10 @@
+
+INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
+ VALUES
+ ('configuration', 'CREATE_DATATABLE', 'DATATABLE', 'CREATE', 0),
+ ('configuration', 'CREATE_DATATABLE_CHECKER', 'DATATABLE', 'CREATE', 0),
+ ('configuration', 'UPDATE_DATATABLE', 'DATATABLE', 'UPDATE', 0),
+ ('configuration', 'UPDATE_DATATABLE_CHECKER', 'DATATABLE', 'UPDATE', 0),
+ ('configuration', 'DELETE_DATATABLE', 'DATATABLE', 'DELETE', 0),
+ ('configuration', 'DELETE_DATATABLE_CHECKER', 'DATATABLE', 'DELETE', 0);
+
diff --git a/mifosng-db/migrations/core_db/V47__staff-hierarchy-link-to-users.sql b/mifosng-db/migrations/core_db/V47__staff-hierarchy-link-to-users.sql
new file mode 100644
index 000000000..1531b04d1
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V47__staff-hierarchy-link-to-users.sql
@@ -0,0 +1,14 @@
+ALTER TABLE `m_appuser`
+ADD COLUMN `staff_id` BIGINT(20) NULL DEFAULT NULL AFTER `office_id` ;
+
+ALTER TABLE m_appuser
+ADD CONSTRAINT `fk_m_appuser_002`
+FOREIGN KEY (`staff_id`)
+REFERENCES m_staff (`id`)
+ON DELETE NO ACTION
+ON UPDATE NO ACTION
+,ADD INDEX `fk_m_appuser_002x` (`staff_id` ASC);
+
+ALTER TABLE `m_staff`
+ADD COLUMN `organisational_role_enum` SMALLINT NULL DEFAULT NULL AFTER `external_id`,
+ADD COLUMN `organisational_role_parent_staff_id` BIGINT(20) NULL DEFAULT NULL AFTER `organisational_role_enum`;
diff --git a/mifosng-db/migrations/core_db/V48__adding-S3-Support.sql b/mifosng-db/migrations/core_db/V48__adding-S3-Support.sql
new file mode 100755
index 000000000..912598592
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V48__adding-S3-Support.sql
@@ -0,0 +1,78 @@
+INSERT INTO c_configuration (name,enabled) VALUES ('amazon-S3',0);
+
+/*New table for storing details of external services used*/
+CREATE TABLE `c_external_service` (
+ `name` VARCHAR(150) NOT NULL,
+ `value` VARCHAR(250) NULL DEFAULT NULL,
+ UNIQUE INDEX `name` (`name`)
+)
+COLLATE='utf8_general_ci'
+ENGINE=InnoDB;
+
+INSERT INTO c_external_service (name) VALUES ('s3_bucket_name');
+INSERT INTO c_external_service (name) VALUES ('s3_access_key');
+INSERT INTO c_external_service (name) VALUES ('s3_secret_key');
+
+
+
+/*Image tables stores details of all images*/
+CREATE TABLE IF NOT EXISTS `m_image`(
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+ `location` varchar(500),
+ `storage_type_enum` SMALLINT(5),
+ PRIMARY KEY (`id`)
+)
+COLLATE='utf8_general_ci'
+ENGINE=InnoDB;
+
+/*Client points to image table*/
+ALTER TABLE `m_client`
+ ADD COLUMN `image_id` BIGINT(20) NULL DEFAULT NULL AFTER `display_name`,
+ ADD CONSTRAINT `FK_m_client_m_image` FOREIGN KEY (`image_id`) REFERENCES `m_image` (`id`);
+
+/*Move existing image locations to new table*/
+drop procedure if exists migrate_customer_image_data;
+
+delimiter #
+create procedure migrate_customer_image_data()
+begin
+DECLARE v_counter INT DEFAULT 0;
+DECLARE num_of_clients INT DEFAULT 0;
+DECLARE curr_image INT DEFAULT 0;
+DECLARE prev_image INT DEFAULT 0;
+SELECT COUNT(*) FROM m_client INTO num_of_clients;
+SET @curr_client := 0;
+while v_counter < num_of_clients do
+ SET @s = CONCAT('INSERT INTO m_image(`location`,`storage_type_enum`) select image_key, 1 FROM m_client where image_key is not null LIMIT ', v_counter , ', ', 1);
+ PREPARE stmt1 FROM @s;
+ EXECUTE stmt1;
+ DEALLOCATE PREPARE stmt1;
+
+ select ifnull(max(`id`),0) from m_image INTO curr_image;
+ SET @z = CONCAT('select id INTO @curr_client FROM m_client where image_key is not null limit ', v_counter , ', ', 1);
+ PREPARE stmt2 FROM @z;
+ EXECUTE stmt2;
+
+ IF (prev_image != curr_image) THEN UPDATE m_client set image_id = curr_image where id=@curr_client;
+ END IF;
+
+ set prev_image=curr_image;
+ set v_counter=v_counter+1;
+end while;
+delete from m_image where `location` is null;
+end#
+
+delimiter ;
+call migrate_customer_image_data();
+
+/*Now drop the procedure*/
+drop procedure if exists migrate_customer_image_data;
+
+/*Delete image key from client*/
+ALTER TABLE `m_client` DROP COLUMN `image_key`;
+
+
+/*Add storage type for m_document table and update existing documents to file storage*/
+ALTER TABLE m_document ADD COLUMN storage_type_enum SMALLINT(5);
+UPDATE m_document set storage_type_enum=1;
+
diff --git a/mifosng-db/migrations/core_db/V49__track-loan-charge-payment-transactions.sql b/mifosng-db/migrations/core_db/V49__track-loan-charge-payment-transactions.sql
new file mode 100755
index 000000000..206e0f909
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V49__track-loan-charge-payment-transactions.sql
@@ -0,0 +1,14 @@
+CREATE TABLE `m_loan_charge_paid_by` (
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+ `loan_transaction_id` BIGINT(20) NOT NULL,
+ `loan_charge_id` BIGINT(20) NOT NULL,
+ `amount` DECIMAL(19,6) NOT NULL,
+ PRIMARY KEY (`id`),
+ INDEX `FK__m_loan_transaction` (`loan_transaction_id`),
+ INDEX `FK__m_loan_charge` (`loan_charge_id`),
+ CONSTRAINT `FK__m_loan_charge` FOREIGN KEY (`loan_charge_id`) REFERENCES `m_loan_charge` (`id`),
+ CONSTRAINT `FK__m_loan_transaction` FOREIGN KEY (`loan_transaction_id`) REFERENCES `m_loan_transaction` (`id`)
+)
+COLLATE='utf8_general_ci'
+ENGINE=InnoDB;
+
diff --git a/mifosng-db/migrations/core_db/V50__add-grace-settings-to-loan-product.sql b/mifosng-db/migrations/core_db/V50__add-grace-settings-to-loan-product.sql
new file mode 100644
index 000000000..bef3665d4
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V50__add-grace-settings-to-loan-product.sql
@@ -0,0 +1,9 @@
+ALTER TABLE `m_product_loan`
+ADD COLUMN `grace_on_principal_periods` SMALLINT(5) NULL DEFAULT NULL AFTER `max_number_of_repayments`,
+ADD COLUMN `grace_on_interest_periods` SMALLINT(5) NULL DEFAULT NULL AFTER `grace_on_principal_periods`,
+ADD COLUMN `grace_interest_free_periods` SMALLINT(5) NULL DEFAULT NULL AFTER `grace_on_interest_periods`;
+
+ALTER TABLE `m_loan`
+ADD COLUMN `grace_on_principal_periods` SMALLINT(5) NULL DEFAULT NULL AFTER `number_of_repayments`,
+ADD COLUMN `grace_on_interest_periods` SMALLINT(5) NULL DEFAULT NULL AFTER `grace_on_principal_periods`,
+ADD COLUMN `grace_interest_free_periods` SMALLINT(5) NULL DEFAULT NULL AFTER `grace_on_interest_periods`;
\ No newline at end of file
diff --git a/mifosng-db/migrations/core_db/V51__track-additional-details-related-to-installment-performance.sql b/mifosng-db/migrations/core_db/V51__track-additional-details-related-to-installment-performance.sql
new file mode 100644
index 000000000..a383eec13
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V51__track-additional-details-related-to-installment-performance.sql
@@ -0,0 +1,5 @@
+ALTER TABLE `m_loan_repayment_schedule`
+ADD COLUMN `obligations_met_on_date` DATE NULL DEFAULT NULL AFTER `completed_derived`;
+
+ALTER TABLE `m_loan_repayment_schedule`
+CHANGE COLUMN `interest_waived_derived` `interest_waived_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `interest_writtenoff_derived` ;
\ No newline at end of file
diff --git a/mifosng-db/migrations/core_db/V52__add_boolean_support_cols_to_acc_accounting_rule.sql b/mifosng-db/migrations/core_db/V52__add_boolean_support_cols_to_acc_accounting_rule.sql
new file mode 100644
index 000000000..55041d7d2
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V52__add_boolean_support_cols_to_acc_accounting_rule.sql
@@ -0,0 +1,6 @@
+ALTER TABLE `acc_accounting_rule`
+ ADD COLUMN `allow_multiple_debits` TINYINT(1) NOT NULL DEFAULT '0' AFTER `debit_account_id`,
+ ADD COLUMN `allow_multiple_credits` TINYINT(1) NOT NULL DEFAULT '0' AFTER `credit_account_id`;
+
+ALTER TABLE acc_rule_tags
+ ADD UNIQUE KEY `UNIQUE_ACCOUNT_RULE_TAGS` (`acc_rule_id`,`tag_id`,`acc_type_enum`);
\ No newline at end of file
diff --git a/mifosng-db/migrations/core_db/V53__track-advance-and-late-payments-on-installment.sql b/mifosng-db/migrations/core_db/V53__track-advance-and-late-payments-on-installment.sql
new file mode 100644
index 000000000..f7858d098
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V53__track-advance-and-late-payments-on-installment.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `m_loan_repayment_schedule`
+ADD COLUMN `total_paid_in_advance_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `penalty_charges_waived_derived`,
+ADD COLUMN `total_paid_late_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `total_paid_in_advance_derived`;
\ No newline at end of file
diff --git a/mifosng-db/migrations/core_db/V54__charge-to-income-account-mappings.sql b/mifosng-db/migrations/core_db/V54__charge-to-income-account-mappings.sql
new file mode 100755
index 000000000..ef63134cb
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V54__charge-to-income-account-mappings.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `acc_product_mapping`
+ ADD COLUMN `charge_id` BIGINT(20) NULL DEFAULT NULL AFTER `payment_type`,
+ ADD CONSTRAINT `FK_acc_product_mapping_m_charge` FOREIGN KEY (`charge_id`) REFERENCES `m_charge` (`id`);
\ No newline at end of file
diff --git a/mifosng-db/migrations/core_db/V55__add-additional-transaction-processing-strategies.sql b/mifosng-db/migrations/core_db/V55__add-additional-transaction-processing-strategies.sql
new file mode 100644
index 000000000..ea34e561a
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V55__add-additional-transaction-processing-strategies.sql
@@ -0,0 +1,12 @@
+ALTER TABLE `ref_loan_transaction_processing_strategy`
+DROP COLUMN `lastmodified_date` ,
+DROP COLUMN `lastmodifiedby_id` ,
+DROP COLUMN `created_date` ,
+DROP COLUMN `createdby_id` ;
+
+
+INSERT INTO `ref_loan_transaction_processing_strategy` (`id`, `code`, `name`) VALUES
+(5,'principal-interest-penalties-fees-order-strategy', 'Principal Interest Penalties Fees Order');
+
+INSERT INTO `ref_loan_transaction_processing_strategy` (`id`,`code`, `name`)
+VALUES (6,'interest-principal-penalties-fees-order-strategy', 'Interest Principal Penalties Fees Order');
\ No newline at end of file
diff --git a/mifosng-db/migrations/core_db/V56__track-overpaid-amount-on-loans.sql b/mifosng-db/migrations/core_db/V56__track-overpaid-amount-on-loans.sql
new file mode 100644
index 000000000..ab9f5e4bc
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V56__track-overpaid-amount-on-loans.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `m_loan`
+ADD COLUMN `total_overpaid_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `total_outstanding_derived`;
\ No newline at end of file
diff --git a/mifosng-provider/build.gradle b/mifosng-provider/build.gradle
index 04bb6b2ba..4f6b03845 100644
--- a/mifosng-provider/build.gradle
+++ b/mifosng-provider/build.gradle
@@ -160,7 +160,8 @@ dependencies {
[group: 'com.lowagie', name: 'itext-rtf', version: '2.1.7'],
[group: 'org.mnode.ical4j', name: 'ical4j', version: '1.0.4'],
[group: 'com.googlecode.flyway', name: 'flyway-maven-plugin', version: '2.1.1'],
- [group: 'org.quartz-scheduler', name: 'quartz', version: '2.1.7']
+ [group: 'org.quartz-scheduler', name: 'quartz', version: '2.1.7'],
+ [group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.2.1']
)
testCompile 'junit:junit:4.11',
diff --git a/mifosng-provider/gradle.properties b/mifosng-provider/gradle.properties
index c7fb5c508..657b57df9 100644
--- a/mifosng-provider/gradle.properties
+++ b/mifosng-provider/gradle.properties
@@ -1 +1 @@
-releaseVersion=1.2.1.RELEASE
\ No newline at end of file
+releaseVersion=1.3.0.RELEASE
\ No newline at end of file
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java
index cf75b5ce4..cd35a4079 100644
--- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java
@@ -9,10 +9,10 @@ import java.util.HashMap;
import org.junit.Before;
import org.junit.Test;
import org.mifosplatform.integrationtests.common.ClientHelper;
+import org.mifosplatform.integrationtests.common.Utils;
import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper;
-import org.mifosplatform.integrationtests.common.Utils;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.builder.ResponseSpecBuilder;
@@ -30,6 +30,7 @@ public class ClientLoanIntegrationTest {
private ResponseSpecification responseSpec;
private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper;
+
@Before
public void setup() {
Utils.initializeRESTAssured();
@@ -40,7 +41,7 @@ public class ClientLoanIntegrationTest {
@Test
public void checkClientLoanCreateAndDisburseFlow() {
- loanTransactionHelper = new LoanTransactionHelper(requestSpec,responseSpec);
+ loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec);
Integer clientID = ClientHelper.createClient(requestSpec, responseSpec);
ClientHelper.verifyClientCreatedOnServer(requestSpec, responseSpec, clientID);
@@ -53,21 +54,35 @@ public class ClientLoanIntegrationTest {
private Integer createLoanProduct() {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
- String loanProductJSON = new LoanProductTestBuilder().withPrincipal("12,000.00").withNumberOfRepayments("4")
- .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("2")
- .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance()
- .withinterestRatePerPeriod("1").build();
+ String loanProductJSON = new LoanProductTestBuilder() //
+ .withPrincipal("12,000.00") //
+ .withNumberOfRepayments("4") //
+ .withRepaymentAfterEvery("1") //
+ .withRepaymentTypeAsMonth() //
+ .withinterestRatePerPeriod("1") //
+ .withInterestRateFrequencyTypeAsMonths() //
+ .withAmortizationTypeAsEqualInstallments() //
+ .withInterestTypeAsDecliningBalance() //
+ .build();
return loanTransactionHelper.getLoanProductId(loanProductJSON);
}
private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID) {
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
- String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("12,000.00").withLoanTermFrequency("4")
- .withLoanTermFrequencyAsMonths().withNumberOfRepayments("4").withRepaymentEveryAfter("1")
- .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2")
- .withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance()
- .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("20 September 2011")
- .withSubmittedOnDate("20 September 2011").build(clientID.toString(), loanProductID.toString());
+ String loanApplicationJSON = new LoanApplicationTestBuilder() //
+ .withPrincipal("12,000.00") //
+ .withLoanTermFrequency("4") //
+ .withLoanTermFrequencyAsMonths() //
+ .withNumberOfRepayments("4") //
+ .withRepaymentEveryAfter("1") //
+ .withRepaymentFrequencyTypeAsMonths() //
+ .withInterestRatePerPeriod("2") //
+ .withAmortizationTypeAsEqualInstallments() //
+ .withInterestTypeAsDecliningBalance() //
+ .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
+ .withExpectedDisbursementDate("20 September 2011") //
+ .withSubmittedOnDate("20 September 2011") //
+ .build(clientID.toString(), loanProductID.toString());
return loanTransactionHelper.getLoanId(loanApplicationJSON);
}
@@ -81,17 +96,17 @@ public class ClientLoanIntegrationTest {
assertEquals("Checking for Due Date for 2nd Month", new ArrayList(Arrays.asList(2011, 11, 20)),
loanSchedule.get(2).get("dueDate"));
- assertEquals("Checking for Principal Due for 2nd Month", new Float("2969.72"), loanSchedule.get(2).get("principalDue"));
+ assertEquals("Checking for Principal Due for 2nd Month", new Float("2969.71"), loanSchedule.get(2).get("principalDue"));
assertEquals("Checking for Interest Due for 2nd Month", new Float("181.77"), loanSchedule.get(2).get("interestOriginalDue"));
assertEquals("Checking for Due Date for 3rd Month", new ArrayList(Arrays.asList(2011, 12, 20)),
loanSchedule.get(3).get("dueDate"));
- assertEquals("Checking for Principal Due for 3rd Month", new Float("3029.11"), loanSchedule.get(3).get("principalDue"));
+ assertEquals("Checking for Principal Due for 3rd Month", new Float("3029.1"), loanSchedule.get(3).get("principalDue"));
assertEquals("Checking for Interest Due for 3rd Month", new Float("122.38"), loanSchedule.get(3).get("interestOriginalDue"));
assertEquals("Checking for Due Date for 4th Month", new ArrayList(Arrays.asList(2012, 1, 20)),
loanSchedule.get(4).get("dueDate"));
- assertEquals("Checking for Principal Due for 4th Month", new Float("3089.68"), loanSchedule.get(4).get("principalDue"));
+ assertEquals("Checking for Principal Due for 4th Month", new Float("3089.7"), loanSchedule.get(4).get("principalDue"));
assertEquals("Checking for Interest Due for 4th Month", new Float("61.79"), loanSchedule.get(4).get("interestOriginalDue"));
}
}
\ No newline at end of file
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java
index fbb1d8bee..b1b0de92a 100644
--- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java
@@ -31,7 +31,7 @@ public class LoanApplicationTestBuilder {
private final String transactionProcessingID = MIFOS_STANDARD_STRATEGY;
private String expectedDisbursmentDate = "";
private String submittedOnDate = "";
- private String loanType = "individual"; //default it to individual
+ private String loanType = "individual";
public String build(final String clientID, final String loanProductId) {
@@ -42,7 +42,7 @@ public class LoanApplicationTestBuilder {
map.put("productId", loanProductId);
map.put("principal", principal);
map.put("loanTermFrequency", loanTermFrequency);
- map.put("loanTermFrequencyType", loanTermFrequencyType); // FIXME - Should this be using
+ map.put("loanTermFrequencyType", loanTermFrequencyType);
map.put("numberOfRepayments", numberOfRepayment);
map.put("repaymentEvery", repaymentPeriod);
map.put("repaymentFrequencyType", repaymentFrequencyType);
@@ -53,7 +53,7 @@ public class LoanApplicationTestBuilder {
map.put("transactionProcessingStrategyId", transactionProcessingID);
map.put("expectedDisbursementDate", expectedDisbursmentDate);
map.put("submittedOnDate", submittedOnDate);
- map.put("loanType", "individual");
+ map.put("loanType", loanType);
return new Gson().toJson(map);
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java
index f9b47b31f..35de2586a 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java
@@ -85,7 +85,8 @@ public class AccountingConstants {
"incomeFromFeeAccountId"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccountId"), LOSSES_WRITTEN_OFF("writeOffAccountId"), INTEREST_RECEIVABLE(
"receivableInterestAccountId"), FEES_RECEIVABLE("receivableFeeAccountId"), PENALTIES_RECEIVABLE(
"receivablePenaltyAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING("paymentChannelToFundSourceMappings"), PAYMENT_TYPE(
- "paymentTypeId");
+ "paymentTypeId"), FEE_INCOME_ACCOUNT_MAPPING("feeToIncomeAccountMappings"), PENALTY_INCOME_ACCOUNT_MAPPING(
+ "penaltyToIncomeAccountMappings"), CHARGE_ID("chargeId"), INCOME_ACCOUNT_ID("incomeAccountId");
private final String value;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/api/GLAccountsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/api/GLAccountsApiResource.java
index 904bfbc87..02a150463 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/api/GLAccountsApiResource.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/api/GLAccountsApiResource.java
@@ -50,9 +50,10 @@ import org.springframework.stereotype.Component;
public class GLAccountsApiResource {
private static final Set RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "name", "parentId", "glCode",
- "disabled", "manualEntriesAllowed", "type", "usage", "description", "assetHeaderAccountOptions", "liabilityHeaderAccountOptions",
- "equityHeaderAccountOptions", "incomeHeaderAccountOptions", "expenseHeaderAccountOptions", "nameDecorated", "tagId",
- "allowedAssetsTagOptions", "allowedLiabilitiesTagOptions", "allowedEquityTagOptions", "allowedIncomeTagOptions", "allowedExpensesTagOptions"));
+ "disabled", "manualEntriesAllowed", "type", "usage", "description", "assetHeaderAccountOptions",
+ "liabilityHeaderAccountOptions", "equityHeaderAccountOptions", "incomeHeaderAccountOptions", "expenseHeaderAccountOptions",
+ "nameDecorated", "tagId", "allowedAssetsTagOptions", "allowedLiabilitiesTagOptions", "allowedEquityTagOptions",
+ "allowedIncomeTagOptions", "allowedExpensesTagOptions", "creditAccounts", "debitAccounts"));
private final String resourceNameForPermission = "GLACCOUNT";
@@ -63,12 +64,13 @@ public class GLAccountsApiResource {
private final PlatformSecurityContext context;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
-
+
@Autowired
public GLAccountsApiResource(final PlatformSecurityContext context, final GLAccountReadPlatformService glAccountReadPlatformService,
final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
- final AccountingDropdownReadPlatformService dropdownReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService) {
+ final AccountingDropdownReadPlatformService dropdownReadPlatformService,
+ final CodeValueReadPlatformService codeValueReadPlatformService) {
this.context = context;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
@@ -82,7 +84,7 @@ public class GLAccountsApiResource {
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
- public String retrieveNewAccountDetails(@Context final UriInfo uriInfo, @QueryParam("type") final Integer type) {
+ public String retrieveNewAccountDetails(@Context final UriInfo uriInfo, @QueryParam("type") final Integer type) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission);
@@ -167,22 +169,32 @@ public class GLAccountsApiResource {
private GLAccountData handleTemplate(final GLAccountData glAccountData) {
final List accountTypeOptions = this.dropdownReadPlatformService.retrieveGLAccountTypeOptions();
final List usageOptions = this.dropdownReadPlatformService.retrieveGLAccountUsageOptions();
- final List assetHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService.retrieveAllEnabledHeaderGLAccounts(GLAccountType.ASSET));
- final List liabilityHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService.retrieveAllEnabledHeaderGLAccounts(GLAccountType.LIABILITY));
- final List equityHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService.retrieveAllEnabledHeaderGLAccounts(GLAccountType.EQUITY));
- final List incomeHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService.retrieveAllEnabledHeaderGLAccounts(GLAccountType.INCOME));
- final List expenseHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService.retrieveAllEnabledHeaderGLAccounts(GLAccountType.EXPENSE));
- final Collection allowedAssetsTagOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode(AccountingConstants.ASSESTS_TAG_OPTION_CODE_NAME);
- final Collection allowedLiabilitiesTagOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode(AccountingConstants.LIABILITIES_TAG_OPTION_CODE_NAME);
- final Collection allowedEquityTagOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode(AccountingConstants.EQUITY_TAG_OPTION_CODE_NAME);
- final Collection allowedIncomeTagOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode(AccountingConstants.INCOME_TAG_OPTION_CODE_NAME);
- final Collection allowedExpensesTagOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode(AccountingConstants.EXPENSES_TAG_OPTION_CODE_NAME);
-
+ final List assetHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService
+ .retrieveAllEnabledHeaderGLAccounts(GLAccountType.ASSET));
+ final List liabilityHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService
+ .retrieveAllEnabledHeaderGLAccounts(GLAccountType.LIABILITY));
+ final List equityHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService
+ .retrieveAllEnabledHeaderGLAccounts(GLAccountType.EQUITY));
+ final List incomeHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService
+ .retrieveAllEnabledHeaderGLAccounts(GLAccountType.INCOME));
+ final List expenseHeaderAccountOptions = defaultIfEmpty(this.glAccountReadPlatformService
+ .retrieveAllEnabledHeaderGLAccounts(GLAccountType.EXPENSE));
+ final Collection allowedAssetsTagOptions = this.codeValueReadPlatformService
+ .retrieveCodeValuesByCode(AccountingConstants.ASSESTS_TAG_OPTION_CODE_NAME);
+ final Collection allowedLiabilitiesTagOptions = this.codeValueReadPlatformService
+ .retrieveCodeValuesByCode(AccountingConstants.LIABILITIES_TAG_OPTION_CODE_NAME);
+ final Collection allowedEquityTagOptions = this.codeValueReadPlatformService
+ .retrieveCodeValuesByCode(AccountingConstants.EQUITY_TAG_OPTION_CODE_NAME);
+ final Collection allowedIncomeTagOptions = this.codeValueReadPlatformService
+ .retrieveCodeValuesByCode(AccountingConstants.INCOME_TAG_OPTION_CODE_NAME);
+ final Collection allowedExpensesTagOptions = this.codeValueReadPlatformService
+ .retrieveCodeValuesByCode(AccountingConstants.EXPENSES_TAG_OPTION_CODE_NAME);
+
return new GLAccountData(glAccountData, accountTypeOptions, usageOptions, assetHeaderAccountOptions, liabilityHeaderAccountOptions,
- equityHeaderAccountOptions, incomeHeaderAccountOptions, expenseHeaderAccountOptions, allowedAssetsTagOptions,
+ equityHeaderAccountOptions, incomeHeaderAccountOptions, expenseHeaderAccountOptions, allowedAssetsTagOptions,
allowedLiabilitiesTagOptions, allowedEquityTagOptions, allowedIncomeTagOptions, allowedExpensesTagOptions);
}
-
+
private List defaultIfEmpty(final List list) {
List returnList = null;
if (list != null && !list.isEmpty()) {
@@ -190,4 +202,4 @@ public class GLAccountsApiResource {
}
return returnList;
}
-}
\ No newline at end of file
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/data/GLAccountData.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/data/GLAccountData.java
index 4d3e9d3d3..8fd608ebd 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/data/GLAccountData.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/data/GLAccountData.java
@@ -71,17 +71,17 @@ public class GLAccountData {
this.expenseHeaderAccountOptions = null;
this.allowedAssetsTagOptions = null;
this.allowedLiabilitiesTagOptions = null;
- this.allowedEquityTagOptions=null;
- this.allowedIncomeTagOptions=null;
- this.allowedExpensesTagOptions=null;
+ this.allowedEquityTagOptions = null;
+ this.allowedIncomeTagOptions = null;
+ this.allowedExpensesTagOptions = null;
}
public GLAccountData(final GLAccountData accountData, final List accountTypeOptions,
final List usageOptions, final List assetHeaderAccountOptions,
final List liabilityHeaderAccountOptions, final List equityHeaderAccountOptions,
- final List incomeHeaderAccountOptions, final List expenseHeaderAccountOptions,
- final Collection allowedAssetsTagOptions, final Collection allowedLiabilitiesTagOptions,
- final Collection allowedEquityTagOptions, final Collection allowedIncomeTagOptions,
+ final List incomeHeaderAccountOptions, final List expenseHeaderAccountOptions,
+ final Collection allowedAssetsTagOptions, final Collection allowedLiabilitiesTagOptions,
+ final Collection allowedEquityTagOptions, final Collection allowedIncomeTagOptions,
final Collection allowedExpensesTagOptions) {
this.id = accountData.id;
this.name = accountData.name;
@@ -116,19 +116,20 @@ public class GLAccountData {
final boolean disabled = false;
final boolean manualEntriesAllowed = true;
final EnumOptionData type;
- if(glAccType != null && glAccType >= GLAccountType.getMinValue() && glAccType <= GLAccountType.getMaxValue())
+ if (glAccType != null && glAccType >= GLAccountType.getMinValue() && glAccType <= GLAccountType.getMaxValue()) {
type = AccountingEnumerations.gLAccountType(glAccType);
- else
+ } else {
type = AccountingEnumerations.gLAccountType(GLAccountType.ASSET);
+ }
final EnumOptionData usage = AccountingEnumerations.gLAccountUsage(GLAccountUsage.DETAIL);
final String description = null;
final String nameDecorated = null;
final CodeValueData tagId = null;
return new GLAccountData(id, name, parentId, glCode, disabled, manualEntriesAllowed, type, usage, description, nameDecorated, tagId);
}
-
+
public GLAccountData(final Long id, final String name, final String glCode) {
- this.id = id;
+ this.id = id;
this.name = name;
this.parentId = null;
this.glCode = glCode;
@@ -148,23 +149,21 @@ public class GLAccountData {
this.expenseHeaderAccountOptions = null;
this.allowedAssetsTagOptions = null;
this.allowedLiabilitiesTagOptions = null;
- this.allowedEquityTagOptions=null;
- this.allowedIncomeTagOptions=null;
- this.allowedExpensesTagOptions=null;
- }
+ this.allowedEquityTagOptions = null;
+ this.allowedIncomeTagOptions = null;
+ this.allowedExpensesTagOptions = null;
+ }
- public Long getId() {
- return this.id;
- }
+ public Long getId() {
+ return this.id;
+ }
- public String getName() {
- return this.name;
- }
+ public String getName() {
+ return this.name;
+ }
- public String getGlCode() {
- return this.glCode;
- }
-
-
+ public String getGlCode() {
+ return this.glCode;
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/data/GLAccountDataForLookup.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/data/GLAccountDataForLookup.java
new file mode 100644
index 000000000..7416dee50
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/data/GLAccountDataForLookup.java
@@ -0,0 +1,26 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.accounting.glaccount.data;
+
+public class GLAccountDataForLookup {
+
+ private final Long id;
+ @SuppressWarnings("unused")
+ private final String name;
+ @SuppressWarnings("unused")
+ private final String glCode;
+
+ public GLAccountDataForLookup(final Long id, final String name, final String glCode) {
+ this.id = id;
+ this.name = name;
+ this.glCode = glCode;
+ }
+
+ public Long getId() {
+ return this.id;
+ }
+
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/exception/InvalidParentGLAccountHeadException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/exception/InvalidParentGLAccountHeadException.java
index 353bbbb42..751ae1e9f 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/exception/InvalidParentGLAccountHeadException.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/exception/InvalidParentGLAccountHeadException.java
@@ -1,11 +1,17 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
package org.mifosplatform.accounting.glaccount.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class InvalidParentGLAccountHeadException extends AbstractPlatformDomainRuleException {
- public InvalidParentGLAccountHeadException(Long glAccountId, Long parentId) {
- super("error.msg.glaccount.id.and.parentid.must.not.same", "parentId:"+parentId+", id"+glAccountId+" should not be same", glAccountId, parentId);
- }
+ public InvalidParentGLAccountHeadException(final Long glAccountId, final Long parentId) {
+ super("error.msg.glaccount.id.and.parentid.must.not.same", "parentId:" + parentId + ", id" + glAccountId + " should not be same",
+ glAccountId, parentId);
+ }
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/service/GLAccountReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/service/GLAccountReadPlatformService.java
index d982c3153..c03ba7423 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/service/GLAccountReadPlatformService.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/service/GLAccountReadPlatformService.java
@@ -8,6 +8,7 @@ package org.mifosplatform.accounting.glaccount.service;
import java.util.List;
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
+import org.mifosplatform.accounting.glaccount.data.GLAccountDataForLookup;
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
public interface GLAccountReadPlatformService {
@@ -24,4 +25,6 @@ public interface GLAccountReadPlatformService {
List retrieveAllEnabledHeaderGLAccounts(GLAccountType accountType);
GLAccountData retrieveNewGLAccountDetails(final Integer type);
+
+ List retrieveAccountsByTagId(final Long ruleId, final Integer transactionType);
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/service/GLAccountReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/service/GLAccountReadPlatformServiceImpl.java
index 1380a34bc..87b9078cd 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/service/GLAccountReadPlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/service/GLAccountReadPlatformServiceImpl.java
@@ -13,6 +13,7 @@ import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.accounting.common.AccountingEnumerations;
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
+import org.mifosplatform.accounting.glaccount.data.GLAccountDataForLookup;
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
import org.mifosplatform.accounting.glaccount.domain.GLAccountUsage;
import org.mifosplatform.accounting.glaccount.exception.GLAccountInvalidClassificationException;
@@ -65,7 +66,7 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
final String nameDecorated = rs.getString("nameDecorated");
final Long codeId = rs.wasNull() ? null : rs.getLong("codeId");
final String codeValue = rs.getString("codeValue");
- CodeValueData tagId = CodeValueData.instance(codeId, codeValue);
+ final CodeValueData tagId = CodeValueData.instance(codeId, codeValue);
return new GLAccountData(id, name, parentId, glCode, disabled, manualEntriesAllowed, accountType, usage, description,
nameDecorated, tagId);
}
@@ -202,4 +203,27 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
public List retrieveAllEnabledHeaderGLAccounts(final GLAccountType accountType) {
return retrieveAllGLAccounts(accountType.getValue(), null, GLAccountUsage.HEADER.getValue(), null, false);
}
+
+ @Override
+ public List retrieveAccountsByTagId(final Long ruleId, final Integer transactionType) {
+ final GLAccountDataLookUpMapper mapper = new GLAccountDataLookUpMapper();
+ final String sql = "Select " + mapper.schema() + " where rule.id=? and tags.acc_type_enum=?";
+ return this.jdbcTemplate.query(sql, mapper, new Object[] { ruleId, transactionType });
+ }
+
+ private static final class GLAccountDataLookUpMapper implements RowMapper {
+
+ public String schema() {
+ return " gl.id as id, gl.name as name, gl.gl_code as glCode from acc_accounting_rule rule join acc_rule_tags tags on tags.acc_rule_id = rule.id join acc_gl_account gl on gl.tag_id=tags.tag_id";
+ }
+
+ @Override
+ public GLAccountDataForLookup mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
+ final Long id = JdbcSupport.getLong(rs, "id");
+ final String name = rs.getString("name");
+ final String glCode = rs.getString("glCode");
+ return new GLAccountDataForLookup(id, name, glCode);
+ }
+
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/command/JournalEntryCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/command/JournalEntryCommand.java
index 22e45080b..2c7eab279 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/command/JournalEntryCommand.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/command/JournalEntryCommand.java
@@ -30,8 +30,8 @@ public class JournalEntryCommand {
private final SingleDebitOrCreditEntryCommand[] debits;
public JournalEntryCommand(final Long officeId, final LocalDate transactionDate, final String comments,
- final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits,
- final String referenceNumber, final Long accountingRuleId, final BigDecimal amount) {
+ final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits, final String referenceNumber,
+ final Long accountingRuleId, final BigDecimal amount) {
this.officeId = officeId;
this.transactionDate = transactionDate;
this.comments = comments;
@@ -53,46 +53,42 @@ public class JournalEntryCommand {
baseDataValidator.reset().parameter("officeId").value(this.officeId).notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("comments").value(this.comments).ignoreIfNull().notExceedingLengthOf(500);
-
+
baseDataValidator.reset().parameter("referenceNumber").value(this.referenceNumber).ignoreIfNull().notExceedingLengthOf(100);
-
+
baseDataValidator.reset().parameter("accountingRule").value(this.accountingRuleId).ignoreIfNull().longGreaterThanZero();
-
- if (this.accountingRuleId == null) {
-
- baseDataValidator.reset().parameter("credits").value(this.credits).notNull();
-
- baseDataValidator.reset().parameter("debits").value(this.debits).notNull();
-
- // validation for credit array elements
- if (this.credits != null) {
- if (this.credits.length == 0) {
- validateSingleDebitOrCredit(baseDataValidator, "credits", 0, new SingleDebitOrCreditEntryCommand(null, null, null, null));
- } else {
- int i = 0;
- for (final SingleDebitOrCreditEntryCommand credit : this.credits) {
- validateSingleDebitOrCredit(baseDataValidator, "credits", i, credit);
- i++;
- }
+
+ baseDataValidator.reset().parameter("credits").value(this.credits).ignoreIfNull();
+
+ baseDataValidator.reset().parameter("debits").value(this.debits).ignoreIfNull();
+
+ // validation for credit array elements
+ if (this.credits != null) {
+ if (this.credits.length == 0) {
+ validateSingleDebitOrCredit(baseDataValidator, "credits", 0, new SingleDebitOrCreditEntryCommand(null, null, null, null));
+ } else {
+ int i = 0;
+ for (final SingleDebitOrCreditEntryCommand credit : this.credits) {
+ validateSingleDebitOrCredit(baseDataValidator, "credits", i, credit);
+ i++;
}
}
-
- // validation for debit array elements
- if (this.debits != null) {
- if (this.debits.length == 0) {
- validateSingleDebitOrCredit(baseDataValidator, "credits", 0, new SingleDebitOrCreditEntryCommand(null, null, null, null));
- } else {
- int i = 0;
- for (final SingleDebitOrCreditEntryCommand debit : this.debits) {
- validateSingleDebitOrCredit(baseDataValidator, "debits", i, debit);
- i++;
- }
- }
- }
- } else {
- baseDataValidator.reset().parameter("amount").value(this.amount).notNull().zeroOrPositiveAmount();
}
+ // validation for debit array elements
+ if (this.debits != null) {
+ if (this.debits.length == 0) {
+ validateSingleDebitOrCredit(baseDataValidator, "credits", 0, new SingleDebitOrCreditEntryCommand(null, null, null, null));
+ } else {
+ int i = 0;
+ for (final SingleDebitOrCreditEntryCommand debit : this.debits) {
+ validateSingleDebitOrCredit(baseDataValidator, "debits", i, debit);
+ i++;
+ }
+ }
+ }
+ baseDataValidator.reset().parameter("amount").value(this.amount).ignoreIfNull().zeroOrPositiveAmount();
+
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
@@ -134,8 +130,8 @@ public class JournalEntryCommand {
return this.referenceNumber;
}
- public Long getAccountingRuleId() {
- return this.accountingRuleId;
- }
+ public Long getAccountingRuleId() {
+ return this.accountingRuleId;
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/ChargePaymentDTO.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/ChargePaymentDTO.java
new file mode 100755
index 000000000..7dbde9413
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/ChargePaymentDTO.java
@@ -0,0 +1,29 @@
+package org.mifosplatform.accounting.journalentry.data;
+
+import java.math.BigDecimal;
+
+public class ChargePaymentDTO {
+
+ private final Long chargeId;
+ private final BigDecimal amount;
+ private final Long loanChargeId;
+
+ public ChargePaymentDTO(Long chargeId, Long loanChargeId, BigDecimal amount) {
+ this.chargeId = chargeId;
+ this.amount = amount;
+ this.loanChargeId = loanChargeId;
+ }
+
+ public Long getChargeId() {
+ return this.chargeId;
+ }
+
+ public BigDecimal getAmount() {
+ return this.amount;
+ }
+
+ public Long getLoanChargeId() {
+ return this.loanChargeId;
+ }
+
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java
index e277c3a3a..cd17861a0 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java
@@ -7,6 +7,7 @@ package org.mifosplatform.accounting.journalentry.data;
import java.math.BigDecimal;
import java.util.Date;
+import java.util.List;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
@@ -28,9 +29,14 @@ public class LoanTransactionDTO {
/*** Boolean values determines if the transaction is reversed ***/
private final boolean reversed;
+ /** Breakdowns of fees and penalties this Transaction pays **/
+ private final List penaltyPayments;
+ private final List feePayments;
+
public LoanTransactionDTO(final Long paymentTypeId, final String transactionId, final Date transactionDate,
final LoanTransactionEnumData transactionType, final BigDecimal amount, final BigDecimal principal, final BigDecimal interest,
- final BigDecimal fees, final BigDecimal penalties, final boolean reversed) {
+ final BigDecimal fees, final BigDecimal penalties, final boolean reversed, final List feePayments,
+ final List penaltyPayments) {
this.paymentTypeId = paymentTypeId;
this.transactionId = transactionId;
this.transactionDate = transactionDate;
@@ -41,6 +47,8 @@ public class LoanTransactionDTO {
this.penalties = penalties;
this.reversed = reversed;
this.transactionType = transactionType;
+ this.feePayments = feePayments;
+ this.penaltyPayments = penaltyPayments;
}
public String getTransactionId() {
@@ -83,4 +91,12 @@ public class LoanTransactionDTO {
return this.paymentTypeId;
}
+ public List getPenaltyPayments() {
+ return this.penaltyPayments;
+ }
+
+ public List getFeePayments() {
+ return this.feePayments;
+ }
+
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/domain/JournalEntry.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/domain/JournalEntry.java
index 32e462a78..e5298504c 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/domain/JournalEntry.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/domain/JournalEntry.java
@@ -73,7 +73,7 @@ public class JournalEntry extends AbstractAuditableCustom {
@SuppressWarnings("unused")
@Column(name = "entity_id")
private Long entityId;
-
+
@Column(name = "ref_num")
private String referenceNumber;
@@ -104,7 +104,7 @@ public class JournalEntry extends AbstractAuditableCustom {
this.entityType = entityType;
this.entityId = entityId;
this.referenceNumber = referenceNumber;
-
+
}
public boolean isDebitEntry() {
@@ -139,8 +139,8 @@ public class JournalEntry extends AbstractAuditableCustom {
this.reversed = reversed;
}
- public String getReferenceNumber() {
- return this.referenceNumber;
- }
+ public String getReferenceNumber() {
+ return this.referenceNumber;
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/domain/JournalEntryType.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/domain/JournalEntryType.java
index 4d6842f85..6c316f5af 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/domain/JournalEntryType.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/domain/JournalEntryType.java
@@ -45,4 +45,12 @@ public enum JournalEntryType {
return name().toString();
}
+ public boolean isDebitType() {
+ return this.value.equals(JournalEntryType.DEBIT.getValue());
+ }
+
+ public boolean isCreditType() {
+ return this.value.equals(JournalEntryType.CREDIT.getValue());
+ }
+
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/exception/JournalEntryInvalidException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/exception/JournalEntryInvalidException.java
index 187a2b395..f3c38462b 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/exception/JournalEntryInvalidException.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/exception/JournalEntryInvalidException.java
@@ -16,7 +16,7 @@ public class JournalEntryInvalidException extends AbstractPlatformDomainRuleExce
/*** enum of reasons for invalid Journal Entry **/
public static enum GL_JOURNAL_ENTRY_INVALID_REASON {
- FUTURE_DATE, ACCOUNTING_CLOSED, NO_DEBITS_OR_CREDITS, DEBIT_CREDIT_SUM_MISMATCH, DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, GL_ACCOUNT_DISABLED, GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED;
+ FUTURE_DATE, ACCOUNTING_CLOSED, NO_DEBITS_OR_CREDITS, DEBIT_CREDIT_SUM_MISMATCH_WITH_AMOUNT, DEBIT_CREDIT_SUM_MISMATCH, DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, GL_ACCOUNT_DISABLED, GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED;
public String errorMessage() {
if (name().toString().equalsIgnoreCase("FUTURE_DATE")) {
@@ -25,6 +25,8 @@ public class JournalEntryInvalidException extends AbstractPlatformDomainRuleExce
return "Journal entry cannot be made prior to last account closing date for the branch";
} else if (name().toString().equalsIgnoreCase("NO_DEBITS_OR_CREDITS")) {
return "Journal Entry must have atleast one Debit and one Credit";
+ } else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_SUM_MISMATCH_WITH_AMOUNT")) {
+ return "Sum of All Debits OR Credits must equal the Amount for a Journal Entry";
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_SUM_MISMATCH")) {
return "Sum of All Debits must equal the sum of all Credits for a Journal Entry";
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY")) {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java
index dc23811a0..7245e7949 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java
@@ -8,6 +8,7 @@ package org.mifosplatform.accounting.journalentry.service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -18,6 +19,7 @@ import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_SAVINGS;
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
+import org.mifosplatform.accounting.journalentry.data.ChargePaymentDTO;
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO;
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
@@ -30,6 +32,7 @@ import org.mifosplatform.accounting.journalentry.exception.JournalEntryInvalidEx
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
+import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.office.domain.OfficeRepository;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
@@ -77,8 +80,28 @@ public class AccountingProcessorHelper {
final boolean reversed = (Boolean) map.get("reversed");
final Long paymentTypeId = (Long) map.get("paymentTypeId");
+ List feePayments = new ArrayList();
+ List penaltyPayments = new ArrayList();
+ // extract charge payment details (if exists)
+ if (map.containsKey("loanChargesPaid")) {
+ @SuppressWarnings("unchecked")
+ final List