瀏覽代碼

2024-12-09 新增 / 修改

新增:
1. 团组经理主管 - 出入境费用明细 - 其它费用明细
2. 团组经理主管 - 出入境费用明细 - 其它费用详情
3. 团组经理主管 - 出入境费用明细 - 其它费用 添加 / 修改

修改:
1. UI bug修改
2. 部分UI逻辑修改
zhaiy 7 月之前
父節點
當前提交
754915c552
共有 34 個文件被更改,包括 3440 次插入121 次删除
  1. 9 1
      app/src/main/AndroidManifest.xml
  2. 14 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/entity/EntryAndExitOtherPayment.kt
  3. 14 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/entity/EntryAndExitPaymentListItem.kt
  4. 12 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/entity/EntryAndExitPaymentPrinciple.kt
  5. 9 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/DeleteEntryAndExitPaymentItemRequest.kt
  6. 8 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/EntryAndExitOtherPaymentListResponse.kt
  7. 8 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/EntryAndExitPaymentListResponse.kt
  8. 9 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/EntryAndExitPaymentPrincipleRequest.kt
  9. 6 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/EntryAndExitPaymentPrincipleResponse.kt
  10. 15 12
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/InBoardDetailResponse.kt
  11. 3 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/OtherPaymentDataSourceRequest.kt
  12. 8 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/OtherPaymentDataSourceResponse.kt
  13. 12 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/UpdateEntryAndExitCurrencyRateRequest.kt
  14. 16 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/UpdateEntryAndExitPaymentDetailRequest.kt
  15. 12 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/UpdateEntryAndExitTypeStatusRequest.kt
  16. 16 0
      app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/UpdateOtherPaymentRequest.kt
  17. 82 6
      app/src/main/java/com/pan_american/android/data/network/APIService.kt
  18. 1 1
      app/src/main/java/com/pan_american/android/ui/customer_resource/related_invitee/RelatedInviteeSearchFragment.kt
  19. 0 4
      app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/EntryAndExitDetailActivity.kt
  20. 88 69
      app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/EntryAndExitFeeTotalFragment.kt
  21. 490 0
      app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/EntryAndExitPaymentDetailActivity.kt
  22. 464 0
      app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/EntryAndExitPaymentListFragment.kt
  23. 21 12
      app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/InBoardFeeFragment.kt
  24. 0 4
      app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/InternationalTravelFeeFragment.kt
  25. 329 0
      app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/OtherPaymentDetailActivity.kt
  26. 430 0
      app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/OtherPaymentFragment.kt
  27. 234 0
      app/src/main/res/layout/activity_entry_and_exit_payment_detail.xml
  28. 253 0
      app/src/main/res/layout/activity_other_payment_detail.xml
  29. 91 6
      app/src/main/res/layout/fragment_entry_and_exit_payment_list.xml
  30. 91 6
      app/src/main/res/layout/fragment_other_payment.xml
  31. 218 0
      app/src/main/res/layout/item_entry_and_exit_other_payment.xml
  32. 190 0
      app/src/main/res/layout/item_entry_and_exit_payment.xml
  33. 255 0
      app/src/main/res/layout/popup_currency_detail.xml
  34. 32 0
      app/src/main/res/values/strings.xml

+ 9 - 1
app/src/main/AndroidManifest.xml

@@ -36,8 +36,16 @@
         android:theme="@style/AppTheme"
         tools:targetApi="31">
         <activity
-            android:name=".ui.group_management.entry_and_exit_fee_detail.EntryAndExitDetailActivity"
+            android:name=".ui.group_management.entry_and_exit_fee_detail.OtherPaymentDetailActivity"
             android:exported="false" />
+        <activity
+            android:name=".ui.group_management.entry_and_exit_fee_detail.EntryAndExitPaymentDetailActivity"
+            android:exported="false"
+            android:launchMode="singleTop" />
+        <activity
+            android:name=".ui.group_management.entry_and_exit_fee_detail.EntryAndExitDetailActivity"
+            android:exported="false"
+            android:launchMode="singleTop" />
         <activity
             android:name=".ui.group_management.entry_and_exit_fee_detail.EntryAndExitFeeGroupListActivity"
             android:exported="false"

+ 14 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/entity/EntryAndExitOtherPayment.kt

@@ -0,0 +1,14 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.entity
+
+class EntryAndExitOtherPayment {
+    var subId = 0
+    var diId = 0
+    var index = 0
+    var setDataId = 0
+    var setDataName = ""
+    var cost = 0.0
+    var currency = 0
+    var currencyName = ""
+    var subTotal = 0.0
+    var remark = ""
+}

+ 14 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/entity/EntryAndExitPaymentListItem.kt

@@ -0,0 +1,14 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.entity
+
+class EntryAndExitPaymentListItem {
+    var subId = 0
+    var diId = 0
+    var type = 0
+    var days = 0
+    var nationalTravelFeeId = 0
+    var arae = ""
+    var cost = 0.0
+    var currency = 0
+    var currencyName = ""
+    var subTotal = 0.0
+}

+ 12 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/entity/EntryAndExitPaymentPrinciple.kt

@@ -0,0 +1,12 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.entity
+
+data class EntryAndExitPaymentPrinciple(
+    val id: Int,
+    val area: String,
+    val currency: Int,
+    val currencyCode: String,
+    val currencyName: String,
+    val roomCost: Double,
+    val foodCost: Double,
+    val publicCost: Double
+)

+ 9 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/DeleteEntryAndExitPaymentItemRequest.kt

@@ -0,0 +1,9 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+import com.pan_american.android.OASystem
+
+data class DeleteEntryAndExitPaymentItemRequest(
+    val portType: Int = 2,
+    val id: Int,
+    val deleteUserId: Int = OASystem.userInfo.userId
+)

+ 8 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/EntryAndExitOtherPaymentListResponse.kt

@@ -0,0 +1,8 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.entity.EntryAndExitOtherPayment
+
+data class EntryAndExitOtherPaymentListResponse(val data: Data): BaseResponse() {
+    inner class Data (val parentId: Int, val otherExpenses_Checked: Int, val otherExpensesTotalCost: Double, val details: ArrayList<EntryAndExitOtherPayment>)
+}

+ 8 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/EntryAndExitPaymentListResponse.kt

@@ -0,0 +1,8 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.entity.EntryAndExitPaymentListItem
+
+class EntryAndExitPaymentListResponse(val data: Data): BaseResponse() {
+    inner class Data (val parentId: Int, val choice: Int, val totalCost:Double, val details: ArrayList<EntryAndExitPaymentListItem>)
+}

+ 9 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/EntryAndExitPaymentPrincipleRequest.kt

@@ -0,0 +1,9 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+data class EntryAndExitPaymentPrincipleRequest(
+    val portType: Int = 2,
+) {
+    var pageIndex = 0
+    var pageSize = 10
+    var search = ""
+}

+ 6 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/EntryAndExitPaymentPrincipleResponse.kt

@@ -0,0 +1,6 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.entity.EntryAndExitPaymentPrinciple
+
+class EntryAndExitPaymentPrincipleResponse(val data: ArrayList<EntryAndExitPaymentPrinciple>): BaseResponse()

+ 15 - 12
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/InBoardDetailResponse.kt

@@ -1,14 +1,17 @@
 package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
 
-data class InBoardDetailResponse(
-    val id : Int,
-    val choiceOne: Int,
-    val choiceOneTotalCost: Double,
-    val visa:Double,
-    val visaRemark: String,
-    val yiMiao: Double,
-    val heSuan: Double,
-    val service: Double,
-    val ticket: Double,
-    val safe: Double
-)
+import com.pan_american.android.base.BaseResponse
+
+data class InBoardDetailResponse(val data: Data): BaseResponse() {
+    inner class Data (
+        val id : Int,
+        val choiceOne: Int,
+        val visa:Double,
+        val visaRemark: String,
+        val yiMiao: Double,
+        val heSuan: Double,
+        val service: Double,
+        val ticket: Double,
+        val safe: Double
+    )
+}

+ 3 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/OtherPaymentDataSourceRequest.kt

@@ -0,0 +1,3 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+data class OtherPaymentDataSourceRequest(val portType: Int = 2, val diId: Int)

+ 8 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/OtherPaymentDataSourceResponse.kt

@@ -0,0 +1,8 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.data.model.common.entity.Selector
+
+data class OtherPaymentDataSourceResponse(val data: Data): BaseResponse() {
+    inner class Data (val groupOtherRateData: ArrayList<Selector>, val otherFeeTypeData: ArrayList<Selector>)
+}

+ 12 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/UpdateEntryAndExitCurrencyRateRequest.kt

@@ -0,0 +1,12 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+import com.pan_american.android.OASystem
+import com.pan_american.android.data.model.common.entity.Selector
+
+data class UpdateEntryAndExitCurrencyRateRequest(
+    val portType: Int = 2,
+    val id: Int,
+    val diId: Int,
+    val currUserId: Int = OASystem.userInfo.userId,
+    val currencys: ArrayList<Selector>
+)

+ 16 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/UpdateEntryAndExitPaymentDetailRequest.kt

@@ -0,0 +1,16 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+import com.pan_american.android.OASystem
+
+class UpdateEntryAndExitPaymentDetailRequest() {
+    val portType = 2
+    var subId = 0
+    var diId = 0
+    var days = 0
+    var nationalTravelFeeId = 0
+    var cost = 0.0
+    var currency = 0
+    var subTotal = 0.0
+    val currUserId = OASystem.userInfo.userId
+    var feeType = 0
+}

+ 12 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/UpdateEntryAndExitTypeStatusRequest.kt

@@ -0,0 +1,12 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+import com.pan_american.android.OASystem
+
+data class UpdateEntryAndExitTypeStatusRequest(
+    val portType: Int = 2,
+    val id: Int,
+    val diId: Int,
+    val currUserId: Int = OASystem.userInfo.userId,
+    val itemType: Int,
+    val isSelected: Int
+)

+ 16 - 0
app/src/main/java/com/pan_american/android/data/model/group_management/entry_and_exit_fee_detail/network/UpdateOtherPaymentRequest.kt

@@ -0,0 +1,16 @@
+package com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network
+
+import com.pan_american.android.OASystem
+
+class UpdateOtherPaymentRequest {
+    val portType = 2
+    val currUserId = OASystem.userInfo.userId
+    var subId = 0
+    var diid = 0
+    var setDataId = 0
+    var index = 0
+    var cost = 0.0
+    var currency = 0
+    var subTotal = 0.0
+    var remark = ""
+}

+ 82 - 6
app/src/main/java/com/pan_american/android/data/network/APIService.kt

@@ -150,16 +150,26 @@ import com.pan_american.android.data.model.group_invite_official.official_visits
 import com.pan_american.android.data.model.group_invite_official.official_visits.network.UpdateOfficialVisitCheckCommitRequest
 import com.pan_american.android.data.model.group_invite_official.official_visits.network.UpdateOfficialVisitRequest
 import com.pan_american.android.data.model.group_invite_official.official_visits.network.UpdateOfficialVisitResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.DeleteEntryAndExitPaymentItemRequest
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitDetailRequest
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitDetailResponse
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitGroupListRequest
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitGroupListResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitOtherPaymentListResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitPaymentListResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitPaymentPrincipleRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitPaymentPrincipleResponse
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitPaymentTypeRequest
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitTipsRequest
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.InBoardDetailResponse
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.InternationalTravelPaymentDetailResponse
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.InternationalTravelTipsResponse
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.NewestVisaPaymentResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.OtherPaymentDataSourceRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.OtherPaymentDataSourceResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateEntryAndExitCurrencyRateRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateEntryAndExitPaymentDetailRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateEntryAndExitTypeStatusRequest
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateInBoardPaymentRequest
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateInBoardPaymentResponse
 import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateInternationalTravelRequest
@@ -465,7 +475,10 @@ interface APIService {
      * 日付申请,日付申请筛选列表
      */
     @POST("/api/Financial/PostPageSearchDailyPaymentPriceTypeData")
-    fun getPaymentSiftDataSource(@Header("authorization") authToken: String = OASystem.token, @Body baseRequest: BaseRequest): Call<DailyPaymentSiftResponse>
+    fun getPaymentSiftDataSource(
+        @Header("authorization") authToken: String = OASystem.token,
+        @Body baseRequest: BaseRequest
+    ): Call<DailyPaymentSiftResponse>
 
     /**
      * 日付申请,添加日付申请列表选项
@@ -862,7 +875,10 @@ interface APIService {
      * 邀请资料,删除文件
      */
     @DELETE("/api/Resource/InvitationOfficialActivityDelFile/{id}")
-    fun deleteInviteDataFile(@Path("id") id: Int, @Query("fileName") fileName: String): Call<BaseResponse>
+    fun deleteInviteDataFile(
+        @Path("id") id: Int,
+        @Query("fileName") fileName: String
+    ): Call<BaseResponse>
 
     /**
      * 文档下载 团组list
@@ -1055,7 +1071,7 @@ interface APIService {
      * 公务出访,省外办/市外办 文件下载
      */
     @POST("/api/Resource/OfficialActivitiesFileDownload")
-    fun downloadProvinceAndCityRequestFile(@Body provinceAndCityDownloadFileRequest: ProvinceAndCityDownloadFileRequest):Call<ProvinceAndCityDownloadFileResponse>
+    fun downloadProvinceAndCityRequestFile(@Body provinceAndCityDownloadFileRequest: ProvinceAndCityDownloadFileRequest): Call<ProvinceAndCityDownloadFileResponse>
 
     /**
      * 基础数据源,通用接口
@@ -1092,7 +1108,7 @@ interface APIService {
      * 公务出访,复核确认/取消确认
      */
     @POST("/api/Resource/OfficialActivitiesInviteOperation")
-    fun updateOfficialVisitCheckCommit(@Body updateOfficialVisitCheckCommitRequest: UpdateOfficialVisitCheckCommitRequest):Call<BaseResponse>
+    fun updateOfficialVisitCheckCommit(@Body updateOfficialVisitCheckCommitRequest: UpdateOfficialVisitCheckCommitRequest): Call<BaseResponse>
 
     /**
      * 提成确认,查询提成列表
@@ -1122,7 +1138,10 @@ interface APIService {
      * 物资进销存,物资申领
      */
     @POST("/api/PersonnelModule/GoodsReceiveOP")
-    fun materialApplicationOperate(@Body materialApplicationRequest: MaterialApplicationRequest, @Header("Authorization") headerValue: String = OASystem.token): Call<MaterialApplicationResponse>
+    fun materialApplicationOperate(
+        @Body materialApplicationRequest: MaterialApplicationRequest,
+        @Header("Authorization") headerValue: String = OASystem.token
+    ): Call<MaterialApplicationResponse>
 
     /**
      * 物资进销存,领用历史记录
@@ -1225,7 +1244,10 @@ interface APIService {
      * 收款账单,导入三公费用
      */
     @GET("/api/Groups/NationalTravelFeeImportReceivables/{id}")
-    fun importThreePublicExpense(@Path("id") groupId: Int, @Header("Authorization") headerValue: String = OASystem.token): Call<BaseResponse>
+    fun importThreePublicExpense(
+        @Path("id") groupId: Int,
+        @Header("Authorization") headerValue: String = OASystem.token
+    ): Call<BaseResponse>
 
     /**
      * 收款账单,获取导出收款账单FileList
@@ -1298,4 +1320,58 @@ interface APIService {
      */
     @POST("/api/Groups/EnterExitCostMobileOpStep2")
     fun updateInternationalTravelPayment(@Body updateInternationalTravelRequest: UpdateInternationalTravelRequest): Call<UpdateInternationalTravelResponse>
+
+    /**
+     * 出入境费用,获取费用list
+     */
+    @POST("/api/Groups/EnterExitCostMobileSubInfo")
+    fun getEntryAndExitPaymentList(@Body entryAndExitPaymentTypeRequest: EntryAndExitPaymentTypeRequest): Call<EntryAndExitPaymentListResponse>
+
+    /**
+     * 出入境费用,删除费用项
+     */
+    @POST("/api/Groups/EnterExitCostMobileSubItemDel")
+    fun deleteEntryAndExitPaymentItem(@Body deleteEntryAndExitPaymentItemRequest: DeleteEntryAndExitPaymentItemRequest): Call<BaseResponse>
+
+    /**
+     * 出入境费用,更新汇率
+     */
+    @POST("/api/Groups/EnterExitCostMobileOpRate")
+    fun updateEntryAndExitCurrencyRate(@Body updateEntryAndExitCurrencyRateRequest: UpdateEntryAndExitCurrencyRateRequest): Call<BaseResponse>
+
+    /**
+     * 出入境费用,获取国家 - 地区 及费用标准
+     */
+    @POST("/api/Groups/NationalTravelFeeMobileData")
+    fun getEntryAndExitCurrencyCityAndPrinciples(@Body entryAndExitPaymentPrincipleRequest: EntryAndExitPaymentPrincipleRequest): Call<EntryAndExitPaymentPrincipleResponse>
+
+    /**
+     * 出入境费用明细,添加 / 更新
+     */
+    @POST("/api/Groups/EnterExitCostMobileOpSingleStep3To6")
+    fun updateEntryAndExitPaymentDetail(@Body updateEntryAndExitPaymentDetailRequest: UpdateEntryAndExitPaymentDetailRequest): Call<BaseResponse>
+
+    /**
+     * 出入境费用明细, 费用勾选项更新
+     */
+    @POST("/api/Groups/EnterExitCostMobileOpSingleCheckbox")
+    fun updateEntryAndExitTypeStatus(@Body updateEntryAndExitTypeStatusRequest: UpdateEntryAndExitTypeStatusRequest): Call<BaseResponse>
+
+    /**
+     * 出入境费用明细,其它款项list
+     */
+    @POST("/api/Groups/EnterExitCostMobileSubInfo")
+    fun getEntryAndExitOtherPaymentList(@Body entryAndExitPaymentTypeRequest: EntryAndExitPaymentTypeRequest): Call<EntryAndExitOtherPaymentListResponse>
+
+    /**
+     * 出入境费用明细,其它款项删除
+     */
+    @POST("/api/Groups/EnterExitCostMobileOtherFeeDel")
+    fun deleteEntryAndExitOtherPayment(@Body deleteEntryAndExitPaymentItemRequest: DeleteEntryAndExitPaymentItemRequest): Call<BaseResponse>
+
+    /**
+     * 出入境费用详细,其它款项 - 获取基础数据源
+     */
+    @POST("/api/Groups/EnterExitCostMobileOtherItemCurrencyData")
+    fun getEntryAndExitOtherPaymentBaseData(@Body otherPaymentDataSourceRequest: OtherPaymentDataSourceRequest): Call<OtherPaymentDataSourceResponse>
 }

+ 1 - 1
app/src/main/java/com/pan_american/android/ui/customer_resource/related_invitee/RelatedInviteeSearchFragment.kt

@@ -589,7 +589,7 @@ class RelatedInviteeSearchFragment : BaseFragment<FragmentRelatedInviteeSearchBi
                             1 -> {
 
                                 val popView = View.inflate(OASystem.context, R.layout.popup_smart_refresh_selector, null)
-                                popupWindow = PopupWindow(popView, RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)
+                                popupWindow = PopupWindow(popView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
 
                                 showPopupWindow {
                                     val searchView: LinearLayout = popView.findViewById(R.id.search_view)

+ 0 - 4
app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/EntryAndExitDetailActivity.kt

@@ -1,8 +1,6 @@
 package com.pan_american.android.ui.group_management.entry_and_exit_fee_detail
 
 import android.os.Bundle
-import android.util.Log
-import com.google.gson.Gson
 import com.pan_american.android.OASystem
 import com.pan_american.android.R
 import com.pan_american.android.base.BaseActivity
@@ -63,8 +61,6 @@ class EntryAndExitDetailActivity : BaseActivity<ActivityEntryAndExitDetailBindin
 
                 if (detailResponse != null) {
 
-                    Log.e("response", Gson().toJson(detailResponse))
-
                     OASystem.entryAndExitDetailResponse = detailResponse
 
                     initViews()

+ 88 - 69
app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/EntryAndExitFeeTotalFragment.kt

@@ -2,13 +2,18 @@ package com.pan_american.android.ui.group_management.entry_and_exit_fee_detail
 
 import android.os.Bundle
 import android.view.LayoutInflater
+import android.view.View
 import android.view.ViewGroup
 import com.pan_american.android.OASystem
 import com.pan_american.android.R
 import com.pan_american.android.base.BaseFragment
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitDetailResponse
 import com.pan_american.android.data.network.APIService
 import com.pan_american.android.data.network.ServiceCreator
 import com.pan_american.android.databinding.FragmentEntryAndExitFeeTotalBinding
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
 
 class EntryAndExitFeeTotalFragment : BaseFragment<FragmentEntryAndExitFeeTotalBinding>() {
 
@@ -20,8 +25,24 @@ class EntryAndExitFeeTotalFragment : BaseFragment<FragmentEntryAndExitFeeTotalBi
         bundle: Bundle?
     ) = FragmentEntryAndExitFeeTotalBinding.inflate(layoutInflater, container, false)
 
-    override fun onResume() {
-        super.onResume()
+    override fun onStart() {
+        super.onStart()
+
+        if (!EventBus.getDefault().isRegistered(this)) {
+            EventBus.getDefault().register(this)
+        }
+    }
+
+    override fun onStop() {
+        super.onStop()
+
+        if (EventBus.getDefault().isRegistered(this)) {
+            EventBus.getDefault().unregister(this)
+        }
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
 
         initViews()
 
@@ -138,86 +159,79 @@ class EntryAndExitFeeTotalFragment : BaseFragment<FragmentEntryAndExitFeeTotalBi
         }
 
         binding.mealFee.setOnClickListener {
-            binding.accommodationFee.setOnClickListener {
-                val bundle = Bundle().apply {
-                    putInt("groupId", OASystem.entryAndExitDetailResponse.diId)
-                    putInt("type", 4)
-                }
-
-                val paymentListFragment = EntryAndExitPaymentListFragment().apply {
-                    arguments = bundle
-                }
-
-                parentFragmentManager.beginTransaction().setCustomAnimations(
-                    R.anim.slide_right_in,
-                    R.anim.slide_left_out,
-                    R.anim.slide_left_in,
-                    R.anim.slide_right_out
-                ).addToBackStack(null)
-                    .add(R.id.entry_and_exit_detail_container, paymentListFragment).commit()
+            val bundle = Bundle().apply {
+                putInt("groupId", OASystem.entryAndExitDetailResponse.diId)
+                putInt("type", 4)
+            }
+
+            val paymentListFragment = EntryAndExitPaymentListFragment().apply {
+                arguments = bundle
             }
+
+            parentFragmentManager.beginTransaction().setCustomAnimations(
+                R.anim.slide_right_in,
+                R.anim.slide_left_out,
+                R.anim.slide_left_in,
+                R.anim.slide_right_out
+            ).addToBackStack(null)
+                .add(R.id.entry_and_exit_detail_container, paymentListFragment).commit()
         }
 
         binding.publicAndMiscellaneousFee.setOnClickListener {
-            binding.accommodationFee.setOnClickListener {
-                val bundle = Bundle().apply {
-                    putInt("groupId", OASystem.entryAndExitDetailResponse.diId)
-                    putInt("type", 5)
-                }
-
-                val paymentListFragment = EntryAndExitPaymentListFragment().apply {
-                    arguments = bundle
-                }
-
-                parentFragmentManager.beginTransaction().setCustomAnimations(
-                    R.anim.slide_right_in,
-                    R.anim.slide_left_out,
-                    R.anim.slide_left_in,
-                    R.anim.slide_right_out
-                ).addToBackStack(null)
-                    .add(R.id.entry_and_exit_detail_container, paymentListFragment).commit()
+            val bundle = Bundle().apply {
+                putInt("groupId", OASystem.entryAndExitDetailResponse.diId)
+                putInt("type", 5)
+            }
+
+            val paymentListFragment = EntryAndExitPaymentListFragment().apply {
+                arguments = bundle
             }
+
+            parentFragmentManager.beginTransaction().setCustomAnimations(
+                R.anim.slide_right_in,
+                R.anim.slide_left_out,
+                R.anim.slide_left_in,
+                R.anim.slide_right_out
+            ).addToBackStack(null)
+                .add(R.id.entry_and_exit_detail_container, paymentListFragment).commit()
         }
 
         binding.trainingFee.setOnClickListener {
-            binding.accommodationFee.setOnClickListener {
-                val bundle = Bundle().apply {
-                    putInt("groupId", OASystem.entryAndExitDetailResponse.diId)
-                    putInt("type", 6)
-                }
-
-                val paymentListFragment = EntryAndExitPaymentListFragment().apply {
-                    arguments = bundle
-                }
-
-                parentFragmentManager.beginTransaction().setCustomAnimations(
-                    R.anim.slide_right_in,
-                    R.anim.slide_left_out,
-                    R.anim.slide_left_in,
-                    R.anim.slide_right_out
-                ).addToBackStack(null)
-                    .add(R.id.entry_and_exit_detail_container, paymentListFragment).commit()
+            val bundle = Bundle().apply {
+                putInt("groupId", OASystem.entryAndExitDetailResponse.diId)
+                putInt("type", 6)
+            }
+
+            val paymentListFragment = EntryAndExitPaymentListFragment().apply {
+                arguments = bundle
             }
+
+            parentFragmentManager.beginTransaction().setCustomAnimations(
+                R.anim.slide_right_in,
+                R.anim.slide_left_out,
+                R.anim.slide_left_in,
+                R.anim.slide_right_out
+            ).addToBackStack(null)
+                .add(R.id.entry_and_exit_detail_container, paymentListFragment).commit()
         }
 
         binding.otherFee.setOnClickListener {
-            binding.accommodationFee.setOnClickListener {
-                val bundle = Bundle().apply {
-                    putInt("groupId", OASystem.entryAndExitDetailResponse.diId)
-                }
-
-                val otherPaymentFragment = OtherPaymentFragment().apply {
-                    arguments = bundle
-                }
-
-                parentFragmentManager.beginTransaction().setCustomAnimations(
-                    R.anim.slide_right_in,
-                    R.anim.slide_left_out,
-                    R.anim.slide_left_in,
-                    R.anim.slide_right_out
-                ).addToBackStack(null)
-                    .add(R.id.entry_and_exit_detail_container, otherPaymentFragment).commit()
+            val bundle = Bundle().apply {
+                putInt("groupId", OASystem.entryAndExitDetailResponse.diId)
+                putInt("paymentId", OASystem.entryAndExitDetailResponse.id)
+            }
+
+            val otherPaymentFragment = OtherPaymentFragment().apply {
+                arguments = bundle
             }
+
+            parentFragmentManager.beginTransaction().setCustomAnimations(
+                R.anim.slide_right_in,
+                R.anim.slide_left_out,
+                R.anim.slide_left_in,
+                R.anim.slide_right_out
+            ).addToBackStack(null)
+                .add(R.id.entry_and_exit_detail_container, otherPaymentFragment).commit()
         }
 
         binding.exportToCollectionBill.setOnClickListener {
@@ -228,4 +242,9 @@ class EntryAndExitFeeTotalFragment : BaseFragment<FragmentEntryAndExitFeeTotalBi
 
         }
     }
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun updateView(response: EntryAndExitDetailResponse) {
+        initViews()
+    }
 }

+ 490 - 0
app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/EntryAndExitPaymentDetailActivity.kt

@@ -0,0 +1,490 @@
+package com.pan_american.android.ui.group_management.entry_and_exit_fee_detail
+
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.PopupWindow
+import android.widget.TextView
+import androidx.core.content.res.ResourcesCompat
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.pan_american.android.OASystem
+import com.pan_american.android.R
+import com.pan_american.android.base.BaseActivity
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.base.ListAdapter
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.entity.EntryAndExitPaymentPrinciple
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitPaymentPrincipleRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitPaymentPrincipleResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateEntryAndExitPaymentDetailRequest
+import com.pan_american.android.data.network.APIService
+import com.pan_american.android.data.network.ServiceCreator
+import com.pan_american.android.databinding.ActivityEntryAndExitPaymentDetailBinding
+import com.pan_american.android.databinding.LayoutTitleBinding
+import com.pan_american.android.util.MoneyInputFilter
+import com.scwang.smart.refresh.layout.api.RefreshLayout
+import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+
+class EntryAndExitPaymentDetailActivity : BaseActivity<ActivityEntryAndExitPaymentDetailBinding>() {
+
+    private var fromList = false
+
+    private lateinit var titleBinding: LayoutTitleBinding
+
+    private val apiService = ServiceCreator.create<APIService>()
+
+    private val entryAndExitPaymentPrincipleRequest = EntryAndExitPaymentPrincipleRequest()
+
+    private val principleData = ArrayList<EntryAndExitPaymentPrinciple>()
+
+    private var cityId = 0
+
+    private var currencyId = 0
+
+    private var rate = 0.0
+
+    private val regex = Regex("^-?\\d+(\\.\\d{1,2})?\$")
+
+    private val updateEntryAndExitPaymentDetailRequest = UpdateEntryAndExitPaymentDetailRequest()
+
+    override fun getViewBinding() = ActivityEntryAndExitPaymentDetailBinding.inflate(layoutInflater)
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        intent.apply {
+            fromList = getBooleanExtra("fromList", false)
+            updateEntryAndExitPaymentDetailRequest.also {
+                it.diId = getIntExtra("diId", 0)
+                it.feeType = getIntExtra("feeType", 0)
+            }
+        }
+
+        if (fromList) {
+            intent.apply {
+                updateEntryAndExitPaymentDetailRequest.also {
+                    it.subId = getIntExtra("id", 0)
+                    it.days = getIntExtra("days", 0)
+                    it.nationalTravelFeeId = getIntExtra("nationalTravelFeeId", 0)
+
+                    cityId = it.nationalTravelFeeId
+                    binding.city.text = getStringExtra("arae")
+
+                    it.cost = getDoubleExtra("cost", 0.0)
+                    it.currency = getIntExtra("currency", 0)
+
+                    currencyId = it.currency
+
+                    it.subTotal = getDoubleExtra("subTotal", 0.0)
+
+                    for (item in OASystem.entryAndExitDetailResponse.currencys) {
+                        if (item.currencyCode == getStringExtra("currencyName")) {
+                            rate = item.rate
+                            binding.currency.text = String.format(
+                                resources.getString(R.string.currency_name_code_format),
+                                item.currencyName,
+                                item.currencyCode
+                            )
+                        }
+                    }
+                }
+            }
+        }
+
+        initTitle()
+        initViews()
+        initEvents()
+    }
+
+    override fun initTitle() {
+        titleBinding = LayoutTitleBinding.bind(binding.root).apply {
+            titleText.text = if (fromList) {
+                resources.getString(R.string.entry_and_exit_payment_detail)
+            } else {
+                resources.getString(R.string.add_entry_and_exit_payment_detail)
+            }
+
+            backButton.setOnClickListener {
+                back()
+            }
+        }
+    }
+
+    override fun initViews() {
+        if (fromList) {
+            binding.commit.text = resources.getString(R.string.update)
+
+            updateEntryAndExitPaymentDetailRequest.apply {
+                binding.nights.setText(days.toString())
+                binding.paymentPrinciple.setText(cost.toString())
+                binding.totalPayment.text = subTotal.toString()
+            }
+
+        } else {
+            binding.commit.text = resources.getString(R.string.add)
+        }
+
+        binding.paymentPrinciple.filters = arrayOf(MoneyInputFilter(2))
+    }
+
+    override fun initEvents() {
+        binding.city.setOnClickListener {
+            entryAndExitPaymentPrincipleRequest.apply {
+                pageIndex = 1
+            }
+
+            getCityAndPaymentPrincipleData(1)
+        }
+
+        binding.paymentPrinciple.addTextChangedListener(object : TextWatcher {
+            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
+
+            }
+
+            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
+
+            }
+
+            override fun afterTextChanged(s: Editable?) {
+                if (binding.paymentPrinciple.text.toString()
+                        .matches(regex) && binding.paymentPrinciple.text.isNotBlank()
+                ) {
+                    binding.totalPayment.text = String.format(
+                        resources.getString(R.string.decimal_format),
+                        binding.paymentPrinciple.text.toString().toDouble() * rate
+                    )
+                }
+            }
+        })
+
+        binding.commit.setOnClickListener {
+            if (binding.nights.text.isNotBlank()) {
+                updateEntryAndExitPaymentDetailRequest.days = binding.nights.text.toString().toInt()
+            } else {
+                showMessage(resources.getString(R.string.nights_input_hint))
+                return@setOnClickListener
+            }
+
+            if (cityId != 0) {
+                updateEntryAndExitPaymentDetailRequest.nationalTravelFeeId = cityId
+            } else {
+                showMessage(resources.getString(R.string.city_selected_hint))
+                return@setOnClickListener
+            }
+
+            if (binding.paymentPrinciple.text.toString().matches(regex)) {
+                updateEntryAndExitPaymentDetailRequest.cost = binding.paymentPrinciple.text.toString().toDouble()
+            } else {
+                showMessage(resources.getString(R.string.payment_price_hint))
+                return@setOnClickListener
+            }
+
+            updateEntryAndExitPaymentDetailRequest.apply {
+                currency = currencyId
+                subTotal = binding.totalPayment.text.toString().toDouble()
+            }
+
+            updateEntryAndExitPaymentDetail()
+        }
+    }
+
+    private fun getCityAndPaymentPrincipleData(type: Int) {
+        apiService.getEntryAndExitCurrencyCityAndPrinciples(entryAndExitPaymentPrincipleRequest)
+            .enqueue(object :
+                Callback<EntryAndExitPaymentPrincipleResponse> {
+                override fun onResponse(
+                    call: Call<EntryAndExitPaymentPrincipleResponse>,
+                    response: Response<EntryAndExitPaymentPrincipleResponse>
+                ) {
+                    val dataResponse = response.body()
+
+                    if (dataResponse != null) {
+                        if (dataResponse.code == 200) {
+
+                            for (item in dataResponse.data) {
+                                principleData.add(item)
+                            }
+
+                            when (type) {
+                                1 -> {
+
+                                    val popView = View.inflate(
+                                        OASystem.context,
+                                        R.layout.popup_smart_refresh_selector,
+                                        null
+                                    )
+                                    popupWindow = PopupWindow(
+                                        popView,
+                                        ViewGroup.LayoutParams.MATCH_PARENT,
+                                        ViewGroup.LayoutParams.WRAP_CONTENT
+                                    )
+
+                                    showPopupWindow {
+                                        val searchView: LinearLayout =
+                                            popView.findViewById(R.id.search_view)
+                                        searchView.visibility = View.VISIBLE
+
+                                        val searchText: EditText =
+                                            popView.findViewById(R.id.search_text)
+
+                                        selector = popView.findViewById(R.id.selector_list)
+
+                                        selectorContainer =
+                                            popView.findViewById(R.id.selector_refresh_container)
+                                        selectorContainer.setEnableRefresh(true)
+                                        selectorContainer.setEnableLoadMore(true)
+
+                                        val layoutManager = LinearLayoutManager(OASystem.context)
+                                        selector.layoutManager = layoutManager
+
+                                        val adapter =
+                                            ListAdapter.Builder<EntryAndExitPaymentPrinciple>()
+                                                .apply {
+                                                    setData(principleData)
+                                                    setLayoutId(R.layout.item_selector)
+                                                    addBindView { itemView, data ->
+                                                        itemView.findViewById<TextView>(R.id.selector_item_name)
+                                                            .apply {
+                                                                text = data.area
+
+                                                                if (cityId == data.id) {
+                                                                    setTextColor(
+                                                                        ResourcesCompat.getColor(
+                                                                            resources,
+                                                                            R.color.text_color_blue,
+                                                                            null
+                                                                        )
+                                                                    )
+                                                                } else {
+                                                                    setTextColor(
+                                                                        ResourcesCompat.getColor(
+                                                                            resources,
+                                                                            R.color.text_color,
+                                                                            null
+                                                                        )
+                                                                    )
+                                                                }
+                                                            }
+                                                    }
+                                                }.create()
+
+                                        selector.adapter = adapter
+
+                                        adapter.onRecyclerViewItemClick =
+                                            object :
+                                                ListAdapter.OnRecyclerViewItemClick<EntryAndExitPaymentPrinciple> {
+                                                override fun onItemClick(position: Int) {
+                                                    principleData[position].apply {
+                                                        binding.city.text = area
+
+                                                        cityId = id
+
+                                                        currencyId = currency
+
+                                                        binding.currency.text = String.format(
+                                                            resources.getString(R.string.currency_name_code_format),
+                                                            currencyName,
+                                                            currencyCode
+                                                        )
+
+                                                        var paymentPrinciple = 0.0
+
+                                                        when (type) {
+                                                            3 -> {
+                                                                binding.paymentPrinciple.setText(
+                                                                    roomCost.toString()
+                                                                )
+
+                                                                paymentPrinciple = roomCost
+                                                            }
+
+                                                            4 -> {
+                                                                binding.paymentPrinciple.setText(
+                                                                    foodCost.toString()
+                                                                )
+
+                                                                paymentPrinciple = foodCost
+                                                            }
+
+                                                            5 -> {
+                                                                binding.paymentPrinciple.setText(
+                                                                    publicCost.toString()
+                                                                )
+
+                                                                paymentPrinciple = publicCost
+                                                            }
+                                                        }
+
+                                                        for (item in OASystem.entryAndExitDetailResponse.currencys) {
+                                                            if (item.currencyCode == currencyCode) {
+                                                                rate = item.rate
+                                                                binding.totalPayment.text =
+                                                                    String.format(
+                                                                        resources.getString(R.string.decimal_format),
+                                                                        paymentPrinciple * rate
+                                                                    )
+                                                            }
+                                                        }
+                                                    }
+
+                                                    popupWindow.dismiss()
+                                                }
+                                            }
+
+                                        selectorContainer.setOnRefreshLoadMoreListener(object :
+                                            OnRefreshLoadMoreListener {
+                                            override fun onRefresh(p0: RefreshLayout) {
+                                                entryAndExitPaymentPrincipleRequest.pageIndex = 1
+
+                                                selector.adapter!!.notifyItemRangeRemoved(
+                                                    0,
+                                                    principleData.size
+                                                )
+
+                                                principleData.clear()
+
+                                                getCityAndPaymentPrincipleData(2)
+                                            }
+
+                                            override fun onLoadMore(p0: RefreshLayout) {
+                                                entryAndExitPaymentPrincipleRequest.pageIndex += 1
+
+                                                getCityAndPaymentPrincipleData(3)
+                                            }
+                                        })
+
+                                        searchText.addTextChangedListener(object : TextWatcher {
+                                            override fun beforeTextChanged(
+                                                p0: CharSequence?,
+                                                p1: Int,
+                                                p2: Int,
+                                                p3: Int
+                                            ) {
+
+                                            }
+
+                                            override fun onTextChanged(
+                                                p0: CharSequence?,
+                                                p1: Int,
+                                                p2: Int,
+                                                p3: Int
+                                            ) {
+
+                                            }
+
+                                            override fun afterTextChanged(editable: Editable?) {
+
+                                                adapter.notifyItemRangeRemoved(
+                                                    0,
+                                                    principleData.size
+                                                )
+
+                                                principleData.clear()
+
+                                                entryAndExitPaymentPrincipleRequest.apply {
+                                                    pageIndex = 1
+                                                    search = editable.toString()
+                                                }
+
+                                                getCityAndPaymentPrincipleData(2)
+                                            }
+                                        })
+
+                                        popupWindow.showAtLocation(
+                                            binding.root,
+                                            Gravity.BOTTOM,
+                                            0,
+                                            0
+                                        )
+                                    }
+
+                                    selectorContainer.setEnableLoadMore(
+                                        entryAndExitPaymentPrincipleRequest.pageIndex < getTotalPage(
+                                            dataResponse.count
+                                        )
+                                    )
+                                    selector.adapter!!.notifyItemInserted(0)
+                                }
+
+                                2 -> {
+                                    selectorContainer.finishRefresh()
+                                    selectorContainer.setEnableLoadMore(
+                                        entryAndExitPaymentPrincipleRequest.pageIndex < getTotalPage(
+                                            dataResponse.count
+                                        )
+                                    )
+                                    selector.adapter!!.notifyItemInserted(0)
+                                }
+
+                                3 -> {
+                                    selectorContainer.finishLoadMore()
+                                    selectorContainer.setEnableLoadMore(
+                                        entryAndExitPaymentPrincipleRequest.pageIndex < getTotalPage(
+                                            dataResponse.count
+                                        )
+                                    )
+                                    selector.adapter!!.notifyItemInserted(principleData.size)
+                                }
+                            }
+
+                        } else {
+                            showMessage(dataResponse.msg)
+                        }
+                    }
+                }
+
+                override fun onFailure(
+                    p0: Call<EntryAndExitPaymentPrincipleResponse>,
+                    p1: Throwable
+                ) {
+                    showErrorInfo(R.string.base_resource_data_get_failed)
+                }
+            })
+    }
+
+    private fun getTotalPage(count: Int): Int {
+        var pageCount = count / 10
+
+        if (count % 10 > 0) {
+            pageCount += 1
+        }
+
+        return pageCount
+    }
+
+    private fun updateEntryAndExitPaymentDetail() {
+
+        apiService.updateEntryAndExitPaymentDetail(updateEntryAndExitPaymentDetailRequest).enqueue(object : Callback<BaseResponse> {
+            override fun onResponse(call: Call<BaseResponse>, response: Response<BaseResponse>) {
+
+                val updateResponse = response.body()
+
+                if (updateResponse != null) {
+                    if (updateResponse.code == 200) {
+
+                        showMessage(resources.getString(R.string.update_success))
+
+                        OASystem.needRefresh = true
+
+                        finish()
+
+                    } else {
+                        showMessage(updateResponse.msg)
+                    }
+                }
+
+            }
+
+            override fun onFailure(p0: Call<BaseResponse>, p1: Throwable) {
+                showErrorInfo(R.string.update_error)
+            }
+        })
+    }
+}

+ 464 - 0
app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/EntryAndExitPaymentListFragment.kt

@@ -1,15 +1,479 @@
 package com.pan_american.android.ui.group_management.entry_and_exit_fee_detail
 
+import android.content.Intent
 import android.os.Bundle
+import android.view.Gravity
 import android.view.LayoutInflater
+import android.view.View
 import android.view.ViewGroup
+import android.widget.EditText
+import android.widget.PopupWindow
+import android.widget.TextView
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.pan_american.android.OASystem
+import com.pan_american.android.R
 import com.pan_american.android.base.BaseFragment
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.base.CardAdapter
+import com.pan_american.android.base.CustomAlertDialog
+import com.pan_american.android.data.model.common.entity.Selector
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.entity.EntryAndExitPaymentListItem
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.DeleteEntryAndExitPaymentItemRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitPaymentListResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitPaymentTypeRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateEntryAndExitCurrencyRateRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateEntryAndExitTypeStatusRequest
+import com.pan_american.android.data.network.APIService
+import com.pan_american.android.data.network.ServiceCreator
 import com.pan_american.android.databinding.FragmentEntryAndExitPaymentListBinding
+import com.pan_american.android.util.MoneyInputFilter
+import org.greenrobot.eventbus.EventBus
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
 
 class EntryAndExitPaymentListFragment : BaseFragment<FragmentEntryAndExitPaymentListBinding>() {
+
+    private var typeId = 0
+
+    private var groupId = 0
+
+    private var paymentId = 0
+
+    private val apiService = ServiceCreator.create<APIService>()
+
+    private val paymentList = ArrayList<EntryAndExitPaymentListItem>()
+
+    private var totalPayment = 0.0
+
     override fun getViewBinding(
         inflater: LayoutInflater,
         container: ViewGroup?,
         bundle: Bundle?
     ) = FragmentEntryAndExitPaymentListBinding.inflate(inflater, container, false)
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        requireArguments().apply {
+            typeId = getInt("type")
+            groupId = getInt("groupId")
+        }
+
+        initViews()
+
+        initEvents()
+
+        getPaymentList()
+    }
+
+    override fun onResume() {
+        super.onResume()
+
+        if (OASystem.needRefresh) {
+
+            binding.paymentList.adapter!!.notifyItemRangeRemoved(0, paymentList.size)
+            paymentList.clear()
+            getPaymentList()
+
+            OASystem.needRefresh = false
+        }
+    }
+
+    private fun getPaymentList() {
+        apiService.getEntryAndExitPaymentList(
+            EntryAndExitPaymentTypeRequest(
+                diId = groupId,
+                subType = typeId
+            )
+        ).enqueue(object : Callback<EntryAndExitPaymentListResponse> {
+            override fun onResponse(
+                call: Call<EntryAndExitPaymentListResponse>,
+                response: Response<EntryAndExitPaymentListResponse>
+            ) {
+                val listResponse = response.body()
+
+                if (listResponse != null) {
+                    if (listResponse.code == 200) {
+
+                        listResponse.data.apply {
+                            paymentId = parentId
+                            totalPayment = totalCost
+                            binding.isSelected.isChecked = choice == 1
+                            binding.paymentTotal.text = String.format(
+                                resources.getString(R.string.total_per_fee_format),
+                                totalPayment
+                            )
+                            for (item in details) {
+                                paymentList.add(item)
+                            }
+                        }
+
+                        changeTotalPayment()
+
+                        initList()
+
+                    } else {
+                        showMessage(listResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<EntryAndExitPaymentListResponse>, p1: Throwable) {
+                showErrorInfo(R.string.entry_and_exit_payment_list_get_error)
+            }
+        })
+    }
+
+    override fun initViews() {
+        when (typeId) {
+            3 -> {
+                binding.title.text = resources.getString(R.string.accommodation_fee)
+            }
+
+            4 -> {
+                binding.title.text = resources.getString(R.string.meal_expenses)
+            }
+
+            5 -> {
+                binding.title.text = resources.getString(R.string.public_and_miscellaneous_expenses)
+            }
+
+            6 -> {
+                binding.title.text = resources.getString(R.string.training_fee)
+            }
+        }
+    }
+
+    override fun initEvents() {
+        binding.isSelected.setOnClickListener {
+            if (binding.isSelected.isChecked) {
+                updateSelectStatus(1)
+            } else {
+                updateSelectStatus(0)
+            }
+        }
+
+        binding.currency.setOnClickListener {
+            showCurrencyPopupView()
+        }
+
+        binding.addPayment.setOnClickListener {
+            val intent =
+                Intent(OASystem.context, EntryAndExitPaymentDetailActivity::class.java).apply {
+                    putExtra("fromList", false)
+                    putExtra("diId", groupId)
+                    putExtra("feeType", typeId)
+                }
+
+            startActivity(intent)
+        }
+    }
+
+    private fun initList() {
+        val layoutManager = LinearLayoutManager(OASystem.context)
+        binding.paymentList.layoutManager = layoutManager
+
+        val adapter = CardAdapter.Builder<EntryAndExitPaymentListItem>().apply {
+            setData(paymentList)
+            setCanDelete(true)
+            setLayoutId(R.layout.item_entry_and_exit_payment)
+            addBindView { itemView, data ->
+                itemView.findViewById<TextView>(R.id.days).text =
+                    String.format(resources.getString(R.string.nights_format), data.days)
+                itemView.findViewById<TextView>(R.id.city).text = data.arae
+                itemView.findViewById<TextView>(R.id.payment_principle).text = data.cost.toString()
+                itemView.findViewById<TextView>(R.id.currency).text = data.currencyName
+                itemView.findViewById<TextView>(R.id.total_payment).text = data.subTotal.toString()
+            }
+        }.create()
+
+        binding.paymentList.adapter = adapter
+
+        adapter.onRecyclerViewItemClick =
+            object : CardAdapter.OnRecyclerViewItemClick<EntryAndExitPaymentListItem> {
+                override fun onItemClick(position: Int) {
+
+                    val item = paymentList[position]
+
+                    val intent = Intent(
+                        OASystem.context,
+                        EntryAndExitPaymentDetailActivity::class.java
+                    ).apply {
+                        putExtra("fromList", true)
+                        putExtra("id", item.subId)
+                        putExtra("days", item.days)
+                        putExtra("nationalTravelFeeId", item.nationalTravelFeeId)
+                        putExtra("arae", item.arae)
+                        putExtra("cost", item.cost)
+                        putExtra("currency", item.currency)
+                        putExtra("currencyName", item.currencyName)
+                        putExtra("subTotal", item.subTotal)
+                        putExtra("diId", groupId)
+                        putExtra("feeType", typeId)
+                    }
+
+                    startActivity(intent)
+                }
+
+                override fun onItemDelete(position: Int) {
+                    CustomAlertDialog.Builder(OASystem.context).apply {
+                        setTitle(resources.getString(R.string.alert))
+                        setMessage(
+                            String.format(
+                                resources.getString(R.string.entry_and_exit_delete_hint),
+                                paymentList[position].days
+                            )
+                        )
+                        setNegativeButtonAndListener(resources.getString(R.string.cancel)) { dialog, _ ->
+                            dialog.dismiss()
+                        }
+                        setPositiveButtonAndListener(resources.getString(R.string.confirm)) { dialog, _ ->
+                            deletePaymentItem(position)
+                            dialog.dismiss()
+                        }
+                    }.show()
+                }
+            }
+    }
+
+    private fun deletePaymentItem(position: Int) {
+        apiService.deleteEntryAndExitPaymentItem(DeleteEntryAndExitPaymentItemRequest(id = paymentList[position].subId))
+            .enqueue(object : Callback<BaseResponse> {
+                override fun onResponse(
+                    call: Call<BaseResponse>,
+                    response: Response<BaseResponse>
+                ) {
+
+                    val deleteResponse = response.body()
+
+                    if (deleteResponse != null) {
+                        if (deleteResponse.code == 200) {
+
+                            totalPayment -= paymentList[position].subTotal
+
+                            paymentList.removeAt(position)
+                            binding.paymentList.adapter!!.notifyItemRemoved(position)
+                            binding.paymentList.adapter!!.notifyItemRangeChanged(
+                                position,
+                                paymentList.size - position
+                            )
+
+                            binding.paymentTotal.text = String.format(
+                                resources.getString(R.string.total_per_fee_format),
+                                totalPayment
+                            )
+
+                            changeTotalPayment()
+
+                            showMessage(resources.getString(R.string.delete_success))
+
+                        } else {
+                            showMessage(deleteResponse.msg)
+                        }
+                    }
+                }
+
+                override fun onFailure(p0: Call<BaseResponse>, p1: Throwable) {
+                    showErrorInfo(R.string.delete_error)
+                }
+            })
+    }
+
+    private fun updateCurrency(currencyList: ArrayList<Selector>) {
+        apiService.updateEntryAndExitCurrencyRate(
+            UpdateEntryAndExitCurrencyRateRequest(
+                id = paymentId,
+                diId = groupId,
+                currencys = currencyList
+            )
+        ).enqueue(object : Callback<BaseResponse> {
+            override fun onResponse(call: Call<BaseResponse>, response: Response<BaseResponse>) {
+                val updateResponse = response.body()
+
+                if (updateResponse != null) {
+                    if (updateResponse.code == 200) {
+                        showMessage(resources.getString(R.string.update_success))
+
+                        binding.paymentList.adapter!!.notifyItemRangeRemoved(0, paymentList.size)
+                        paymentList.clear()
+                        getPaymentList()
+                        popupWindow.dismiss()
+
+                    } else {
+                        showMessage(updateResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<BaseResponse>, p1: Throwable) {
+                showErrorInfo(R.string.update_error)
+            }
+        })
+    }
+
+    private fun changeTotalPayment() {
+        when (typeId) {
+            3 -> {
+                OASystem.entryAndExitDetailResponse.choiceThreeTotalCost = totalPayment
+            }
+
+            4 -> {
+                OASystem.entryAndExitDetailResponse.choiceFourTotalCost = totalPayment
+            }
+
+            5 -> {
+                OASystem.entryAndExitDetailResponse.choiceFiveTotalCost = totalPayment
+            }
+
+            6 -> {
+                OASystem.entryAndExitDetailResponse.choiceSixTotalCost = totalPayment
+            }
+        }
+
+        EventBus.getDefault().post(OASystem.entryAndExitDetailResponse)
+    }
+
+    private fun showCurrencyPopupView() {
+        val popView =
+            View.inflate(OASystem.context, R.layout.popup_currency_detail, null)
+        popupWindow = PopupWindow(
+            popView,
+            ViewGroup.LayoutParams.WRAP_CONTENT,
+            ViewGroup.LayoutParams.WRAP_CONTENT
+        )
+
+        showPopupWindow {
+            val usdCurrency: EditText = popView.findViewById(R.id.usd_currency)
+            val eurCurrency: EditText = popView.findViewById(R.id.eur_currency)
+            val gbpCurrency: EditText = popView.findViewById(R.id.gbp_currency)
+            val jpyCurrency: EditText = popView.findViewById(R.id.jpy_currency)
+            val hkdCurrency: EditText = popView.findViewById(R.id.hkd_currency)
+            val cancel: TextView = popView.findViewById(R.id.cancel)
+            val commit: TextView = popView.findViewById(R.id.commit)
+
+            usdCurrency.filters = arrayOf(MoneyInputFilter(4))
+            eurCurrency.filters = arrayOf(MoneyInputFilter(4))
+            gbpCurrency.filters = arrayOf(MoneyInputFilter(4))
+            jpyCurrency.filters = arrayOf(MoneyInputFilter(4))
+            hkdCurrency.filters = arrayOf(MoneyInputFilter(4))
+
+            for (item in OASystem.entryAndExitDetailResponse.currencys) {
+                when (item.currencyCode) {
+                    "USD" -> usdCurrency.setText(item.rate.toString())
+
+                    "EUR" -> eurCurrency.setText(item.rate.toString())
+
+                    "GBP" -> gbpCurrency.setText(item.rate.toString())
+
+                    "JPY" -> jpyCurrency.setText(item.rate.toString())
+
+                    "HKD" -> hkdCurrency.setText(item.rate.toString())
+                }
+            }
+
+            cancel.setOnClickListener {
+                popupWindow.dismiss()
+            }
+
+            commit.setOnClickListener {
+                if (usdCurrency.text.toString().endsWith('.') || usdCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.usd_currency_input_hint))
+                    return@setOnClickListener
+                }
+                if (eurCurrency.text.toString().endsWith('.') || eurCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.eur_currency_input_hint))
+                    return@setOnClickListener
+                }
+                if (gbpCurrency.text.toString().endsWith('.') || gbpCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.gbp_currency_input_hint))
+                    return@setOnClickListener
+                }
+                if (jpyCurrency.text.toString().endsWith('.') || jpyCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.jpy_currency_input_hint))
+                    return@setOnClickListener
+                }
+                if (hkdCurrency.text.toString().endsWith('.') || hkdCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.hkd_currency_input_hint))
+                    return@setOnClickListener
+                }
+
+                for (item in OASystem.entryAndExitDetailResponse.currencys) {
+                    when (item.currencyCode) {
+                        "USD" -> item.rate = usdCurrency.text.toString().toDouble()
+
+                        "EUR" -> item.rate = eurCurrency.text.toString().toDouble()
+
+                        "GBP" -> item.rate = gbpCurrency.text.toString().toDouble()
+
+                        "JPY" -> item.rate = jpyCurrency.text.toString().toDouble()
+
+                        "HKD" -> item.rate = hkdCurrency.text.toString().toDouble()
+                    }
+                }
+
+                updateCurrency(OASystem.entryAndExitDetailResponse.currencys)
+            }
+
+            popupWindow.showAtLocation(binding.root, Gravity.CENTER, 0, 0)
+        }
+    }
+
+    private fun updateSelectStatus(status: Int) {
+        apiService.updateEntryAndExitTypeStatus(
+            UpdateEntryAndExitTypeStatusRequest(
+                id = paymentId,
+                diId = groupId,
+                itemType = typeId,
+                isSelected = status
+            )
+        ).enqueue(object : Callback<BaseResponse> {
+            override fun onResponse(call: Call<BaseResponse>, response: Response<BaseResponse>) {
+                val updateResponse = response.body()
+
+                if (updateResponse != null) {
+                    if (updateResponse.code == 200) {
+                        showMessage(resources.getString(R.string.update_success))
+
+                        when(typeId) {
+                            3 -> {
+                                OASystem.entryAndExitDetailResponse.choiceThree = status
+                            }
+
+                            4 -> {
+                                OASystem.entryAndExitDetailResponse.choiceFour = status
+                            }
+
+                            5 -> {
+                                OASystem.entryAndExitDetailResponse.choiceFive = status
+                            }
+
+                            6 -> {
+                                OASystem.entryAndExitDetailResponse.choiceSix = status
+                            }
+                        }
+
+                        EventBus.getDefault().post(OASystem.entryAndExitDetailResponse)
+
+                    } else {
+                        showMessage(updateResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<BaseResponse>, p1: Throwable) {
+                showErrorInfo(R.string.interface_request_error)
+            }
+        })
+    }
 }

+ 21 - 12
app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/InBoardFeeFragment.kt

@@ -65,18 +65,27 @@ class InBoardFeeFragment : BaseFragment<FragmentInBoardFeeBinding>() {
                 response: Response<InBoardDetailResponse>
             ) {
 
-                response.body()?.apply {
-
-                    paymentId = id
-
-                    binding.isSelected.isChecked = choiceOne == 1
-                    binding.visaPrice.setText(visa.toString())
-                    binding.visaDescription.setText(visaRemark)
-                    binding.vaccinePrice.setText(yiMiao.toString())
-                    binding.nucleicAcidTestingPrice.setText(heSuan.toString())
-                    binding.servicePrice.setText(service.toString())
-                    binding.insurancePrice.setText(safe.toString())
-                    binding.ticketPrice.setText(ticket.toString())
+                val detailResponse = response.body()
+
+                if (detailResponse != null) {
+                    if (detailResponse.code == 200) {
+
+                        detailResponse.data.apply {
+                            paymentId = id
+
+                            binding.isSelected.isChecked = choiceOne == 1
+                            binding.visaPrice.setText(visa.toString())
+                            binding.visaDescription.setText(visaRemark)
+                            binding.vaccinePrice.setText(yiMiao.toString())
+                            binding.nucleicAcidTestingPrice.setText(heSuan.toString())
+                            binding.servicePrice.setText(service.toString())
+                            binding.insurancePrice.setText(safe.toString())
+                            binding.ticketPrice.setText(ticket.toString())
+                        }
+
+                    } else {
+                        showMessage(detailResponse.msg)
+                    }
                 }
             }
 

+ 0 - 4
app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/InternationalTravelFeeFragment.kt

@@ -1,11 +1,9 @@
 package com.pan_american.android.ui.group_management.entry_and_exit_fee_detail
 
 import android.os.Bundle
-import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import com.google.gson.Gson
 import com.pan_american.android.OASystem
 import com.pan_american.android.R
 import com.pan_american.android.base.BaseFragment
@@ -215,8 +213,6 @@ class InternationalTravelFeeFragment : BaseFragment<FragmentInternationalTravelF
 
     private fun updateInternationalTravel(updateInternationalTravelRequest: UpdateInternationalTravelRequest) {
 
-        Log.e("request", Gson().toJson(updateInternationalTravelRequest))
-
         apiService.updateInternationalTravelPayment(updateInternationalTravelRequest)
             .enqueue(object : Callback<UpdateInternationalTravelResponse> {
                 override fun onResponse(

+ 329 - 0
app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/OtherPaymentDetailActivity.kt

@@ -0,0 +1,329 @@
+package com.pan_american.android.ui.group_management.entry_and_exit_fee_detail
+
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.widget.TextView
+import androidx.core.content.res.ResourcesCompat
+import com.pan_american.android.OASystem
+import com.pan_american.android.R
+import com.pan_american.android.base.BaseActivity
+import com.pan_american.android.base.ListAdapter
+import com.pan_american.android.data.model.common.entity.Selector
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.OtherPaymentDataSourceRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.OtherPaymentDataSourceResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateOtherPaymentRequest
+import com.pan_american.android.data.network.APIService
+import com.pan_american.android.data.network.ServiceCreator
+import com.pan_american.android.databinding.ActivityOtherPaymentDetailBinding
+import com.pan_american.android.databinding.LayoutTitleBinding
+import com.pan_american.android.util.MoneyInputFilter
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+
+class OtherPaymentDetailActivity : BaseActivity<ActivityOtherPaymentDetailBinding>() {
+
+    private var fromList = false
+
+    private var groupId = 0
+
+    private lateinit var titleBinding: LayoutTitleBinding
+
+    private val apiService = ServiceCreator.create<APIService>()
+
+    private val rateList = ArrayList<Selector>()
+
+    private val paymentTypeList = ArrayList<Selector>()
+
+    private var currencyRate = 0.0
+
+    private val updateOtherPaymentRequest = UpdateOtherPaymentRequest()
+
+    private val regex = Regex("^-?\\d+(\\.\\d{1,2})?\$")
+
+    override fun getViewBinding() = ActivityOtherPaymentDetailBinding.inflate(layoutInflater)
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        intent.apply {
+            fromList = getBooleanExtra("fromList", false)
+            updateOtherPaymentRequest.diid = getIntExtra("diId", 0)
+            updateOtherPaymentRequest.index = getIntExtra("index", 0)
+
+            groupId = updateOtherPaymentRequest.diid
+
+            binding.index.text = updateOtherPaymentRequest.index.toString()
+        }
+
+        if (fromList) {
+            intent.apply {
+                updateOtherPaymentRequest.subId = getIntExtra("subId", 0)
+                updateOtherPaymentRequest.setDataId = getIntExtra("setDataId", 0)
+
+                binding.paymentType.text = getStringExtra("setDataName")
+
+                updateOtherPaymentRequest.cost = getDoubleExtra("cost", 0.0)
+                updateOtherPaymentRequest.currency = getIntExtra("currency", 0)
+
+                binding.currency.text = getStringExtra("currencyName")
+
+                updateOtherPaymentRequest.subTotal = getDoubleExtra("subTotal", 0.0)
+                updateOtherPaymentRequest.remark = getStringExtra("remark").toString()
+            }
+        }
+
+        initTitle()
+
+        getOtherPaymentBaseData()
+
+        initViews()
+    }
+
+    override fun initTitle() {
+        titleBinding = LayoutTitleBinding.bind(binding.root).apply {
+            titleText.text = if (fromList) {
+                resources.getString(R.string.entry_and_exit_payment_detail)
+            } else {
+                resources.getString(R.string.add_entry_and_exit_payment_detail)
+            }
+
+            backButton.setOnClickListener {
+                back()
+            }
+        }
+    }
+
+    override fun initViews() {
+        if (fromList) {
+            binding.commit.text = resources.getString(R.string.update)
+        } else {
+            binding.commit.text = resources.getString(R.string.add)
+        }
+
+        binding.paymentPrinciple.filters = arrayOf(MoneyInputFilter(2))
+
+        updateOtherPaymentRequest.apply {
+            binding.paymentPrinciple.setText(cost.toString())
+            binding.totalPayment.text = subTotal.toString()
+            binding.remark.setText(remark)
+        }
+
+    }
+
+    override fun initEvents() {
+        binding.paymentType.setOnClickListener {
+
+            showSelector {
+                val adapter = ListAdapter.Builder<Selector>().apply {
+                    setData(paymentTypeList)
+                    setLayoutId(R.layout.item_selector)
+                    addBindView { itemView, data ->
+                        itemView.findViewById<TextView>(R.id.selector_item_name).apply {
+                            if (updateOtherPaymentRequest.setDataId == data.id) {
+                                setTextColor(
+                                    ResourcesCompat.getColor(
+                                        resources,
+                                        R.color.text_color_blue,
+                                        null
+                                    )
+                                )
+                            } else {
+                                setTextColor(
+                                    ResourcesCompat.getColor(
+                                        resources,
+                                        R.color.text_color,
+                                        null
+                                    )
+                                )
+                            }
+
+                            text = data.name
+                        }
+                    }
+                }.create()
+
+                selector.adapter = adapter
+
+                adapter.onRecyclerViewItemClick = object : ListAdapter.OnRecyclerViewItemClick<Selector> {
+                    override fun onItemClick(position: Int) {
+                        paymentTypeList[position].apply {
+                            binding.paymentType.text = name
+                            updateOtherPaymentRequest.setDataId = id
+
+                            popupWindow.dismiss()
+                        }
+                    }
+                }
+            }
+        }
+
+        binding.paymentPrinciple.addTextChangedListener(object : TextWatcher {
+            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
+
+            }
+
+            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
+
+            }
+
+            override fun afterTextChanged(s: Editable?) {
+                if (binding.paymentPrinciple.text.toString()
+                        .matches(regex) && binding.paymentPrinciple.text.isNotBlank()
+                ) {
+                    binding.totalPayment.text = String.format(
+                        resources.getString(R.string.decimal_format),
+                        binding.paymentPrinciple.text.toString().toDouble() * currencyRate
+                    )
+                }
+            }
+        })
+
+        binding.currency.setOnClickListener {
+            showSelector {
+                val adapter = ListAdapter.Builder<Selector>().apply {
+                    setData(rateList)
+                    setLayoutId(R.layout.item_selector)
+                    addBindView { itemView, data ->
+                        itemView.findViewById<TextView>(R.id.selector_item_name).apply {
+                            if (updateOtherPaymentRequest.currency == data.currencyId) {
+                                setTextColor(
+                                    ResourcesCompat.getColor(
+                                        resources,
+                                        R.color.text_color_blue,
+                                        null
+                                    )
+                                )
+                            } else {
+                                setTextColor(
+                                    ResourcesCompat.getColor(
+                                        resources,
+                                        R.color.text_color,
+                                        null
+                                    )
+                                )
+                            }
+
+                            text = data.currencyName
+                        }
+                    }
+                }.create()
+
+                selector.adapter = adapter
+
+                adapter.onRecyclerViewItemClick = object : ListAdapter.OnRecyclerViewItemClick<Selector> {
+                    override fun onItemClick(position: Int) {
+                        rateList[position].apply {
+                            binding.currency.text = currencyCode
+                            updateOtherPaymentRequest.currency = currencyId
+                            currencyRate = rate
+
+                            binding.totalPayment.text = String.format(
+                                resources.getString(R.string.decimal_format),
+                                binding.paymentPrinciple.text.toString().toDouble() * currencyRate
+                            )
+
+                            popupWindow.dismiss()
+                        }
+                    }
+                }
+            }
+        }
+
+        binding.commit.setOnClickListener {
+
+        }
+    }
+
+    private fun getOtherPaymentBaseData() {
+        apiService.getEntryAndExitOtherPaymentBaseData(OtherPaymentDataSourceRequest(diId = groupId))
+            .enqueue(object : Callback<OtherPaymentDataSourceResponse> {
+                override fun onResponse(
+                    call: Call<OtherPaymentDataSourceResponse>,
+                    response: Response<OtherPaymentDataSourceResponse>
+                ) {
+                    val dataResponse = response.body()
+
+                    if (dataResponse != null) {
+                        if (dataResponse.code == 200) {
+
+                            dataResponse.data.apply {
+                                for (item in groupOtherRateData) {
+                                    when(item.currencyCode) {
+                                        "USD" -> {
+                                            for (currency in OASystem.entryAndExitDetailResponse.currencys) {
+                                                if (item.currencyCode == currency.currencyCode) {
+                                                    item.rate = currency.rate
+                                                }
+                                            }
+                                        }
+
+                                        "EUR" -> {
+                                            for (currency in OASystem.entryAndExitDetailResponse.currencys) {
+                                                if (item.currencyCode == currency.currencyCode) {
+                                                    item.rate = currency.rate
+                                                }
+                                            }
+                                        }
+
+                                        "GBP" -> {
+                                            for (currency in OASystem.entryAndExitDetailResponse.currencys) {
+                                                if (item.currencyCode == currency.currencyCode) {
+                                                    item.rate = currency.rate
+                                                }
+                                            }
+                                        }
+
+                                        "JPY" -> {
+                                            for (currency in OASystem.entryAndExitDetailResponse.currencys) {
+                                                if (item.currencyCode == currency.currencyCode) {
+                                                    item.rate = currency.rate
+                                                }
+                                            }
+                                        }
+
+                                        "HKD" -> {
+                                            for (currency in OASystem.entryAndExitDetailResponse.currencys) {
+                                                if (item.currencyCode == currency.currencyCode) {
+                                                    item.rate = currency.rate
+                                                }
+                                            }
+                                        }
+
+                                        else -> {
+                                            rateList.add(item)
+                                        }
+                                    }
+                                }
+
+                                for (item in otherFeeTypeData) {
+                                    paymentTypeList.add(item)
+                                }
+
+                                for (item in rateList) {
+                                    if (item.currencyId == updateOtherPaymentRequest.currency) {
+                                        currencyRate = item.rate
+                                        binding.currency.text = String.format(
+                                            resources.getString(R.string.currency_name_code_format),
+                                            item.currencyName,
+                                            item.currencyCode
+                                        )
+                                    }
+                                }
+
+                                initEvents()
+                            }
+
+                        } else {
+                            showMessage(dataResponse.msg)
+                        }
+                    }
+                }
+
+                override fun onFailure(p0: Call<OtherPaymentDataSourceResponse>, p1: Throwable) {
+                    showErrorInfo(R.string.other_payment_base_data_get_error)
+                }
+            })
+    }
+}

+ 430 - 0
app/src/main/java/com/pan_american/android/ui/group_management/entry_and_exit_fee_detail/OtherPaymentFragment.kt

@@ -1,16 +1,446 @@
 package com.pan_american.android.ui.group_management.entry_and_exit_fee_detail
 
+import android.content.Intent
 import android.os.Bundle
+import android.util.Log
+import android.view.Gravity
 import android.view.LayoutInflater
+import android.view.View
 import android.view.ViewGroup
+import android.widget.EditText
+import android.widget.PopupWindow
+import android.widget.TextView
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.google.gson.Gson
+import com.pan_american.android.OASystem
+import com.pan_american.android.R
 import com.pan_american.android.base.BaseFragment
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.base.CardAdapter
+import com.pan_american.android.base.CustomAlertDialog
+import com.pan_american.android.data.model.common.entity.Selector
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.entity.EntryAndExitOtherPayment
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.DeleteEntryAndExitPaymentItemRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitOtherPaymentListResponse
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.EntryAndExitPaymentTypeRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateEntryAndExitCurrencyRateRequest
+import com.pan_american.android.data.model.group_management.entry_and_exit_fee_detail.network.UpdateEntryAndExitTypeStatusRequest
+import com.pan_american.android.data.network.APIService
+import com.pan_american.android.data.network.ServiceCreator
 import com.pan_american.android.databinding.FragmentOtherPaymentBinding
+import com.pan_american.android.util.MoneyInputFilter
+import com.pan_american.android.util.ScrollEditText
+import org.greenrobot.eventbus.EventBus
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
 
 
 class OtherPaymentFragment : BaseFragment<FragmentOtherPaymentBinding>() {
+
+    private var groupId = 0
+
+    private var paymentId = 0
+
+    private var paymentList = ArrayList<EntryAndExitOtherPayment>()
+
+    private var apiService = ServiceCreator.create<APIService>()
+
+    private var totalPayment = 0.0
+
     override fun getViewBinding(
         inflater: LayoutInflater,
         container: ViewGroup?,
         bundle: Bundle?
     ) = FragmentOtherPaymentBinding.inflate(inflater, container, false)
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        requireArguments().apply {
+            groupId = getInt("groupId")
+        }
+
+        initViews()
+
+        initEvents()
+
+        getPaymentList()
+    }
+
+    override fun onResume() {
+        super.onResume()
+
+        if (OASystem.needRefresh) {
+
+            binding.paymentList.adapter!!.notifyItemRangeRemoved(0, paymentList.size)
+            paymentList.clear()
+            getPaymentList()
+
+            OASystem.needRefresh = false
+        }
+    }
+
+    private fun getPaymentList() {
+        apiService.getEntryAndExitOtherPaymentList(
+            EntryAndExitPaymentTypeRequest(
+                diId = groupId,
+                subType = 7
+            )
+        ).enqueue(object : Callback<EntryAndExitOtherPaymentListResponse> {
+            override fun onResponse(
+                call: Call<EntryAndExitOtherPaymentListResponse>,
+                response: Response<EntryAndExitOtherPaymentListResponse>
+            ) {
+                val listResponse = response.body()
+
+                if (listResponse != null) {
+                    if (listResponse.code == 200) {
+
+                        listResponse.data.apply {
+                            paymentId = parentId
+                            totalPayment = otherExpensesTotalCost
+                            binding.isSelected.isChecked = otherExpenses_Checked == 1
+                            binding.paymentTotal.text = String.format(
+                                resources.getString(R.string.total_per_fee_format),
+                                totalPayment
+                            )
+                            for (item in details) {
+                                paymentList.add(item)
+                            }
+                        }
+
+                        OASystem.entryAndExitDetailResponse.otherExpensesTotalCost = totalPayment
+
+                        EventBus.getDefault().post(OASystem.entryAndExitDetailResponse)
+
+                        initList()
+
+                    } else {
+                        showMessage(listResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<EntryAndExitOtherPaymentListResponse>, p1: Throwable) {
+                showErrorInfo(R.string.entry_and_exit_payment_list_get_error)
+            }
+        })
+    }
+
+    override fun initViews() {
+        binding.title.text = resources.getString(R.string.other_fee)
+    }
+
+    override fun initEvents() {
+        binding.isSelected.setOnClickListener {
+            if (binding.isSelected.isChecked) {
+                updateSelectStatus(1)
+            } else {
+                updateSelectStatus(0)
+            }
+        }
+
+        binding.currency.setOnClickListener {
+            showCurrencyPopupView()
+        }
+
+        binding.addPayment.setOnClickListener {
+            val intent =
+                Intent(OASystem.context, OtherPaymentDetailActivity::class.java).apply {
+                    putExtra("fromList", false)
+                    putExtra("diId", groupId)
+                    putExtra("index", if (paymentList.size == 0) {
+                        1
+                    } else {
+                        paymentList.last().index + 1
+                    })
+                }
+
+            startActivity(intent)
+        }
+    }
+
+    private fun initList() {
+        val layoutManager = LinearLayoutManager(OASystem.context)
+        binding.paymentList.layoutManager = layoutManager
+
+        val adapter = CardAdapter.Builder<EntryAndExitOtherPayment>().apply {
+            setData(paymentList)
+            setCanDelete(true)
+            setLayoutId(R.layout.item_entry_and_exit_other_payment)
+            addBindView { itemView, data ->
+                itemView.findViewById<TextView>(R.id.index).text =
+                    String.format(resources.getString(R.string.index_format), data.index)
+                itemView.findViewById<TextView>(R.id.payment_type).text = data.setDataName
+                itemView.findViewById<TextView>(R.id.payment_principle).text = data.cost.toString()
+                itemView.findViewById<TextView>(R.id.currency).text = data.currencyName
+                itemView.findViewById<TextView>(R.id.total_payment).text = data.subTotal.toString()
+                itemView.findViewById<ScrollEditText>(R.id.remark).apply {
+                    setText(data.remark.ifBlank { "-" })
+                    isEnabled(false)
+                }
+            }
+        }.create()
+
+        binding.paymentList.adapter = adapter
+
+        adapter.onRecyclerViewItemClick =
+            object : CardAdapter.OnRecyclerViewItemClick<EntryAndExitOtherPayment> {
+                override fun onItemClick(position: Int) {
+
+                    val item = paymentList[position]
+
+                    val intent = Intent(
+                        OASystem.context,
+                        OtherPaymentDetailActivity::class.java
+                    ).apply {
+                        putExtra("fromList", true)
+                        putExtra("diId", groupId)
+                        putExtra("index", item.index)
+                        putExtra("subId", item.subId)
+                        putExtra("setDataId", item.setDataId)
+                        putExtra("setDataName", item.setDataName)
+                        putExtra("cost", item.cost)
+                        putExtra("currency", item.currency)
+                        putExtra("currencyName", item.currencyName)
+                        putExtra("subTotal", item.subTotal)
+                        putExtra("remark", item.remark)
+                    }
+
+                    startActivity(intent)
+                }
+
+                override fun onItemDelete(position: Int) {
+                    CustomAlertDialog.Builder(OASystem.context).apply {
+                        setTitle(resources.getString(R.string.alert))
+                        setMessage(
+                            String.format(
+                                resources.getString(R.string.entry_and_exit_other_delete_hint),
+                                paymentList[position].index
+                            )
+                        )
+                        setNegativeButtonAndListener(resources.getString(R.string.cancel)) { dialog, _ ->
+                            dialog.dismiss()
+                        }
+                        setPositiveButtonAndListener(resources.getString(R.string.confirm)) { dialog, _ ->
+                            deletePaymentItem(position)
+                            dialog.dismiss()
+                        }
+                    }.show()
+                }
+            }
+    }
+
+    private fun showCurrencyPopupView() {
+        val popView =
+            View.inflate(OASystem.context, R.layout.popup_currency_detail, null)
+        popupWindow = PopupWindow(
+            popView,
+            ViewGroup.LayoutParams.WRAP_CONTENT,
+            ViewGroup.LayoutParams.WRAP_CONTENT
+        )
+
+        showPopupWindow {
+            val usdCurrency: EditText = popView.findViewById(R.id.usd_currency)
+            val eurCurrency: EditText = popView.findViewById(R.id.eur_currency)
+            val gbpCurrency: EditText = popView.findViewById(R.id.gbp_currency)
+            val jpyCurrency: EditText = popView.findViewById(R.id.jpy_currency)
+            val hkdCurrency: EditText = popView.findViewById(R.id.hkd_currency)
+            val cancel: TextView = popView.findViewById(R.id.cancel)
+            val commit: TextView = popView.findViewById(R.id.commit)
+
+            usdCurrency.filters = arrayOf(MoneyInputFilter(4))
+            eurCurrency.filters = arrayOf(MoneyInputFilter(4))
+            gbpCurrency.filters = arrayOf(MoneyInputFilter(4))
+            jpyCurrency.filters = arrayOf(MoneyInputFilter(4))
+            hkdCurrency.filters = arrayOf(MoneyInputFilter(4))
+
+            for (item in OASystem.entryAndExitDetailResponse.currencys) {
+                when (item.currencyCode) {
+                    "USD" -> usdCurrency.setText(item.rate.toString())
+
+                    "EUR" -> eurCurrency.setText(item.rate.toString())
+
+                    "GBP" -> gbpCurrency.setText(item.rate.toString())
+
+                    "JPY" -> jpyCurrency.setText(item.rate.toString())
+
+                    "HKD" -> hkdCurrency.setText(item.rate.toString())
+                }
+            }
+
+            cancel.setOnClickListener {
+                popupWindow.dismiss()
+            }
+
+            commit.setOnClickListener {
+                if (usdCurrency.text.toString().endsWith('.') || usdCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.usd_currency_input_hint))
+                    return@setOnClickListener
+                }
+                if (eurCurrency.text.toString().endsWith('.') || eurCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.eur_currency_input_hint))
+                    return@setOnClickListener
+                }
+                if (gbpCurrency.text.toString().endsWith('.') || gbpCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.gbp_currency_input_hint))
+                    return@setOnClickListener
+                }
+                if (jpyCurrency.text.toString().endsWith('.') || jpyCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.jpy_currency_input_hint))
+                    return@setOnClickListener
+                }
+                if (hkdCurrency.text.toString().endsWith('.') || hkdCurrency.text.toString()
+                        .isBlank()
+                ) {
+                    showMessage(resources.getString(R.string.hkd_currency_input_hint))
+                    return@setOnClickListener
+                }
+
+                for (item in OASystem.entryAndExitDetailResponse.currencys) {
+                    when (item.currencyCode) {
+                        "USD" -> item.rate = usdCurrency.text.toString().toDouble()
+
+                        "EUR" -> item.rate = eurCurrency.text.toString().toDouble()
+
+                        "GBP" -> item.rate = gbpCurrency.text.toString().toDouble()
+
+                        "JPY" -> item.rate = jpyCurrency.text.toString().toDouble()
+
+                        "HKD" -> item.rate = hkdCurrency.text.toString().toDouble()
+                    }
+                }
+
+                updateCurrency(OASystem.entryAndExitDetailResponse.currencys)
+            }
+
+            popupWindow.showAtLocation(binding.root, Gravity.CENTER, 0, 0)
+        }
+    }
+
+    private fun updateCurrency(currencyList: ArrayList<Selector>) {
+        apiService.updateEntryAndExitCurrencyRate(
+            UpdateEntryAndExitCurrencyRateRequest(
+                id = paymentId,
+                diId = groupId,
+                currencys = currencyList
+            )
+        ).enqueue(object : Callback<BaseResponse> {
+            override fun onResponse(call: Call<BaseResponse>, response: Response<BaseResponse>) {
+                val updateResponse = response.body()
+
+                if (updateResponse != null) {
+                    if (updateResponse.code == 200) {
+                        showMessage(resources.getString(R.string.update_success))
+
+                        binding.paymentList.adapter!!.notifyItemRangeRemoved(0, paymentList.size)
+                        paymentList.clear()
+                        getPaymentList()
+                        popupWindow.dismiss()
+
+                    } else {
+                        showMessage(updateResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<BaseResponse>, p1: Throwable) {
+                showErrorInfo(R.string.update_error)
+            }
+        })
+    }
+
+    private fun updateSelectStatus(status: Int) {
+
+        Log.e("request", Gson().toJson(UpdateEntryAndExitTypeStatusRequest(
+            id = paymentId,
+            diId = groupId,
+            itemType = 7,
+            isSelected = status
+        )))
+
+        apiService.updateEntryAndExitTypeStatus(
+            UpdateEntryAndExitTypeStatusRequest(
+                id = paymentId,
+                diId = groupId,
+                itemType = 7,
+                isSelected = status
+            )
+        ).enqueue(object : Callback<BaseResponse> {
+            override fun onResponse(call: Call<BaseResponse>, response: Response<BaseResponse>) {
+                val updateResponse = response.body()
+
+                if (updateResponse != null) {
+                    if (updateResponse.code == 200) {
+                        showMessage(resources.getString(R.string.update_success))
+
+                        OASystem.entryAndExitDetailResponse.otherExpenses_Checked = status
+
+                        EventBus.getDefault().post(OASystem.entryAndExitDetailResponse)
+
+                    } else {
+                        showMessage(updateResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<BaseResponse>, p1: Throwable) {
+                showErrorInfo(R.string.interface_request_error)
+            }
+        })
+    }
+
+    private fun deletePaymentItem(position: Int) {
+        apiService.deleteEntryAndExitOtherPayment(DeleteEntryAndExitPaymentItemRequest(id = paymentList[position].subId))
+            .enqueue(object : Callback<BaseResponse> {
+                override fun onResponse(
+                    call: Call<BaseResponse>,
+                    response: Response<BaseResponse>
+                ) {
+
+                    val deleteResponse = response.body()
+
+                    if (deleteResponse != null) {
+                        if (deleteResponse.code == 200) {
+
+                            totalPayment -= paymentList[position].subTotal
+
+                            paymentList.removeAt(position)
+                            binding.paymentList.adapter!!.notifyItemRemoved(position)
+                            binding.paymentList.adapter!!.notifyItemRangeChanged(
+                                position,
+                                paymentList.size - position
+                            )
+
+                            binding.paymentTotal.text = String.format(
+                                resources.getString(R.string.total_per_fee_format),
+                                totalPayment
+                            )
+
+                            OASystem.entryAndExitDetailResponse.otherExpensesTotalCost = totalPayment
+
+                            EventBus.getDefault().post(OASystem.entryAndExitDetailResponse)
+
+                            showMessage(resources.getString(R.string.delete_success))
+
+                        } else {
+                            showMessage(deleteResponse.msg)
+                        }
+                    }
+                }
+
+                override fun onFailure(p0: Call<BaseResponse>, p1: Throwable) {
+                    showErrorInfo(R.string.delete_error)
+                }
+            })
+    }
 }

+ 234 - 0
app/src/main/res/layout/activity_entry_and_exit_payment_detail.xml

@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <include
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        layout="@layout/layout_title" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/common_padding_heavy"
+        android:layout_marginTop="@dimen/common_padding_huge"
+        android:layout_marginEnd="@dimen/common_padding_heavy"
+        android:orientation="vertical"
+        tools:ignore="UselessParent">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/nights_number"
+                android:textSize="@dimen/text_size_medium" />
+
+            <EditText
+                android:id="@+id/nights"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_input"
+                android:importantForAutofill="no"
+                android:inputType="number"
+                android:selectAllOnFocus="true"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/city"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/city"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_select"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/payment_principle"
+                android:textSize="@dimen/text_size_medium" />
+
+            <EditText
+                android:id="@+id/payment_principle"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_input"
+                android:importantForAutofill="no"
+                android:inputType="numberDecimal"
+                android:selectAllOnFocus="true"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/currency"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/currency"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/total_payment"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/total_payment"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:text="@string/cny" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/commit"
+                android:layout_width="0dp"
+                android:layout_height="@dimen/button_height"
+                android:layout_gravity="center"
+                android:layout_margin="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@drawable/shape_corner_solid_blue"
+                android:gravity="center"
+                android:text="@string/update"
+                android:textColor="@color/white"
+                android:textSize="@dimen/text_size_large"
+                android:textStyle="bold" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</LinearLayout>

+ 253 - 0
app/src/main/res/layout/activity_other_payment_detail.xml

@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <include
+        layout="@layout/layout_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/common_padding_heavy"
+        android:layout_marginTop="@dimen/common_padding_huge"
+        android:layout_marginEnd="@dimen/common_padding_heavy"
+        android:orientation="vertical"
+        tools:ignore="UselessParent">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/index_number"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/index"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/payment_type"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/payment_type"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_select"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/payment_principle"
+                android:textSize="@dimen/text_size_medium" />
+
+            <EditText
+                android:id="@+id/payment_principle"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_input"
+                android:importantForAutofill="no"
+                android:inputType="numberDecimal"
+                android:selectAllOnFocus="true"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/currency"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/currency"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_select"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/total_payment"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/total_payment"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:text="@string/cny" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:orientation="vertical">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/notes"
+                android:textSize="@dimen/text_size_medium" />
+
+            <com.pan_american.android.util.ScrollEditText
+                android:id="@+id/remark"
+                android:layout_width="match_parent"
+                android:layout_height="120dp"
+                android:layout_marginTop="@dimen/common_padding" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/commit"
+                android:layout_width="0dp"
+                android:layout_height="@dimen/button_height"
+                android:layout_gravity="center"
+                android:layout_margin="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@drawable/shape_corner_solid_blue"
+                android:gravity="center"
+                android:text="@string/update"
+                android:textColor="@color/white"
+                android:textSize="@dimen/text_size_large"
+                android:textStyle="bold" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</LinearLayout>

+ 91 - 6
app/src/main/res/layout/fragment_entry_and_exit_payment_list.xml

@@ -1,13 +1,98 @@
 <?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ui.group_management.entry_and_exit_fee_detail.EntryAndExitPaymentListFragment">
+    android:background="@color/white"
+    android:orientation="vertical">
 
-    <TextView
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:text="@string/hello_blank_fragment" />
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/common_padding"
+        android:orientation="horizontal"
+        tools:ignore="UselessParent">
 
-</FrameLayout>
+        <CheckBox
+            android:id="@+id/is_selected"
+            android:layout_width="50dp"
+            android:layout_height="50dp"
+            android:layout_gravity="center"
+            android:theme="@style/CheckBoxTheme" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_weight="1"
+            android:padding="@dimen/common_padding_small"
+            android:textSize="@dimen/text_size_large"
+            android:textStyle="bold" />
+
+        <TextView
+            android:id="@+id/add_payment"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginEnd="@dimen/common_padding"
+            android:background="@drawable/shape_corner_solid_blue"
+            android:padding="@dimen/common_padding_small"
+            android:text="@string/add"
+            android:textColor="@color/white"
+            android:textSize="@dimen/text_size_small" />
+
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/line"
+        android:layout_marginTop="@dimen/common_padding_small"
+        android:layout_marginBottom="@dimen/common_padding"
+        android:background="@color/line_color" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/common_padding"
+        android:layout_marginBottom="@dimen/common_padding_small"
+        android:gravity="end"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/currency"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/show_exchange_rate"
+            android:textColor="@color/title_background_color"
+            android:textSize="@dimen/text_size_medium" />
+
+    </LinearLayout>
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/payment_list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:background="@color/background_color"
+        android:paddingBottom="@dimen/common_padding_small"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/payment_total"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_margin="@dimen/common_padding"
+            android:padding="@dimen/common_padding_large"
+            android:text=""
+            android:textSize="@dimen/text_size_large"
+            android:textStyle="bold" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 91 - 6
app/src/main/res/layout/fragment_other_payment.xml

@@ -1,13 +1,98 @@
 <?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ui.group_management.entry_and_exit_fee_detail.OtherPaymentFragment">
+    android:background="@color/white"
+    android:orientation="vertical">
 
-    <TextView
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:text="@string/hello_blank_fragment" />
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/common_padding"
+        android:orientation="horizontal"
+        tools:ignore="UselessParent">
 
-</FrameLayout>
+        <CheckBox
+            android:id="@+id/is_selected"
+            android:layout_width="50dp"
+            android:layout_height="50dp"
+            android:layout_gravity="center"
+            android:theme="@style/CheckBoxTheme" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_weight="1"
+            android:padding="@dimen/common_padding_small"
+            android:textSize="@dimen/text_size_large"
+            android:textStyle="bold" />
+
+        <TextView
+            android:id="@+id/add_payment"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginEnd="@dimen/common_padding"
+            android:background="@drawable/shape_corner_solid_blue"
+            android:padding="@dimen/common_padding_small"
+            android:text="@string/add"
+            android:textColor="@color/white"
+            android:textSize="@dimen/text_size_small" />
+
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/line"
+        android:layout_marginTop="@dimen/common_padding_small"
+        android:layout_marginBottom="@dimen/common_padding"
+        android:background="@color/line_color" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/common_padding"
+        android:layout_marginBottom="@dimen/common_padding_small"
+        android:gravity="end"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/currency"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/show_exchange_rate"
+            android:textColor="@color/title_background_color"
+            android:textSize="@dimen/text_size_medium" />
+
+    </LinearLayout>
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/payment_list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:background="@color/background_color"
+        android:paddingBottom="@dimen/common_padding_small"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/payment_total"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_margin="@dimen/common_padding"
+            android:padding="@dimen/common_padding_large"
+            android:text=""
+            android:textSize="@dimen/text_size_large"
+            android:textStyle="bold" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 218 - 0
app/src/main/res/layout/item_entry_and_exit_other_payment.xml

@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_margin="@dimen/common_padding"
+    android:background="@drawable/shape_corner_stroke_white"
+    android:orientation="vertical"
+    tools:viewBindingIgnore="true">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/common_padding"
+        android:orientation="vertical"
+        tools:ignore="UselessParent">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal"
+            tools:ignore="UseCompoundDrawables">
+
+            <TextView
+                android:id="@+id/index"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_marginEnd="@dimen/common_padding_huge"
+                android:layout_weight="1"
+                android:textColor="@color/text_color_blue"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <ImageView
+                android:id="@+id/delete"
+                android:layout_width="@dimen/common_padding_heavy"
+                android:layout_height="@dimen/common_padding_heavy"
+                android:layout_marginEnd="@dimen/common_padding"
+                android:src="@mipmap/icon_delete"
+                tools:ignore="ContentDescription" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/payment_type"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/payment_type"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/payment_principle"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/payment_principle"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/currency"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/currency"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/total_payment"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/total_payment"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_marginEnd="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/cny"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:orientation="vertical">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/notes"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <com.pan_american.android.util.ScrollEditText
+                android:id="@+id/remark"
+                android:layout_width="match_parent"
+                android:layout_height="120dp"
+                android:layout_marginTop="@dimen/common_padding"/>
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</LinearLayout>

+ 190 - 0
app/src/main/res/layout/item_entry_and_exit_payment.xml

@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_margin="@dimen/common_padding"
+    android:background="@drawable/shape_corner_stroke_white"
+    android:orientation="vertical"
+    tools:viewBindingIgnore="true">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/common_padding"
+        android:orientation="vertical"
+        tools:ignore="UselessParent">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal"
+            tools:ignore="UseCompoundDrawables">
+
+            <TextView
+                android:id="@+id/days"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_marginEnd="@dimen/common_padding_huge"
+                android:layout_weight="1"
+                android:textColor="@color/text_color_blue"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <ImageView
+                android:id="@+id/delete"
+                android:layout_width="@dimen/common_padding_heavy"
+                android:layout_height="@dimen/common_padding_heavy"
+                android:layout_marginEnd="@dimen/common_padding"
+                android:src="@mipmap/icon_delete"
+                tools:ignore="ContentDescription" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/city"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/city"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/payment_principle"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/payment_principle"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/currency"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/currency"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/total_payment"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/total_payment"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_marginEnd="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/cny"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</LinearLayout>

+ 255 - 0
app/src/main/res/layout/popup_currency_detail.xml

@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="@dimen/common_padding_huge"
+    android:layout_marginEnd="@dimen/common_padding_huge"
+    android:background="@drawable/shape_corner_white"
+    android:orientation="vertical"
+    tools:viewBindingIgnore="true">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/common_padding_heavy"
+        android:layout_marginTop="@dimen/common_padding_huge"
+        android:layout_marginEnd="@dimen/common_padding_heavy"
+        android:orientation="vertical"
+        tools:ignore="UselessParent">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/usd_currency"
+                android:textSize="@dimen/text_size_medium" />
+
+            <EditText
+                android:id="@+id/usd_currency"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_input"
+                android:importantForAutofill="no"
+                android:inputType="numberDecimal"
+                android:selectAllOnFocus="true"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/eur_currency"
+                android:textSize="@dimen/text_size_medium" />
+
+            <EditText
+                android:id="@+id/eur_currency"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_input"
+                android:importantForAutofill="no"
+                android:inputType="numberDecimal"
+                android:selectAllOnFocus="true"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/gbp_currency"
+                android:textSize="@dimen/text_size_medium" />
+
+            <EditText
+                android:id="@+id/gbp_currency"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_input"
+                android:importantForAutofill="no"
+                android:inputType="numberDecimal"
+                android:selectAllOnFocus="true"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/jpy_currency"
+                android:textSize="@dimen/text_size_medium" />
+
+            <EditText
+                android:id="@+id/jpy_currency"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_input"
+                android:importantForAutofill="no"
+                android:inputType="numberDecimal"
+                android:selectAllOnFocus="true"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/hkd_currency"
+                android:textSize="@dimen/text_size_medium" />
+
+            <EditText
+                android:id="@+id/hkd_currency"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:hint="@string/please_input"
+                android:importantForAutofill="no"
+                android:inputType="numberDecimal"
+                android:selectAllOnFocus="true"
+                android:singleLine="true"
+                android:textColor="@color/text_color"
+                android:textColorHint="@color/hint_text_color"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/cancel"
+                android:layout_width="0dp"
+                android:layout_height="@dimen/button_height"
+                android:layout_gravity="center"
+                android:layout_margin="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@drawable/shape_corner_reset_button"
+                android:gravity="center"
+                android:text="@string/cancel"
+                android:textColor="@color/white"
+                android:textSize="@dimen/text_size_large"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/commit"
+                android:layout_width="0dp"
+                android:layout_height="@dimen/button_height"
+                android:layout_gravity="center"
+                android:layout_margin="@dimen/common_padding"
+                android:layout_weight="1"
+                android:background="@drawable/shape_corner_solid_blue"
+                android:gravity="center"
+                android:text="@string/update"
+                android:textColor="@color/white"
+                android:textSize="@dimen/text_size_large"
+                android:textStyle="bold" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+
+</LinearLayout>

+ 32 - 0
app/src/main/res/values/strings.xml

@@ -1325,6 +1325,9 @@
 
     <string name="show_currency">查看汇率</string>
     <string name="city_traffic_payment">城市区间交通费</string>
+    <string name="payment_principle">费用标准</string>
+    <string name="nights_format">第 %d 晚</string>
+    <string name="index_format">第 %d 项</string>
 
     <string name="visa_price_input_hint">请输入正确的签证费用</string>
     <string name="vaccine_price_input_hint">请输入正确的疫苗费用</string>
@@ -1334,17 +1337,46 @@
     <string name="ticket_price_input_hint">请输入正确的参展门票费用</string>
 
     <string name="put_in">填入</string>
+    <string name="show_exchange_rate">查看汇率</string>
+    <string name="entry_and_exit_delete_hint">确认删除第%d晚的费用项? </string>
+    <string name="entry_and_exit_type_change_hint">是否选择 / 反项: %s</string>
+    <string name="entry_and_exit_other_delete_hint">确认删除第%d项费用?</string>
+
+    <string name="usd_currency">美元汇率</string>
+    <string name="eur_currency">欧元汇率</string>
+    <string name="gbp_currency">英镑汇率</string>
+    <string name="jpy_currency">日元汇率</string>
+    <string name="hkd_currency">港币汇率</string>
+
+    <string name="usd_currency_input_hint">请输入正确的美元汇率</string>
+    <string name="eur_currency_input_hint">请输入正确的欧元汇率</string>
+    <string name="gbp_currency_input_hint">请输入正确的英镑汇率</string>
+    <string name="jpy_currency_input_hint">请输入正确的日元汇率</string>
+    <string name="hkd_currency_input_hint">请输入正确的港币汇率</string>
+
+    <string name="entry_and_exit_payment_detail">三公费用详情</string>
+    <string name="add_entry_and_exit_payment_detail">新增三公费用</string>
+    <string name="nights_number">第几晚</string>
+
+    <string name="index_number">第几项</string>
+    <string name="other_payment_base_data_get_error">其它款项基础数据源获取失败</string>
+
     <string name="economy_class_price_input_hint">请输入正确的经济舱价格</string>
     <string name="business_class_price_input_hint">请输入正确的公务舱价格</string>
     <string name="first_class_price_input_hint">请输入正确的头等舱价格</string>
     <string name="city_traffic_payment_input_hint">请输入正确的城市间交通费用</string>
 
+    <string name="nights_input_hint">请输入正确的天数</string>
+    <string name="city_selected_hint">请选择国家 / 地区</string>
+
     <string name="entry_and_exit_detail_total_get_error">出入境费用总览获取失败</string>
     <string name="in_board_payment_detail_get_error">境内费用详情获取失败</string>
     <string name="newest_visa_payment_get_error">获取最新签证费用失败</string>
     <string name="international_travel_payment_get_error">国际旅费详情获取失败</string>
     <string name="international_travel_tips_get_error">国际旅费Tips获取失败</string>
 
+    <string name="entry_and_exit_payment_list_get_error">出入境费用明细费用列表获取失败</string>
+
     <!-- TODO: Remove or change this placeholder text -->
     <string name="hello_blank_fragment">Hello blank fragment</string>