validate([ 'month' => ['required', 'date_format:Y-m', 'after_or_equal:2000-01'], 'row_key' => ['required', 'regex:/^[a-f0-9]{64}$/'], 'courier' => ['required', 'string', 'max:191'], ]); // 重新读取候选,禁止提交任意快递名称或其他公司的包裹。 $found = false; foreach ($data->rows(['month' => $input['month']]) as $row) { if ($row['selection_key'] !== $input['row_key']) continue; $found = in_array($input['courier'], array_column($row['courier_candidates'], 'courier'), true); break; } abort_unless($found, 422, '该快递已不在当前首发候选中,请刷新后重新选择。'); $store->save((int) company_id(), $input['month'], $input['row_key'], $input['courier'], mb_substr((string) user()->name, 0, 191)); return response()->json(['message' => '扣款快递已保存。']); } public function export(AccessoryReshipPageData $data) { $filters = $data->filters(); // 先完成读取,失败时返回正常错误,避免下载半份扣款清单。 $file = tmpfile(); if ($file === false) abort(500, '无法创建导出文件。'); fwrite($file, "\xEF\xBB\xBF"); fputcsv($file, ['交易单号','补发快递单号','补发快递','补发时间','原始条形码','处理后条形码','补发运费','匹配状态','首发快递公司(候选)','首发快递单号(候选)','首发所属月份(候选)','扣款比例(%)','扣款金额','说明']); foreach ($data->rows($filters) as $row) { if (!AccessoryReshipPageData::inCategory($row, $filters['match_status'])) continue; $values = [$row['trade_no'], $row['express_no'], ($row['express_name1'] ?: ($row['express_name2'] ?? '')), $row['ship_time'], $row['barcode'], $row['normalized_barcode'], $row['freight'], $row['deduction_state'] === 'ready' ? '可扣款' : ($row['status'] === 'matched' ? '已匹配待核对' : '未匹配不扣款'), implode(' / ', array_column($row['matches'], 'courier')), implode(' / ', array_column($row['matches'], 'express_no')), implode(' / ', array_column($row['matches'], 'month')), $row['deduction_rate_basis_points'] === null ? '' : number_format($row['deduction_rate_basis_points'] / 100, 2, '.', '') . '%', $row['deduction_cents'] === null ? '' : number_format($row['deduction_cents'] / 100, 2, '.', ''), $row['deduction_note']]; fputcsv($file, array_map(static function ($value) { $value = (string) $value; return preg_match('/^[=+\-@\t\r\n]/u', $value) ? "'" . $value : $value; }, $values)); } rewind($file); return response()->streamDownload(function () use ($file) { fpassthru($file); fclose($file); }, '配件补发扣款-' . $filters['month'] . '.csv', ['Content-Type' => 'text/csv; charset=UTF-8']); } }