181 lines
6.9 KiB
PHP
181 lines
6.9 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Business;
|
||
|
||
use Illuminate\Http\RedirectResponse;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Routing\Controller;
|
||
use Modules\EcommerceFinance\Services\SupplierNegativeAlertDingTalkWorkflow;
|
||
use Modules\EcommerceFinance\View\SupplierNegativeAlertPageData;
|
||
use RuntimeException;
|
||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||
use Throwable;
|
||
|
||
class SupplierNegativeAlertDingTalkActions extends Controller
|
||
{
|
||
public function __construct(
|
||
private readonly SupplierNegativeAlertPageData $pageData,
|
||
private readonly SupplierNegativeAlertDingTalkWorkflow $workflow,
|
||
) {
|
||
$this->middleware('auth');
|
||
$this->middleware('company.identify');
|
||
}
|
||
|
||
public function saveRobot(Request $request): RedirectResponse
|
||
{
|
||
$data = $request->validate([
|
||
'dingtalk_webhook' => ['nullable', 'string', 'max:2048'],
|
||
'dingtalk_secret' => ['nullable', 'string', 'max:256'],
|
||
'dingtalk_group_name' => ['required', 'string', 'max:191'],
|
||
]);
|
||
|
||
$this->workflow->saveConfiguration(
|
||
(string) ($data['dingtalk_webhook'] ?? ''),
|
||
(string) ($data['dingtalk_secret'] ?? ''),
|
||
(string) $data['dingtalk_group_name'],
|
||
);
|
||
|
||
return back()->with('success', '供应商负数预警群机器人已保存。');
|
||
}
|
||
|
||
public function send(Request $request): RedirectResponse
|
||
{
|
||
$data = $request->validate([
|
||
'purchaser' => ['nullable', 'string', 'max:191'],
|
||
'month' => ['nullable', 'string', 'regex:/^\d{4}-\d{2}$/'],
|
||
'supplier' => ['nullable', 'string', 'max:191'],
|
||
'checker' => ['nullable', 'string', 'max:191'],
|
||
'settlement_method' => ['nullable', 'string', 'max:191'],
|
||
'handling' => ['nullable', 'in:,pending'],
|
||
]);
|
||
$purchaser = trim((string) ($data['purchaser'] ?? ''));
|
||
$filters = [
|
||
'month' => (string) ($data['month'] ?? ''),
|
||
'supplier' => (string) ($data['supplier'] ?? ''),
|
||
'checker' => (string) ($data['checker'] ?? ''),
|
||
'settlement_method' => (string) ($data['settlement_method'] ?? ''),
|
||
'purchaser' => $purchaser,
|
||
'handling' => (string) ($data['handling'] ?? ''),
|
||
];
|
||
$filteredRows = $this->pageData->rowsForFilters([
|
||
...$filters,
|
||
'purchaser' => '',
|
||
]);
|
||
$rows = $purchaser === ''
|
||
? $filteredRows
|
||
: array_values(array_filter(
|
||
$filteredRows,
|
||
static fn (array $row): bool => trim((string) ($row['purchaser'] ?? '')) === $purchaser,
|
||
));
|
||
if ($rows === []) {
|
||
return back()->withErrors([
|
||
'dingtalk_send' => '当前筛选没有可发送给该采购的供应商。',
|
||
]);
|
||
}
|
||
|
||
$companyId = (int) (company_id() ?: 1);
|
||
$rows = $this->workflow->unhandledRows($rows, $companyId);
|
||
if ($rows === []) {
|
||
return back()->withErrors([
|
||
'dingtalk_send' => '当前筛选中的供应商均已回传处理结果,无需重复发送。',
|
||
]);
|
||
}
|
||
|
||
try {
|
||
if ($purchaser === '') {
|
||
$result = $this->workflow->sendGrouped(
|
||
$rows,
|
||
$filters,
|
||
$companyId,
|
||
user_id() ? (int) user_id() : null,
|
||
);
|
||
} else {
|
||
$result = $this->workflow->send(
|
||
$rows,
|
||
$purchaser,
|
||
$filters,
|
||
$companyId,
|
||
user_id() ? (int) user_id() : null,
|
||
);
|
||
}
|
||
} catch (Throwable $exception) {
|
||
report($exception);
|
||
|
||
return back()->withErrors(['dingtalk_send' => '发送失败:' . $exception->getMessage()]);
|
||
}
|
||
|
||
if ($purchaser === '') {
|
||
$message = "已一键发送至{$result['group_name']}:{$result['purchaser_count']} 位采购,"
|
||
. "{$result['supplier_count']} 家供应商、{$result['row_count']} 条预警。";
|
||
if ($result['unassigned_supplier_count'] > 0) {
|
||
$message .= " 另有 {$result['unassigned_supplier_count']} 家供应商未分配采购,未发送。";
|
||
}
|
||
|
||
return back()->with('success', $message);
|
||
}
|
||
|
||
return back()->with('success', "已发送至{$result['group_name']}:采购 {$purchaser},"
|
||
. "{$result['supplier_count']} 家供应商、{$result['row_count']} 条预警。");
|
||
}
|
||
|
||
public function export(Request $request): StreamedResponse
|
||
{
|
||
$data = $this->pageData->exportData($request->query());
|
||
$fields = array_values(array_filter(
|
||
(array) ($data['fields'] ?? []),
|
||
static fn (array $field): bool => ($field['name'] ?? '') !== 'company',
|
||
));
|
||
$fields[] = ['name' => 'handling_result_meta', 'label' => '回传信息', 'type' => 'text'];
|
||
$rows = (array) ($data['rows'] ?? []);
|
||
$filters = (array) ($data['filters'] ?? []);
|
||
$period = trim((string) ($filters['month'] ?? '')) ?: '全部月份';
|
||
$filename = '供应商负数预警_' . $period . '_' . now()->format('Ymd_His') . '.csv';
|
||
|
||
return response()->streamDownload(function () use ($fields, $rows): void {
|
||
$stream = fopen('php://output', 'w');
|
||
if ($stream === false) {
|
||
throw new RuntimeException('无法创建供应商负数预警导出文件。');
|
||
}
|
||
|
||
fwrite($stream, "\xEF\xBB\xBF");
|
||
fputcsv($stream, array_map(
|
||
static fn (array $field): string => (string) ($field['label'] ?? ''),
|
||
$fields,
|
||
));
|
||
|
||
foreach ($rows as $row) {
|
||
$values = [];
|
||
foreach ($fields as $field) {
|
||
$name = (string) ($field['name'] ?? '');
|
||
$value = $row[$name] ?? '';
|
||
if ($name === 'handling_result' && trim((string) $value) === '') {
|
||
$value = '采购未回传';
|
||
} elseif (is_array($value)) {
|
||
$value = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||
}
|
||
$values[] = $this->csvCell($value);
|
||
}
|
||
fputcsv($stream, $values);
|
||
}
|
||
|
||
fclose($stream);
|
||
}, $filename, [
|
||
'Content-Type' => 'text/csv; charset=UTF-8',
|
||
'Cache-Control' => 'private, no-store',
|
||
]);
|
||
}
|
||
|
||
private function csvCell(mixed $value): string
|
||
{
|
||
$text = trim((string) $value);
|
||
if ($text === '' || is_numeric($text)) {
|
||
return $text;
|
||
}
|
||
if (preg_match('/^\d{12,}$/', $text) === 1) {
|
||
return "'" . $text;
|
||
}
|
||
|
||
return preg_match('/^[=+@\t\r]/u', $text) === 1 ? "'" . $text : $text;
|
||
}
|
||
}
|