diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/room/query/RoomVoiceProfileByRoomAccountQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/room/query/RoomVoiceProfileByRoomAccountQryExe.java index 0293afcd..c1e0f330 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/room/query/RoomVoiceProfileByRoomAccountQryExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/room/query/RoomVoiceProfileByRoomAccountQryExe.java @@ -31,9 +31,9 @@ public class RoomVoiceProfileByRoomAccountQryExe { if (roomVoiceProfile == null || !Objects.equals(roomVoiceProfile.getSysOrigin(), cmd.requireReqSysOrigin())) { return null; } - /*if (!userRegionGateway.checkEqRegion(cmd.getReqUserId(), roomVoiceProfile.getUserId())) { + if (!userRegionGateway.checkEqRegion(cmd.requiredReqUserId(), roomVoiceProfile.getUserId())) { return null; - }*/ + } return roomVoiceProfile; } diff --git a/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/room/query/RoomVoiceProfileByRoomAccountQryExeTest.java b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/room/query/RoomVoiceProfileByRoomAccountQryExeTest.java new file mode 100644 index 00000000..9f497b35 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/room/query/RoomVoiceProfileByRoomAccountQryExeTest.java @@ -0,0 +1,73 @@ +package com.red.circle.other.app.command.room.query; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.red.circle.framework.core.dto.ReqSysOrigin; +import com.red.circle.other.app.common.room.RoomVoiceProfileCommon; +import com.red.circle.other.app.dto.clientobject.room.RoomVoiceProfileCO; +import com.red.circle.other.app.dto.cmd.room.SearchRoomAccountCmd; +import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway; +import org.junit.jupiter.api.Test; + +class RoomVoiceProfileByRoomAccountQryExeTest { + + @Test + void execute_shouldReturnRoomWhenSearcherAndRoomOwnerAreSameRegion() { + RoomVoiceProfileCommon roomVoiceProfileCommon = mock(RoomVoiceProfileCommon.class); + UserRegionGateway userRegionGateway = mock(UserRegionGateway.class); + RoomVoiceProfileByRoomAccountQryExe exe = new RoomVoiceProfileByRoomAccountQryExe( + roomVoiceProfileCommon, + userRegionGateway + ); + + SearchRoomAccountCmd cmd = new SearchRoomAccountCmd(); + cmd.setReqUserId(1001L); + cmd.setReqSysOrigin(ReqSysOrigin.of("LIKEI", "LIKEI")); + cmd.setRoomAccount("88888"); + + RoomVoiceProfileCO roomVoiceProfile = new RoomVoiceProfileCO() + .setSysOrigin("LIKEI") + .setUserId(2001L); + + when(roomVoiceProfileCommon.getAvailableByRoomAccount(cmd.requireReqSysOriginEnum(), "88888")) + .thenReturn(roomVoiceProfile); + when(userRegionGateway.checkEqRegion(1001L, 2001L)).thenReturn(true); + + RoomVoiceProfileCO result = exe.execute(cmd); + + assertSame(roomVoiceProfile, result); + verify(userRegionGateway).checkEqRegion(1001L, 2001L); + } + + @Test + void execute_shouldHideRoomWhenSearcherAndRoomOwnerAreDifferentRegion() { + RoomVoiceProfileCommon roomVoiceProfileCommon = mock(RoomVoiceProfileCommon.class); + UserRegionGateway userRegionGateway = mock(UserRegionGateway.class); + RoomVoiceProfileByRoomAccountQryExe exe = new RoomVoiceProfileByRoomAccountQryExe( + roomVoiceProfileCommon, + userRegionGateway + ); + + SearchRoomAccountCmd cmd = new SearchRoomAccountCmd(); + cmd.setReqUserId(1001L); + cmd.setReqSysOrigin(ReqSysOrigin.of("LIKEI", "LIKEI")); + cmd.setRoomAccount("88888"); + + RoomVoiceProfileCO roomVoiceProfile = new RoomVoiceProfileCO() + .setSysOrigin("LIKEI") + .setUserId(2001L); + + when(roomVoiceProfileCommon.getAvailableByRoomAccount(cmd.requireReqSysOriginEnum(), "88888")) + .thenReturn(roomVoiceProfile); + when(userRegionGateway.checkEqRegion(1001L, 2001L)).thenReturn(false); + + RoomVoiceProfileCO result = exe.execute(cmd); + + assertNull(result); + verify(userRegionGateway).checkEqRegion(1001L, 2001L); + } +} diff --git a/sql/20260430_mifapay_supported_country_channels_only.sql b/sql/20260430_mifapay_supported_country_channels_only.sql new file mode 100644 index 00000000..8d9a4e05 --- /dev/null +++ b/sql/20260430_mifapay_supported_country_channels_only.sql @@ -0,0 +1,201 @@ +-- MiFaPay supported country/channel restriction. +-- Source: merchant enabled methods provided on 2026-04-30. +-- This file is intended to run after 20260430_mifapay_full_payment_country_channels.sql. +-- The fee columns below are kept as source notes only; current payment tables do not store fees. + +START TRANSACTION; + +SET @factory_code := 'MIFA_PAY'; +SET @sys_origin := 'LIKEI'; +SET @region_relation_group := 'OPEN_PAY_COUNTRY'; + +DROP TEMPORARY TABLE IF EXISTS `tmp_mifapay_supported_channel`; +CREATE TEMPORARY TABLE `tmp_mifapay_supported_channel` ( + `country_code` VARCHAR(2) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `currency` VARCHAR(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `channel_code` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `factory_channel` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `fee_percent` DECIMAL(10, 4) NOT NULL DEFAULT 0, + `fixed_fee` DECIMAL(18, 4) NOT NULL DEFAULT 0, + `fixed_fee_currency` VARCHAR(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '', + `sort` INT NOT NULL, + PRIMARY KEY (`country_code`, `currency`, `channel_code`, `factory_channel`) +) ENGINE=Memory; + +INSERT INTO `tmp_mifapay_supported_channel` + (`country_code`, `currency`, `channel_code`, `factory_channel`, `fee_percent`, `fixed_fee`, `fixed_fee_currency`, `sort`) +VALUES + ('ID', 'IDR', 'BankTransfer_BCA', 'BCA', 1.0000, 4500.0000, 'IDR', 10), + ('ID', 'IDR', 'BankTransfer_BNI', 'BNI', 1.0000, 4500.0000, 'IDR', 20), + ('ID', 'IDR', 'BankTransfer_BRI', 'BRI', 1.0000, 4500.0000, 'IDR', 30), + ('ID', 'IDR', 'BankTransfer_Mandiri', 'Mandiri', 1.0000, 4500.0000, 'IDR', 40), + ('ID', 'IDR', 'BankTransfer_Permata', 'Permata', 1.0000, 4500.0000, 'IDR', 50), + ('ID', 'IDR', 'Ewallet_DANA', 'DANA', 2.5000, 0.0000, '', 60), + ('ID', 'IDR', 'Ewallet_LinkAja', 'LinkAja', 3.0000, 0.0000, '', 70), + ('ID', 'IDR', 'Ewallet_OVO', 'OVO', 3.0000, 0.0000, '', 80), + ('ID', 'IDR', 'Ewallet_ShopeePay', 'ShopeePay', 3.0000, 0.0000, '', 90), + ('ID', 'IDR', 'QR_QRIS', 'QRIS', 1.8000, 0.0000, '', 100), + ('IN', 'INR', 'Ewallet_BHIM', 'BHIM', 2.5000, 0.0000, '', 110), + ('IN', 'INR', 'Ewallet_GooglePay', 'GooglePay', 2.5000, 0.0000, '', 120), + ('IN', 'INR', 'Ewallet_Mobikwik', 'Mobikwik', 2.5000, 0.0000, '', 130), + ('IN', 'INR', 'Ewallet_Paytm', 'Paytm', 2.5000, 0.0000, '', 140), + ('IN', 'INR', 'Ewallet_PhonePe', 'PhonePe', 2.5000, 0.0000, '', 150), + ('IN', 'INR', 'Ewallet_UPI', 'UPI', 2.5000, 0.0000, '', 160), + ('PK', 'PKR', 'Ewallet_Easypaisa', 'Easypaisa', 5.5000, 0.0000, '', 170), + ('PK', 'PKR', 'Ewallet_JazzCash', 'JazzCash', 5.5000, 0.0000, '', 180), + ('VN', 'VND', 'QR_VietQR', 'VietQR', 4.5000, 0.0000, '', 190), + ('VN', 'VND', 'BankTransfer_VN_BankTransfer', 'VN_BankTransfer', 4.5000, 0.0000, '', 200); + +-- Hide unsupported MiFaPay country/channel combinations. +UPDATE `sys_pay_country_channel_details` d +JOIN `sys_pay_country` pc ON pc.`id` = d.`pay_country_id` +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +SET d.`is_shelf` = 0, + d.`update_time` = CURRENT_TIMESTAMP +WHERE d.`factory_code` = @factory_code + AND NOT EXISTS ( + SELECT 1 + FROM `tmp_mifapay_supported_channel` s + WHERE s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` + AND s.`channel_code` = d.`channel_code` + AND s.`factory_channel` = d.`factory_channel` + ); + +-- Enable supported MiFaPay country/channel combinations. +UPDATE `sys_pay_country_channel_details` d +JOIN `sys_pay_country` pc ON pc.`id` = d.`pay_country_id` +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +JOIN `tmp_mifapay_supported_channel` s + ON s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` + AND s.`channel_code` = d.`channel_code` + AND s.`factory_channel` = d.`factory_channel` +SET d.`is_shelf` = 1, + d.`factory_min_limit` = 0.01, + d.`factory_max_limit` = 99999999.00, + d.`factory_daily_limit` = 99999999.00, + d.`suggest_score` = GREATEST(1, 100 - s.`sort` DIV 10), + d.`update_time` = CURRENT_TIMESTAMP +WHERE d.`factory_code` = @factory_code; + +-- Keep only supported country/channel pairs visible. +UPDATE `sys_pay_country_channel` cch +JOIN `sys_pay_country` pc ON pc.`id` = cch.`pay_country_id` +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +SET cch.`is_shelf` = 0, + cch.`update_time` = CURRENT_TIMESTAMP +WHERE EXISTS ( + SELECT 1 + FROM `sys_pay_country_channel_details` d + WHERE d.`pay_country_id` = cch.`pay_country_id` + AND d.`channel_code` = cch.`channel_code` + AND d.`factory_code` = @factory_code + ) + AND NOT EXISTS ( + SELECT 1 + FROM `tmp_mifapay_supported_channel` s + WHERE s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` + AND s.`channel_code` = cch.`channel_code` + ); + +UPDATE `sys_pay_country_channel` cch +JOIN `sys_pay_country` pc ON pc.`id` = cch.`pay_country_id` +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +JOIN `tmp_mifapay_supported_channel` s + ON s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` + AND s.`channel_code` = cch.`channel_code` +SET cch.`is_shelf` = 1, + cch.`update_time` = CURRENT_TIMESTAMP; + +-- Keep only supported MiFaPay countries visible in generic pay country APIs. +UPDATE `sys_pay_country` pc +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +SET pc.`is_shelf` = 0, + pc.`update_time` = CURRENT_TIMESTAMP +WHERE EXISTS ( + SELECT 1 + FROM `sys_pay_country_channel_details` d + WHERE d.`pay_country_id` = pc.`id` + AND d.`factory_code` = @factory_code + ) + AND NOT EXISTS ( + SELECT 1 + FROM `tmp_mifapay_supported_channel` s + WHERE s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` + ); + +UPDATE `sys_pay_country` pc +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +JOIN (SELECT DISTINCT `country_code`, `currency` FROM `tmp_mifapay_supported_channel`) s + ON s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` +SET pc.`is_shelf` = 1, + pc.`update_time` = CURRENT_TIMESTAMP; + +-- V2 region exposure uses sys_region_relation. Hide unsupported pay countries for LIKEI. +UPDATE `sys_region_relation` rr +JOIN `sys_pay_country` pc ON pc.`id` = rr.`relation_id` +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +SET rr.`is_showcase` = 0, + rr.`update_time` = CURRENT_TIMESTAMP +WHERE rr.`sys_origin` = @sys_origin + AND rr.`group_type` = @region_relation_group + AND NOT EXISTS ( + SELECT 1 + FROM `tmp_mifapay_supported_channel` s + WHERE s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` + ); + +UPDATE `sys_region_relation` rr +JOIN `sys_pay_country` pc ON pc.`id` = rr.`relation_id` +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +JOIN (SELECT DISTINCT `country_code`, `currency` FROM `tmp_mifapay_supported_channel`) s + ON s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` +SET rr.`is_showcase` = 1, + rr.`update_time` = CURRENT_TIMESTAMP +WHERE rr.`sys_origin` = @sys_origin + AND rr.`group_type` = @region_relation_group; + +COMMIT; + +-- Verification queries. +SELECT 'supported_pay_countries' AS `metric`, COUNT(DISTINCT pc.`id`) AS `value` +FROM `sys_pay_country` pc +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +JOIN (SELECT DISTINCT `country_code`, `currency` FROM `tmp_mifapay_supported_channel`) s + ON s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` +WHERE pc.`is_shelf` = 1; + +SELECT 'supported_channel_details' AS `metric`, COUNT(*) AS `value` +FROM `sys_pay_country_channel_details` d +JOIN `sys_pay_country` pc ON pc.`id` = d.`pay_country_id` +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +JOIN `tmp_mifapay_supported_channel` s + ON s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` + AND s.`channel_code` = d.`channel_code` + AND s.`factory_channel` = d.`factory_channel` +WHERE d.`factory_code` = @factory_code + AND d.`is_shelf` = 1; + +SELECT 'unsupported_shelf_mifapay_details' AS `metric`, COUNT(*) AS `value` +FROM `sys_pay_country_channel_details` d +JOIN `sys_pay_country` pc ON pc.`id` = d.`pay_country_id` +JOIN `sys_country_code` cc ON cc.`id` = pc.`country_id` +WHERE d.`factory_code` = @factory_code + AND d.`is_shelf` = 1 + AND NOT EXISTS ( + SELECT 1 + FROM `tmp_mifapay_supported_channel` s + WHERE s.`country_code` = cc.`alpha_two` + AND s.`currency` = pc.`currency` + AND s.`channel_code` = d.`channel_code` + AND s.`factory_channel` = d.`factory_channel` + );