This is an automated email from the ASF dual-hosted git repository. rajanmaurya154 pushed a commit to branch development in repository https://gitbox.apache.org/repos/asf/fineract-cn-mobile.git
commit 3432194ca2ea29cee805c678fa98a6f0741f4f17 Author: Mohak <mohakpuri1...@gmail.com> AuthorDate: Tue Jul 17 11:28:34 2018 +0530 feat: list and search ledger --- .../java/org/apache/fineract/FakeJsonName.java | 1 + .../org/apache/fineract/FakeRemoteDataSource.java | 6 + .../data/datamanager/DataManagerAccounting.kt | 31 ++++ .../fineract/data/models/accounts/AccountType.kt | 21 +++ .../apache/fineract/data/models/accounts/Ledger.kt | 25 +++ .../fineract/data/models/accounts/LedgerPage.kt | 9 ++ .../fineract/data/remote/BaseApiManager.java | 8 +- .../org/apache/fineract/data/remote/EndPoints.java | 1 + .../fineract/data/services/AccountingService.kt | 19 +++ .../injection/component/ActivityComponent.java | 45 +++--- .../injection/component/ApplicationComponent.java | 2 + .../apache/fineract/ui/adapters/LedgerAdapter.kt | 65 ++++++++ .../fineract/ui/online/DashboardActivity.java | 4 + .../ui/online/accounting/ledgers/LedgerContract.kt | 32 ++++ .../ui/online/accounting/ledgers/LedgerFragment.kt | 168 +++++++++++++++++++++ .../online/accounting/ledgers/LedgerPresenter.kt | 87 +++++++++++ .../org/apache/fineract/utils/StatusUtils.java | 28 ++++ app/src/main/res/layout/fragment_ledger.xml | 26 ++++ app/src/main/res/layout/item_ledger.xml | 76 ++++++++++ app/src/main/res/menu/menu_ledger_search.xml | 12 ++ app/src/main/res/menu/menu_navigation_drawer.xml | 7 + app/src/main/res/values/strings.xml | 3 + app/src/main/resources/ledgerPage.json | 62 ++++++++ 23 files changed, 720 insertions(+), 18 deletions(-) diff --git a/app/src/commonTest/java/org/apache/fineract/FakeJsonName.java b/app/src/commonTest/java/org/apache/fineract/FakeJsonName.java index 441ae48..95a3bdd 100644 --- a/app/src/commonTest/java/org/apache/fineract/FakeJsonName.java +++ b/app/src/commonTest/java/org/apache/fineract/FakeJsonName.java @@ -17,4 +17,5 @@ public class FakeJsonName { public static final String LOAN_ACCOUNT = "loanAccount.json"; public static final String PLANNED_PAYMENT_PAGE = "plannedPaymentPage.json"; public static final String ROLES = "role.json"; + public static final String LEDGER_PAGE = "ledgerPage.json"; } diff --git a/app/src/commonTest/java/org/apache/fineract/FakeRemoteDataSource.java b/app/src/commonTest/java/org/apache/fineract/FakeRemoteDataSource.java index 01f6bb3..02611f9 100644 --- a/app/src/commonTest/java/org/apache/fineract/FakeRemoteDataSource.java +++ b/app/src/commonTest/java/org/apache/fineract/FakeRemoteDataSource.java @@ -3,6 +3,7 @@ package org.apache.fineract; import com.google.gson.reflect.TypeToken; import org.apache.fineract.data.models.Authentication; +import org.apache.fineract.data.models.accounts.LedgerPage; import org.apache.fineract.data.models.customer.Command; import org.apache.fineract.data.models.customer.Customer; import org.apache.fineract.data.models.customer.CustomerPage; @@ -78,4 +79,9 @@ public class FakeRemoteDataSource { return testDataFactory.getObjectTypePojo(PlannedPaymentPage.class, FakeJsonName.PLANNED_PAYMENT_PAGE); } + + public static LedgerPage getLedgerPage() { + return testDataFactory.getObjectTypePojo(LedgerPage.class, FakeJsonName.LEDGER_PAGE); + } + } diff --git a/app/src/main/java/org/apache/fineract/data/datamanager/DataManagerAccounting.kt b/app/src/main/java/org/apache/fineract/data/datamanager/DataManagerAccounting.kt new file mode 100644 index 0000000..8d96cc6 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/data/datamanager/DataManagerAccounting.kt @@ -0,0 +1,31 @@ +package org.apache.fineract.data.datamanager + +import io.reactivex.Observable +import io.reactivex.ObservableSource +import io.reactivex.functions.Function +import org.apache.fineract.data.local.PreferencesHelper +import org.apache.fineract.data.remote.BaseApiManager +import javax.inject.Inject +import org.apache.fineract.FakeRemoteDataSource +import org.apache.fineract.data.datamanager.api.DataManagerAuth +import org.apache.fineract.data.datamanager.api.FineractBaseDataManager +import org.apache.fineract.data.models.accounts.Ledger +import org.apache.fineract.data.models.accounts.LedgerPage +import javax.inject.Singleton + +@Singleton +class DataManagerAccounting @Inject constructor(val baseManagerApi: BaseApiManager, + dataManagerAuth: DataManagerAuth, + val preferencesHelper: PreferencesHelper) + : FineractBaseDataManager(dataManagerAuth, preferencesHelper) { + + fun fetchLedgers(): Observable<LedgerPage> = + baseManagerApi.accountingService.fetchLedgers() + .onErrorResumeNext(Function<Throwable, ObservableSource<LedgerPage>> + { Observable.just(FakeRemoteDataSource.getLedgerPage()) }) + + fun findLedger(identifier: String): Observable<Ledger> = + baseManagerApi.accountingService.findLedger(identifier) + .onErrorResumeNext(Function<Throwable, ObservableSource<Ledger>> + { Observable.just(FakeRemoteDataSource.getLedgerPage()!!.ledgers!![0]) }) +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/data/models/accounts/AccountType.kt b/app/src/main/java/org/apache/fineract/data/models/accounts/AccountType.kt new file mode 100644 index 0000000..f0495a2 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/data/models/accounts/AccountType.kt @@ -0,0 +1,21 @@ +package org.apache.fineract.data.models.accounts + +import com.google.gson.annotations.SerializedName + +enum class AccountType { + + @SerializedName("ASSET") + ASSET, + + @SerializedName("LIABILITY") + LIABILITY, + + @SerializedName("EQUITY") + EQUITY, + + @SerializedName("REVENUE") + REVENUE, + + @SerializedName("EXPENSE") + EXPENSE +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/data/models/accounts/Ledger.kt b/app/src/main/java/org/apache/fineract/data/models/accounts/Ledger.kt new file mode 100644 index 0000000..b945674 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/data/models/accounts/Ledger.kt @@ -0,0 +1,25 @@ +package org.apache.fineract.data.models.accounts + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize +import java.math.BigDecimal + +@Parcelize +data class Ledger( + + @SerializedName("type") val type: AccountType, + @SerializedName("identifier") val identifier: String? = null, + @SerializedName("name") val name: String? = null, + @SerializedName("description") val description: String? = null, + @SerializedName("parentLedgerIdentifier") val parentLedgerIdentifier: String? = null, + @SerializedName("subLedgers") val subLedgers: List<Ledger>? = null, + @SerializedName("totalValue") val totalValue: BigDecimal? = null, + @SerializedName("createdOn") val createdOn: String? = null, + @SerializedName("createdBy") val createdBy: String? = null, + @SerializedName("lastModifiedOn") val lastModifiedOn: String? = null, + @SerializedName("lastModifiedBy") val lastModifiedBy: String? = null, + @SerializedName("showAccountsInChart") val showAccountsInChart: Boolean + +) : Parcelable + diff --git a/app/src/main/java/org/apache/fineract/data/models/accounts/LedgerPage.kt b/app/src/main/java/org/apache/fineract/data/models/accounts/LedgerPage.kt new file mode 100644 index 0000000..3094be6 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/data/models/accounts/LedgerPage.kt @@ -0,0 +1,9 @@ +package org.apache.fineract.data.models.accounts + +import com.google.gson.annotations.SerializedName + +data class LedgerPage( + @SerializedName("ledgers") val ledgers: List<Ledger>? = null, + @SerializedName("totalPages") val totalPages: Int? = null, + @SerializedName("totalElements") val totalElements: Long? = null +) \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/data/remote/BaseApiManager.java b/app/src/main/java/org/apache/fineract/data/remote/BaseApiManager.java index a757812..0b8e0de 100644 --- a/app/src/main/java/org/apache/fineract/data/remote/BaseApiManager.java +++ b/app/src/main/java/org/apache/fineract/data/remote/BaseApiManager.java @@ -2,6 +2,7 @@ package org.apache.fineract.data.remote; import android.content.Context; +import org.apache.fineract.data.services.AccountingService; import org.apache.fineract.data.services.AnonymousService; import org.apache.fineract.data.services.AuthService; import org.apache.fineract.data.services.CustomerService; @@ -33,7 +34,7 @@ public class BaseApiManager { private static IndividualLendingService individualLendingService; private static AnonymousService anonymousService; private static RolesService rolesService; - + private static AccountingService accountingService; public BaseApiManager(Context context) { createService(context); @@ -47,6 +48,7 @@ public class BaseApiManager { loanApi = createApi(LoanService.class); individualLendingService = createApi(IndividualLendingService.class); rolesService = createApi(RolesService.class); + accountingService = createApi(AccountingService.class); } private static void initAnonymous() { @@ -115,4 +117,8 @@ public class BaseApiManager { public RolesService getRolesAndPermissionsService() { return rolesService; } + + public AccountingService getAccountingService() { + return accountingService; + } } diff --git a/app/src/main/java/org/apache/fineract/data/remote/EndPoints.java b/app/src/main/java/org/apache/fineract/data/remote/EndPoints.java index 8172ea0..4bd9a21 100644 --- a/app/src/main/java/org/apache/fineract/data/remote/EndPoints.java +++ b/app/src/main/java/org/apache/fineract/data/remote/EndPoints.java @@ -15,5 +15,6 @@ public class EndPoints { public static final String API_CUSTOMER_PATH = "/api/customer/v1"; public static final String API_DEPOSIT_PATH = "/api/deposit/v1"; public static final String API_PORTFOLIO_PATH = "/api/portfolio/v1"; + public static final String API_ACCOUNTING_PATH = "/api/accounting/v1"; } diff --git a/app/src/main/java/org/apache/fineract/data/services/AccountingService.kt b/app/src/main/java/org/apache/fineract/data/services/AccountingService.kt new file mode 100644 index 0000000..fa94fff --- /dev/null +++ b/app/src/main/java/org/apache/fineract/data/services/AccountingService.kt @@ -0,0 +1,19 @@ +package org.apache.fineract.data.services + +import io.reactivex.Observable +import org.apache.fineract.data.models.accounts.Ledger +import org.apache.fineract.data.models.accounts.LedgerPage +import org.apache.fineract.data.remote.EndPoints +import retrofit2.http.GET +import retrofit2.http.Path + + +interface AccountingService { + + @GET(EndPoints.API_ACCOUNTING_PATH + "/ledgers") + fun fetchLedgers(): Observable<LedgerPage> + + @GET(EndPoints.API_ACCOUNTING_PATH + "/ledgers/{identifier}") + fun findLedger(@Path("identifier") identifier: String): Observable<Ledger> + +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java b/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java index a4dfd00..144a10a 100644 --- a/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java +++ b/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java @@ -4,34 +4,44 @@ import org.apache.fineract.injection.PerActivity; import org.apache.fineract.injection.module.ActivityModule; import org.apache.fineract.ui.offline.CustomerPayloadFragment; import org.apache.fineract.ui.online.DashboardActivity; -import org.apache.fineract.ui.online.customers.createcustomer.customeractivity.CreateCustomerActivity; -import org.apache.fineract.ui.online.customers.createcustomer.formcustomeraddress.FormCustomerAddressFragment; - +import org.apache.fineract.ui.online.accounting.ledgers.LedgerFragment; +import org.apache.fineract.ui.online.customers.createcustomer.customeractivity + .CreateCustomerActivity; +import org.apache.fineract.ui.online.customers.createcustomer.formcustomeraddress + .FormCustomerAddressFragment; import org.apache.fineract.ui.online.customers.customeractivities.CustomerActivitiesFragment; +import org.apache.fineract.ui.online.customers.customerdetails.CustomerDetailsFragment; import org.apache.fineract.ui.online.customers.customerlist.CustomersFragment; -import org.apache.fineract.ui.online.customers.customerprofile.editcustomerprofilebottomsheet.EditCustomerProfileBottomSheet; +import org.apache.fineract.ui.online.customers.customerprofile.editcustomerprofilebottomsheet + .EditCustomerProfileBottomSheet; import org.apache.fineract.ui.online.customers.customertasks.CustomerTasksBottomSheetFragment; -import org.apache.fineract.ui.online.depositaccounts.createdepositaccount.FormDepositOverviewFragment; - -import org.apache.fineract.ui.online.depositaccounts.createdepositaccount.createdepositactivity.CreateDepositActivity; -import org.apache.fineract.ui.online.depositaccounts.createdepositaccount.formdepositassignproduct.FormDepositAssignProductFragment; +import org.apache.fineract.ui.online.depositaccounts.createdepositaccount + .FormDepositOverviewFragment; +import org.apache.fineract.ui.online.depositaccounts.createdepositaccount.createdepositactivity + .CreateDepositActivity; +import org.apache.fineract.ui.online.depositaccounts.createdepositaccount + .formdepositassignproduct.FormDepositAssignProductFragment; +import org.apache.fineract.ui.online.depositaccounts.depositaccountdetails + .DepositAccountDetailsFragment; import org.apache.fineract.ui.online.depositaccounts.depositaccountslist.DepositAccountsFragment; -import org.apache.fineract.ui.online.customers.customerdetails.CustomerDetailsFragment; -import org.apache.fineract.ui.online.loanaccounts.loanaccountlist.LoanAccountsFragment; -import org.apache.fineract.ui.online.loanaccounts.debtincomereport.DebtIncomeReportFragment; -import org.apache.fineract.ui.online.depositaccounts.depositaccountdetails.DepositAccountDetailsFragment; -import org.apache.fineract.ui.online.identification.createidentification.identificationactivity.CreateIdentificationActivity; -import org.apache.fineract.ui.online.identification.identificationdetails.IdentificationDetailsFragment; +import org.apache.fineract.ui.online.identification.createidentification.identificationactivity + .CreateIdentificationActivity; +import org.apache.fineract.ui.online.identification.identificationdetails + .IdentificationDetailsFragment; import org.apache.fineract.ui.online.identification.identificationlist.IdentificationsFragment; -import org.apache.fineract.ui.online.identification.uploadidentificationscan.UploadIdentificationCardBottomSheet; +import org.apache.fineract.ui.online.identification.uploadidentificationscan + .UploadIdentificationCardBottomSheet; import org.apache.fineract.ui.online.launcher.LauncherActivity; +import org.apache.fineract.ui.online.loanaccounts.debtincomereport.DebtIncomeReportFragment; +import org.apache.fineract.ui.online.loanaccounts.loanaccountlist.LoanAccountsFragment; import org.apache.fineract.ui.online.loanaccounts.loanapplication.BaseFragmentDebtIncome; -import org.apache.fineract.ui.online.loanaccounts.loanapplication.loanactivity.LoanApplicationActivity; +import org.apache.fineract.ui.online.loanaccounts.loanapplication.loanactivity + .LoanApplicationActivity; import org.apache.fineract.ui.online.loanaccounts.loanapplication.loancosigner.LoanCoSignerFragment; import org.apache.fineract.ui.online.loanaccounts.loanapplication.loandetails.LoanDetailsFragment; import org.apache.fineract.ui.online.loanaccounts.loandetails.CustomerLoanDetailsFragment; -import org.apache.fineract.ui.online.login.LoginActivity; import org.apache.fineract.ui.online.loanaccounts.plannedpayment.PlannedPaymentFragment; +import org.apache.fineract.ui.online.login.LoginActivity; import org.apache.fineract.ui.online.roles.roleslist.RolesFragment; import dagger.Subcomponent; @@ -101,4 +111,5 @@ public interface ActivityComponent { void inject(CustomerPayloadFragment customerPayloadFragment); + void inject(LedgerFragment ledgerFragment); } diff --git a/app/src/main/java/org/apache/fineract/injection/component/ApplicationComponent.java b/app/src/main/java/org/apache/fineract/injection/component/ApplicationComponent.java index 7a22b6e..c24b5a9 100644 --- a/app/src/main/java/org/apache/fineract/injection/component/ApplicationComponent.java +++ b/app/src/main/java/org/apache/fineract/injection/component/ApplicationComponent.java @@ -14,6 +14,7 @@ import org.apache.fineract.data.datamanager.api.DataManagerIndividualLending; import org.apache.fineract.data.datamanager.api.DataManagerLoans; import org.apache.fineract.data.datamanager.api.DataManagerRoles; import org.apache.fineract.data.datamanager.database.DbManagerCustomer; +import org.apache.fineract.data.datamanager.DataManagerAccounting; import org.apache.fineract.data.local.PreferencesHelper; import org.apache.fineract.data.local.database.helpers.DatabaseHelperCustomer; import org.apache.fineract.data.remote.BaseApiManager; @@ -44,6 +45,7 @@ public interface ApplicationComponent { DataManagerIndividualLending dataManagerIndividualLending(); DataManagerAnonymous dataManagerAnonymous(); DataManagerRoles dataManagerRolesAndPermissions(); + DataManagerAccounting dataManagerAccounting(); BaseApiManager baseApiManager(); PreferencesHelper preferencesHelper(); diff --git a/app/src/main/java/org/apache/fineract/ui/adapters/LedgerAdapter.kt b/app/src/main/java/org/apache/fineract/ui/adapters/LedgerAdapter.kt new file mode 100644 index 0000000..dccd522 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/adapters/LedgerAdapter.kt @@ -0,0 +1,65 @@ +package org.apache.fineract.ui.adapters + +import android.content.Context +import android.support.v7.widget.AppCompatImageView +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import kotlinx.android.synthetic.main.item_ledger.view.* +import org.apache.fineract.R +import org.apache.fineract.data.models.accounts.Ledger +import org.apache.fineract.injection.ApplicationContext +import org.apache.fineract.utils.DateUtils +import org.apache.fineract.utils.StatusUtils +import javax.inject.Inject + +class LedgerAdapter @Inject constructor(@ApplicationContext val context: Context) + : RecyclerView.Adapter<LedgerAdapter.ViewHolder>() { + + private var ledgers: List<Ledger> = ArrayList() + + override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder { + + val view = LayoutInflater.from(parent?.context).inflate(R.layout.item_ledger, parent, false) + return ViewHolder(view) + } + + override fun getItemCount(): Int = ledgers.size + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + + val ledger = ledgers[position] + + holder.tvLedgerIdentifier.text = ledger.identifier + + val modifiedBy = context.getString(R.string.last_modified_by) + context.getString( + R.string.colon) + ledger.lastModifiedBy + holder.tvModifiedBy.text = modifiedBy + + val lastModifiedOn = context.getString(R.string.last_modified_on) + context.getString( + R.string.colon) + + DateUtils.getDate(ledger.lastModifiedOn, + DateUtils.INPUT_DATE_FORMAT, DateUtils.OUTPUT_DATE_FORMAT) + + StatusUtils.setAccountType(ledger.type, holder?.ivAccountTypeIndicator, context) + + holder.tvModifiedOn.text = lastModifiedOn + holder.tvTotalValue.text = ledger.totalValue.toString() + } + + fun setLedgerList(ledgers: List<Ledger>) { + this.ledgers = ledgers + notifyDataSetChanged() + } + + class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + + val tvLedgerIdentifier: TextView = itemView.tv_ledger_identifier + val tvModifiedBy: TextView = itemView.tv_modified_by + val tvModifiedOn: TextView = itemView.tv_modified_on + val tvTotalValue: TextView = itemView.tv_total_value + val ivAccountTypeIndicator: AppCompatImageView = itemView.iv_type_indicator + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/online/DashboardActivity.java b/app/src/main/java/org/apache/fineract/ui/online/DashboardActivity.java index f053318..2b782cb 100644 --- a/app/src/main/java/org/apache/fineract/ui/online/DashboardActivity.java +++ b/app/src/main/java/org/apache/fineract/ui/online/DashboardActivity.java @@ -17,6 +17,7 @@ import org.apache.fineract.data.local.PreferencesHelper; import org.apache.fineract.jobs.StartSyncJob; import org.apache.fineract.ui.base.FineractBaseActivity; import org.apache.fineract.ui.offline.CustomerPayloadFragment; +import org.apache.fineract.ui.online.accounting.ledgers.LedgerFragment; import org.apache.fineract.ui.online.customers.customerlist.CustomersFragment; import org.apache.fineract.ui.online.dashboard.DashboardFragment; import org.apache.fineract.ui.online.launcher.LauncherActivity; @@ -113,6 +114,9 @@ public class DashboardActivity extends FineractBaseActivity implements case R.id.item_logout: logout(); break; + case R.id.item_ledger: + replaceFragment(LedgerFragment.Companion.newInstance(), true, R.id.container); + break; } drawerLayout.closeDrawer(Gravity.START); setTitle(item.getTitle()); diff --git a/app/src/main/java/org/apache/fineract/ui/online/accounting/ledgers/LedgerContract.kt b/app/src/main/java/org/apache/fineract/ui/online/accounting/ledgers/LedgerContract.kt new file mode 100644 index 0000000..e76cd28 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/online/accounting/ledgers/LedgerContract.kt @@ -0,0 +1,32 @@ +package org.apache.fineract.ui.online.accounting.accounts + +import org.apache.fineract.data.models.accounts.Ledger +import org.apache.fineract.ui.base.MvpView + +interface LedgerContract { + + interface View : MvpView { + + fun showUserInterface() + + fun showLedgers(ledgers: List<Ledger>) + + fun showEmptyLedgers() + + fun showRecyclerView(status: Boolean) + + fun showProgressbar() + + fun hideProgressbar() + + fun searchedLedger(ledger: Ledger) + + } + + interface Presenter { + + fun getLedgersPage() + + fun searchLedger(identifier: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/online/accounting/ledgers/LedgerFragment.kt b/app/src/main/java/org/apache/fineract/ui/online/accounting/ledgers/LedgerFragment.kt new file mode 100644 index 0000000..482eb6d --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/online/accounting/ledgers/LedgerFragment.kt @@ -0,0 +1,168 @@ +package org.apache.fineract.ui.online.accounting.ledgers + + +import android.app.SearchManager +import android.content.Context +import android.os.Bundle +import android.support.v4.widget.SwipeRefreshLayout +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.SearchView +import android.text.TextUtils +import android.view.* +import kotlinx.android.synthetic.main.fragment_ledger.* +import kotlinx.android.synthetic.main.layout_exception_handler.* +import org.apache.fineract.R +import org.apache.fineract.data.models.accounts.Ledger +import org.apache.fineract.ui.adapters.LedgerAdapter +import org.apache.fineract.ui.base.FineractBaseActivity +import org.apache.fineract.ui.base.FineractBaseFragment +import org.apache.fineract.ui.online.accounting.accounts.LedgerContract +import java.util.* +import javax.inject.Inject +import kotlin.collections.ArrayList + + +class LedgerFragment : FineractBaseFragment(), LedgerContract.View, + SwipeRefreshLayout.OnRefreshListener { + + @Inject + lateinit var ledgerAdapter: LedgerAdapter + + @Inject + lateinit var ledgerPresenter: LedgerPresenter + + lateinit var ledgerList: List<Ledger> + + companion object { + fun newInstance(): LedgerFragment = LedgerFragment() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setHasOptionsMenu(true) + ledgerList = ArrayList() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + val rootView = inflater.inflate(R.layout.fragment_ledger, container, false) + (activity as FineractBaseActivity).activityComponent.inject(this) + ledgerPresenter.attachView(this) + initializeFineractUIErrorHandler(activity, rootView) + + return rootView + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + showUserInterface() + + btn_try_again.setOnClickListener { + layoutError.visibility = View.GONE + ledgerPresenter.getLedgersPage() + } + + ledgerPresenter.getLedgersPage() + } + + override fun showUserInterface() { + + setToolbarTitle(getString(R.string.ledger)) + val layoutManager = LinearLayoutManager(activity) + layoutManager.orientation = LinearLayoutManager.VERTICAL + rvLedger.layoutManager = layoutManager + rvLedger.setHasFixedSize(true) + + rvLedger.adapter = ledgerAdapter + + swipeContainer.setColorSchemeColors(*activity!! + .resources.getIntArray(R.array.swipeRefreshColors)) + swipeContainer.setOnRefreshListener(this) + } + + override fun onRefresh() { + ledgerPresenter.getLedgersPage() + } + + override fun showLedgers(ledgers: List<Ledger>) { + showRecyclerView(true) + this.ledgerList = ledgers + ledgerAdapter.setLedgerList(ledgers) + } + + override fun showEmptyLedgers() { + showRecyclerView(false) + showFineractEmptyUI(getString(R.string.ledger), getString(R.string.ledger), + R.drawable.ic_person_outline_black_24dp) + } + + override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + super.onCreateOptionsMenu(menu, inflater) + inflater?.inflate(R.menu.menu_ledger_search, menu) + setUpSearchInterface(menu) + } + + private fun setUpSearchInterface(menu: Menu?) { + + val searchManager = activity?.getSystemService(Context.SEARCH_SERVICE) as? SearchManager + val searchView = menu?.findItem(R.id.ledger_search)?.actionView as? SearchView + + searchView?.setSearchableInfo(searchManager?.getSearchableInfo(activity?.componentName)) + + searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + ledgerPresenter.searchLedger(query) + return false + } + + override fun onQueryTextChange(newText: String): Boolean { + if (TextUtils.isEmpty(newText)) { + showRecyclerView(true) + ledgerAdapter.setLedgerList(ledgerList) + } + + return false + } + }) + + } + + override fun searchedLedger(ledger: Ledger) { + showRecyclerView(true) + ledgerAdapter.setLedgerList(Collections.singletonList(ledger)) + } + + override fun showRecyclerView(status: Boolean) { + if (status) { + rvLedger.visibility = View.VISIBLE + layoutError.visibility = View.GONE + } else { + rvLedger.visibility = View.GONE + layoutError.visibility = View.VISIBLE + } + } + + override fun showProgressbar() { + swipeContainer.isRefreshing = true + } + + override fun hideProgressbar() { + swipeContainer.isRefreshing = false + } + + override fun showNoInternetConnection() { + showRecyclerView(false) + showFineractNoInternetUI() + } + + override fun showError(message: String) { + showRecyclerView(false) + showFineractErrorUI(getString(R.string.ledger)) + } + + override fun onDestroyView() { + super.onDestroyView() + ledgerPresenter.detachView() + } +} diff --git a/app/src/main/java/org/apache/fineract/ui/online/accounting/ledgers/LedgerPresenter.kt b/app/src/main/java/org/apache/fineract/ui/online/accounting/ledgers/LedgerPresenter.kt new file mode 100644 index 0000000..5086b40 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/online/accounting/ledgers/LedgerPresenter.kt @@ -0,0 +1,87 @@ +package org.apache.fineract.ui.online.accounting.ledgers + +import android.content.Context +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.observers.DisposableObserver +import io.reactivex.schedulers.Schedulers +import org.apache.fineract.R +import org.apache.fineract.data.datamanager.DataManagerAccounting +import org.apache.fineract.data.models.accounts.Ledger +import org.apache.fineract.data.models.accounts.LedgerPage +import org.apache.fineract.injection.ApplicationContext +import org.apache.fineract.ui.base.BasePresenter +import org.apache.fineract.ui.online.accounting.accounts.LedgerContract +import javax.inject.Inject + +class LedgerPresenter @Inject constructor(@ApplicationContext context: Context, + val dataManagerAccounting: DataManagerAccounting) + : BasePresenter<LedgerContract.View>(context), LedgerContract.Presenter { + + private val compositeDisposable = CompositeDisposable() + + override fun getLedgersPage() { + checkViewAttached() + mvpView.showProgressbar() + + compositeDisposable.add(dataManagerAccounting.fetchLedgers() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(object : DisposableObserver<LedgerPage>() { + override fun onComplete() { + + } + + override fun onNext(ledgerPage: LedgerPage) { + + mvpView.hideProgressbar() + + if (ledgerPage.ledgers != null) { + + if (ledgerPage.ledgers.isEmpty()) { + mvpView.showLedgers(ledgerPage.ledgers) + } else { + mvpView.showEmptyLedgers() + } + } + + } + + override fun onError(throwable: Throwable) { + mvpView.hideProgressbar() + showExceptionError(throwable, + context.getString(R.string.error_fetching_ledger)) + } + }) + ) + } + + override fun searchLedger(identifier: String) { + checkViewAttached() + mvpView.showProgressbar() + + compositeDisposable.add(dataManagerAccounting.findLedger(identifier) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(object : DisposableObserver<Ledger>() { + override fun onComplete() { + + } + + override fun onNext(ledger: Ledger) { + mvpView.hideProgressbar() + mvpView.searchedLedger(ledger) + + } + + override fun onError(throwable: Throwable) { + mvpView.hideProgressbar() + showExceptionError(throwable, + context.getString(R.string.error_fetching_ledger)) + } + }) + ) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/utils/StatusUtils.java b/app/src/main/java/org/apache/fineract/utils/StatusUtils.java index 8ede644..4795aa9 100644 --- a/app/src/main/java/org/apache/fineract/utils/StatusUtils.java +++ b/app/src/main/java/org/apache/fineract/utils/StatusUtils.java @@ -8,6 +8,7 @@ import android.widget.ImageView; import com.google.gson.annotations.SerializedName; import org.apache.fineract.R; +import org.apache.fineract.data.models.accounts.AccountType; import org.apache.fineract.data.models.customer.Command; import org.apache.fineract.data.models.customer.Customer; import org.apache.fineract.data.models.deposit.DepositAccount; @@ -233,5 +234,32 @@ public class StatusUtils { } } + + public static void setAccountType(AccountType action, ImageView imageView, + Context context) { + switch (action) { + case ASSET: + imageView.setColorFilter( + ContextCompat.getColor(context, R.color.status)); + break; + case LIABILITY: + imageView.setColorFilter( + ContextCompat.getColor(context, R.color.red_dark)); + break; + case EQUITY: + imageView.setColorFilter( + ContextCompat.getColor(context, R.color.blue)); + break; + case REVENUE: + imageView.setColorFilter( + ContextCompat.getColor(context, R.color.green_dark)); + break; + case EXPENSE: + imageView.setColorFilter( + ContextCompat.getColor(context, R.color.red_light)); + break; + + } + } } diff --git a/app/src/main/res/layout/fragment_ledger.xml b/app/src/main/res/layout/fragment_ledger.xml new file mode 100644 index 0000000..19ff350 --- /dev/null +++ b/app/src/main/res/layout/fragment_ledger.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.design.widget.CoordinatorLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + <android.support.v4.widget.SwipeRefreshLayout + android:id="@+id/swipeContainer" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + <android.support.v7.widget.RecyclerView + android:id="@+id/rvLedger" + android:layout_centerHorizontal="true" + android:layout_height="0dp" + android:layout_marginBottom="@dimen/layout_padding_30dp" + android:layout_weight="1" + android:layout_width="wrap_content"/> + </android.support.v4.widget.SwipeRefreshLayout> + + <include + layout="@layout/layout_exception_handler" + android:id="@+id/layoutError" + android:visibility="gone"/> + +</android.support.design.widget.CoordinatorLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/item_ledger.xml b/app/src/main/res/layout/item_ledger.xml new file mode 100644 index 0000000..c61fb82 --- /dev/null +++ b/app/src/main/res/layout/item_ledger.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/ll_loan_accounts" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clickable="true" + android:foreground="?android:attr/selectableItemBackground" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/ll_ledger" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/iv_type_indicator" + android:layout_width="@dimen/side_bar_width" + android:layout_height="match_parent" + android:layout_marginBottom="@dimen/default_margin" + android:layout_marginTop="@dimen/default_margin" + app:srcCompat="@drawable/round_corner" /> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical" + android:padding="@dimen/layout_padding_24dp"> + + <TextView + android:id="@+id/tv_ledger_identifier" + style="@style/Base.TextAppearance.AppCompat.Medium" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:textColor="@color/black" + tools:text="Teller Identifier" /> + + <TextView + android:id="@+id/tv_modified_by" + style="@style/Base.TextAppearance.AppCompat.Small" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:lines="1" + tools:text="Last modified by: rajan" /> + + <TextView + android:id="@+id/tv_modified_on" + style="@style/Base.TextAppearance.AppCompat.Small" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="Last modified on: 10 July 2018" /> + + </LinearLayout> + + <TextView + android:id="@+id/tv_total_value" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginEnd="@dimen/layout_padding_24dp" + android:layout_marginRight="@dimen/layout_padding_24dp" + android:textSize="@dimen/text_medium" + tools:text="Total Value" /> + + </LinearLayout> + + <View + android:layout_width="match_parent" + android:layout_height="0.2dp" + android:background="#E7DFDF" /> + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/menu/menu_ledger_search.xml b/app/src/main/res/menu/menu_ledger_search.xml new file mode 100644 index 0000000..6ddfbd0 --- /dev/null +++ b/app/src/main/res/menu/menu_ledger_search.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:id="@+id/ledger_search" + android:icon="@drawable/ic_search_black_24dp" + android:title="@string/ledger_search" + app:showAsAction="always" + app:actionViewClass="android.support.v7.widget.SearchView"/> + +</menu> \ No newline at end of file diff --git a/app/src/main/res/menu/menu_navigation_drawer.xml b/app/src/main/res/menu/menu_navigation_drawer.xml index 0e289df..0d505c2 100644 --- a/app/src/main/res/menu/menu_navigation_drawer.xml +++ b/app/src/main/res/menu/menu_navigation_drawer.xml @@ -29,6 +29,13 @@ android:id="@+id/item_customer_payload" android:title="Customer Payloads"/> + <item + android:checked="true" + android:icon="@drawable/ic_customer_black_24dp" + android:id="@+id/item_ledger" + android:title="@string/ledger"/> + + </group> <group diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7b01082..e81ddf5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -82,6 +82,7 @@ <string name="amount">Amount</string> <string name="description">Description</string> <string name="products">Products</string> + <string name="ledger">Ledgers</string> <string name="day">Day</string> <string name="in">In</string> <string name="required">Required</string> @@ -171,6 +172,7 @@ <string name="created_by">Created by</string> <string name="no_deposit_account">No deposit account</string> <string name="identification_search">Search identification card</string> + <string name="ledger_search">Ledger Search</string> <string name="loan_last_modified_by">%1$s %2$s</string> <string name="loan_created_by">%1$s %2$s</string> <string name="search_beneficiary">Search beneficiary</string> @@ -265,6 +267,7 @@ <string name="error_updating_deposit_account">Error updating deposit account</string> <string name="error_fetching_customer_activities">Error fetching customer activities</string> <string name="error_fetching_roles">Error fetching roles</string> + <string name="error_fetching_ledger">Error fetching ledger</string> <string name="error_sorry_not_able_to_load">Sorry we weren\'t able to load</string> <string name="error_fetching_customer_details">Failed to fetch customer details</string> <string name="error_fetching_deposit_product">Failed to fetch deposit product</string> diff --git a/app/src/main/resources/ledgerPage.json b/app/src/main/resources/ledgerPage.json new file mode 100644 index 0000000..139fc67 --- /dev/null +++ b/app/src/main/resources/ledgerPage.json @@ -0,0 +1,62 @@ +{ + "ledgers": [ + { + "type": "ASSET", + "identifier": "identifier1", + "name": "name", + "description": "description", + "parentLedgerIdentifier": "parentLedgerIdentifier", + "subLedgers": [], + "totalValue": 1200, + "createdOn": "createdOn", + "createdBy": "createdBy", + "lastModifiedOn": "lastModifiedOn", + "lastModifiedBy": "lastModifiedBy", + "showAccountsInChart": false + }, + { + "type": "LIABILITY", + "identifier": "identifier2", + "name": "name", + "description": "description", + "parentLedgerIdentifier": "parentLedgerIdentifier", + "subLedgers": [], + "totalValue": 1500, + "createdOn": "createdOn", + "createdBy": "createdBy", + "lastModifiedOn": "lastModifiedOn", + "lastModifiedBy": "lastModifiedBy", + "showAccountsInChart": false + }, + { + "type": "EQUITY", + "identifier": "identifier3", + "name": "name", + "description": "description", + "parentLedgerIdentifier": "parentLedgerIdentifier", + "subLedgers": [], + "totalValue": 1800, + "createdOn": "createdOn", + "createdBy": "createdBy", + "lastModifiedOn": "lastModifiedOn", + "lastModifiedBy": "lastModifiedBy", + "showAccountsInChart": false + }, + { + "type": "REVENUE", + "identifier": "identifier4", + "name": "name", + "description": "description", + "parentLedgerIdentifier": "parentLedgerIdentifier", + "subLedgers": [], + "totalValue": 2100, + "createdOn": "createdOn", + "createdBy": "createdBy", + "lastModifiedOn": "lastModifiedOn", + "lastModifiedBy": "lastModifiedBy", + "showAccountsInChart": false + } + ], + "totalPages": 1, + "totalElements": 4 +} \ No newline at end of file