agents[(int) $agent['id']] = $agent; $this->agentsByDepartment[(int) $agent['dept_id']][] = (int) $agent['id']; } } public function calculate(array $device, string $product): array { if (empty($device['merchant_id'])) { return ['merchant_rate' => 0.0, 'manager_rate' => 0.0]; } $merchantAgent = (int) $device['merchant_agent_id']; $manager = (int) $device['manage_agent_id']; $parentRate = $this->agentRate($merchantAgent, $product); $relativeRate = $this->validRate($device['merchant_relative_rate']); // 不分成和入驻费没有按订单比例分成;明确的 0 不依赖上级档案。 if (in_array($device['profit_method'], ['不分成', '入驻费'], true) || $relativeRate === 0.0) { $merchantRate = 0.0; } else { $merchantRate = $parentRate !== null && $relativeRate !== null ? round($parentRate * $relativeRate / 100, 4) : null; } $managerRate = $this->agentRate($manager, $product); if ($manager === $merchantAgent) { $childRate = $merchantRate; } else { $childId = $this->findBranchChild($manager, $merchantAgent); // 0 表示管理人不在这条分成链上;NULL 表示关系有歧义,不能猜测。 if ($childId === 0) { return ['merchant_rate' => $merchantRate, 'manager_rate' => 0.0]; } $childRate = $childId === null ? null : $this->agentRate($childId, $product); } $netManagerRate = $managerRate !== null && $childRate !== null && $managerRate >= $childRate ? round($managerRate - $childRate, 4) : null; return ['merchant_rate' => $merchantRate, 'manager_rate' => $netManagerRate]; } private function agentRate(int $id, string $product): ?float { return $this->validRate($this->agents[$id]['rates'][$product] ?? null); } private function validRate(mixed $value): ?float { return is_numeric($value) && $value >= 0 && $value <= 100 ? (float) $value : null; } /** 沿商户代理的部门祖先路径,查找管理人下面参与该笔分成的第一个代理。 */ private function findBranchChild(int $managerId, int $merchantAgentId): ?int { $manager = $this->agents[$managerId] ?? null; $merchantAgent = $this->agents[$merchantAgentId] ?? null; if (!$manager || !$merchantAgent) { return null; } $path = array_map('intval', array_filter(explode(',', $merchantAgent['dept_level'] ?? ''), 'strlen')); $path[] = (int) $merchantAgent['dept_id']; $position = array_search((int) $manager['dept_id'], $path, true); if ($position === false) { return 0; } if ((int) $manager['dept_id'] === (int) $merchantAgent['dept_id']) { return null; } foreach (array_slice($path, $position + 1) as $departmentId) { if ($departmentId === (int) $merchantAgent['dept_id']) { return $merchantAgentId; } $candidates = $this->agentsByDepartment[$departmentId] ?? []; if (count($candidates) > 1) { return null; } if (count($candidates) === 1) { return $candidates[0]; } } return null; } }