'group:自媒体4', 'channel_codes' => ['tag_et4h', 'tag_et4q', 'group:ignored'], 'is_group' => true, ]); conversionFinanceExpect( $leafCodes === ['tag_et4h', 'tag_et4q'], 'Stats channel codes must expand a group into leaf codes only' ); $reflection = new ReflectionClass(FirstVisitConversionLogic::class); $canViewFinance = $reflection->getMethod('canViewFinance'); $maskFinanceFields = $reflection->getMethod('maskFinanceFields'); $personalYejiMediaSources = $reflection->getMethod('personalYejiMediaSources'); $canViewFinance->setAccessible(true); $maskFinanceFields->setAccessible(true); $personalYejiMediaSources->setAccessible(true); conversionFinanceExpect( $canViewFinance->invoke(null, 1, ['root' => 1, 'role_name' => '医助']) === true, 'Root must always see cash cost and ROI' ); conversionFinanceExpect( $canViewFinance->invoke(null, 8, ['root' => 0, 'role_name' => '经理']) === true, 'Managers must always see cash cost and ROI' ); conversionFinanceExpect( $canViewFinance->invoke(null, 0, ['root' => 0, 'role_name' => '诊室组长']) === false, 'Group leaders without the finance permission must not see cash cost and ROI' ); conversionFinanceExpect( $canViewFinance->invoke(null, 0, ['root' => 0, 'role_name' => '医助']) === false, 'Assistants without the finance permission must not see cash cost and ROI' ); $masked = $maskFinanceFields->invoke(null, [ 'completed_order_count' => 2, 'account_cost' => 88.5, 'cash_cost' => 12.3, 'roi' => 1.5, 'children' => [[ 'name' => '医助甲', 'account_cost' => 40, 'roi' => 2, 'children' => [], ]], ]); conversionFinanceExpect( !isset($masked['account_cost'], $masked['cash_cost'], $masked['roi']) && $masked['completed_order_count'] === 2 && !isset($masked['children'][0]['account_cost'], $masked['children'][0]['roi']), 'Finance fields must be stripped from summary rows and nested members' ); $groupSources = $personalYejiMediaSources->invoke(null, 'group:自媒体4', [ 'channel_code' => 'group:自媒体4', 'channel_name' => '自媒体4', 'channel_codes' => ['tag_et4h', 'tag_et4q'], 'channel_names' => ['自媒体4H', '自媒体4Q'], 'is_group' => true, ]); conversionFinanceExpect( is_array($groupSources) && in_array('自媒体4', $groupSources, true) && in_array('自媒体4H', $groupSources, true) && in_array('自媒体4Q', $groupSources, true) && in_array('tag_et4h', $groupSources, true) && !in_array('group:自媒体4', $groupSources, true), 'Group channel opening counts must match every leaf name and code, not the synthetic group code' ); echo "FirstVisitConversionFinanceAndChannelTest passed\n";