'扣款比例须为0至100的数字,最多两位小数。']); } [$whole, $decimal] = array_pad(explode('.', $percent, 2), 2, ''); $points = (int) $whole * 100 + (int) str_pad($decimal, 2, '0'); if ($points > 10000) { throw ValidationException::withMessages(['rate_percent' => '扣款比例不能超过100%。']); } return $points; } public static function amount(int $freightCents, int $basisPoints): int { return intdiv($freightCents * $basisPoints + 5000, 10000); } /** 名称精确匹配;不默认比例,不对多候选累计运费。 */ public function apply(array $row, array $configs, ?string $selectedCourier = null): array { // 同名快递只保留一个首发包裹;不同名称必须由业务选择,不能按比例猜归属。 $candidates = []; foreach ($row['matches'] as $match) { $name = trim((string) $match['courier']); $candidates[$name] ??= array_replace($match, ['courier' => $name]); } $row['courier_candidates'] = array_values($candidates); $selected = $selectedCourier !== null ? ($candidates[$selectedCourier] ?? null) : null; if (count($candidates) === 1) $selected = reset($candidates); $row['selected_courier'] = $selected['courier'] ?? null; $row['matches'] = $selected === null ? array_values($candidates) : [$selected]; $row['deduction_cents'] = $row['status'] === 'unmatched' ? 0 : null; $row['deduction_rate_basis_points'] = null; $row['deduction_state'] = 'unmatched'; $row['deduction_note'] = '三个月内未匹配首发快递单号'; $reshipCourier = trim((string) (($row['express_name1'] ?? '') ?: ($row['express_name2'] ?? ''))); if (in_array($reshipCourier, ['外采快递', '线下快递'], true)) { $row['deduction_cents'] = 0; $row['deduction_state'] = 'excluded_courier'; $row['deduction_note'] = '补发快递为' . $reshipCourier . ',不参与扣款'; return $row; } if ($row['status'] === 'unmatched') { return $row; } if ($selected === null) { $row['deduction_state'] = 'selection_required'; $row['deduction_note'] = '请选择需要扣款的首发快递,补发运费仅计一次'; return $row; } $rates = []; $missing = false; foreach ($row['matches'] as &$match) { $config = $configs[trim((string) $match['courier'])] ?? null; $match['rate_basis_points'] = $config['rate_basis_points'] ?? null; $match['courier_code'] = $config['courier_code'] ?? null; $match['deduction_cents'] = $config !== null && $row['freight_cents'] !== null ? self::amount($row['freight_cents'], (int) $config['rate_basis_points']) : null; if ($config === null) { $missing = true; } else { $rates[] = (int) $config['rate_basis_points']; } } unset($match); if ($missing) { $row['deduction_state'] = 'missing_config'; $row['deduction_note'] = '首发快递未配置扣款比例,暂不计入扣款合计'; } elseif ($row['freight_cents'] === null) { $row['deduction_state'] = 'invalid_amount'; $row['deduction_note'] = '补发运费缺失或异常,待核实'; } else { $rate = $rates[0]; $row['deduction_rate_basis_points'] = $rate; $row['deduction_cents'] = self::amount($row['freight_cents'], $rate); $row['deduction_state'] = $rate === 0 ? 'zero_rate' : 'ready'; $row['deduction_note'] = $rate === 0 ? '扣款比例0%,不扣款' : '按所选首发快递配置比例核算,仅计一次'; if ($rate > 0 && $row['deduction_cents'] === 0) { $row['deduction_state'] = 'zero_amount'; $row['deduction_note'] = '扣款金额为0,不扣款'; } } return $row; } }