厂家可在钉钉 AI 卡片内直接确认月度货款,确认结果签名回传并在财务端实时展示。 Co-authored-by: 苏木 <594326199@qq.com> Co-committed-by: 苏木 <594326199@qq.com>
82 lines
3.3 KiB
PHP
82 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Business;
|
|
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Modules\EcommerceFinance\Services\SupplierSummaryAICard;
|
|
use Modules\EcommerceFinance\Services\SupplierSummaryConfirmation;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Throwable;
|
|
|
|
/**
|
|
* 钉钉 AI 卡片 HTTP 回传入口。DingTalk 的签名头用于校验请求来源。
|
|
*/
|
|
class SupplierSummaryCardCallback extends Controller
|
|
{
|
|
public function __construct(
|
|
private readonly SupplierSummaryAICard $summaryAICard,
|
|
private readonly SupplierSummaryConfirmation $confirmations,
|
|
) {
|
|
}
|
|
|
|
public function __invoke(Request $request): JsonResponse
|
|
{
|
|
$this->summaryAICard->assertValidCallbackSignature($request);
|
|
|
|
if (trim((string) $request->input('type', '')) !== 'actionCallback') {
|
|
return response()->json(['success' => false, 'message' => '不支持的钉钉回调类型。'], Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
}
|
|
$outTrackId = trim((string) $request->input('outTrackId', ''));
|
|
$companyId = $this->confirmations->companyIdFromOutTrackId($outTrackId);
|
|
if ($companyId === null) {
|
|
return response()->json(['success' => false, 'message' => '确认卡片标识无效。'], Response::HTTP_NOT_FOUND);
|
|
}
|
|
$dingTalkUserId = trim((string) $request->input('userId', ''));
|
|
if ($dingTalkUserId === '') {
|
|
return response()->json(['success' => false, 'message' => '钉钉确认人缺失。'], Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
}
|
|
|
|
$content = $request->input('content', []);
|
|
if (is_string($content)) {
|
|
$decoded = json_decode($content, true);
|
|
$content = is_array($decoded) ? $decoded : [];
|
|
}
|
|
$params = is_array($content) ? data_get($content, 'cardPrivateData.params', []) : [];
|
|
if (is_string($params)) {
|
|
$decoded = json_decode($params, true);
|
|
$params = is_array($decoded) ? $decoded : [];
|
|
}
|
|
if (! is_array($params) || trim((string) ($params['action'] ?? '')) !== 'confirm') {
|
|
return response()->json(['success' => false, 'message' => '不支持的卡片操作。'], Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
}
|
|
|
|
$record = $this->confirmations->find($outTrackId, $companyId);
|
|
if ($record === null) {
|
|
return response()->json(['success' => false, 'message' => '确认记录不存在。'], Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
$result = $this->confirmations->confirm(
|
|
$outTrackId,
|
|
$companyId,
|
|
$dingTalkUserId,
|
|
trim((string) $request->input('corpId', '')),
|
|
);
|
|
// 重复回调也使用同一个 outUpdateId 重试卡片状态,避免首次回写卡片
|
|
// 短暂失败后按钮一直停留在“厂家确认”,财务确认记录本身保持幂等。
|
|
try {
|
|
$this->summaryAICard->updateConfirmed($result['record']);
|
|
} catch (Throwable $exception) {
|
|
report($exception);
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'confirmed' => true,
|
|
'newly_confirmed' => $result['newly_confirmed'],
|
|
'confirmed_at' => (string) ($result['record']['confirmed_at'] ?? ''),
|
|
]);
|
|
}
|
|
}
|