修改审批流程模块儿
This commit is contained in:
@@ -128,7 +128,7 @@ class PurchaseOrdersController extends BaseController
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceResubmit($request, $request->all());
|
||||
return $raw === true ? $this->success('提交成功') : $this->error('提交失败');
|
||||
return $this->success($raw);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ class ApprovalInstances extends Model
|
||||
'current_step',
|
||||
'finished_at',
|
||||
'deadline_at',
|
||||
'round'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
||||
@@ -57,6 +57,7 @@ class ApprovalRecords extends Model
|
||||
'status',
|
||||
'comment',
|
||||
'approved_at',
|
||||
'round'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
||||
@@ -166,7 +166,6 @@ class PurchaseOrdersService
|
||||
case 'index':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'show':
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'] ?? 0;
|
||||
break;
|
||||
@@ -214,13 +213,15 @@ class PurchaseOrdersService
|
||||
*/
|
||||
protected function afterServiceStore($res)
|
||||
{
|
||||
if ($res->status == 1) {
|
||||
$this->startApproval($res, ['resubmitted'=>0]);
|
||||
}
|
||||
// if ($res->status == 1) {
|
||||
// $this->startApproval($res, ['resubmitted'=>0]);
|
||||
// }
|
||||
|
||||
$this->startApproval($res, ['resubmitted'=>0]);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function startApproval($item, $formData)
|
||||
public function startApproval($item)
|
||||
{
|
||||
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
$appro->start('purchase_orders', 'purchase_orders', $item->id, ['resubmitted'=>0], $item->buyer_id);
|
||||
@@ -229,20 +230,45 @@ class PurchaseOrdersService
|
||||
|
||||
public function serviceResubmit(Request $request, array $data = [])
|
||||
{
|
||||
$info = $this->logicShow($this->buildQueryConfig($request, 'show'));
|
||||
if ($info->status == 3) {
|
||||
$instance = \app\common\model\ApprovalInstances::where('biz_id', $info->id)->where('flow_type', 'purchase_orders')->first();
|
||||
if ( $instance === null) {
|
||||
new BusinessException('未找到审批实例');
|
||||
}
|
||||
// 审批服务
|
||||
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
// 重新提交
|
||||
$appro->resubmit($instance->id, $instance->initiator_id, ['resubmitted'=>1], $data['remark']);
|
||||
// 添加到讨论
|
||||
$appro->postDiscussion($instance->id, $instance->initiator_id, $data['remark'], true, [], 'name');
|
||||
return true;
|
||||
$p = $request->all();
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['buyer_id'] = $request->user->uid;
|
||||
$info = $this->logicShow($config);
|
||||
if ($info === null) {
|
||||
throw new BusinessException('未找到采购单');
|
||||
}
|
||||
return false;
|
||||
if ($info->status != 3) {
|
||||
throw new BusinessException('该状态不能重新提交');
|
||||
}
|
||||
$instance = \app\common\model\ApprovalInstances::where('biz_id', $info->id)->where('flow_type', 'purchase_orders')->first();
|
||||
if ( $instance === null) {
|
||||
throw new BusinessException('未找到审批实例');
|
||||
}
|
||||
// 审批服务
|
||||
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
// 重新提交
|
||||
$result = $appro->resubmit($instance->id, $instance->initiator_id, ['resubmitted'=>1], $data['remark']);
|
||||
// 添加到讨论
|
||||
if (!empty($data['remark'])) {
|
||||
$appro->postDiscussion($instance->id, $instance->initiator_id, $data['remark'], false, [], 'name');
|
||||
}
|
||||
|
||||
$info->status = 1;
|
||||
$info->save();
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function updateStatus(array $data = [])
|
||||
{
|
||||
|
||||
$info = PurchaseOrders::where('id', $data['id'])->first();
|
||||
if ($info === null) {
|
||||
throw new BusinessException('未找到采购单');
|
||||
}
|
||||
$info->status = $data['status'];
|
||||
return $info->save();
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ class ApprovalFlowService
|
||||
'initiator_id' => $initiatorId,
|
||||
'status' => 'processing',
|
||||
'current_step' => $firstIndex,
|
||||
'round' => 1,
|
||||
'deadline_at' => $deadlineAt,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
@@ -50,16 +51,15 @@ class ApprovalFlowService
|
||||
'flow_type' => $flowType,
|
||||
'biz_type' => $bizType,
|
||||
'biz_id' => $bizId,
|
||||
'round' => 1,
|
||||
];
|
||||
|
||||
// 解析首步审批人(支持 role_id 或 roles.name)
|
||||
$approverIds = $this->resolveApprovers($firstStep, $instance, true);
|
||||
foreach ($approverIds as $uid) {
|
||||
$this->insertApprovalRecord($instanceId, $firstIndex, $uid);
|
||||
$this->insertApprovalRecord($instance, $firstIndex, $uid);
|
||||
}
|
||||
|
||||
// $this->sendNotification($approverIds, $instance, 'pending', false);
|
||||
|
||||
$extra = [];
|
||||
$submitNote = $formData['submit_note'] ?? '';
|
||||
if (is_string($submitNote) && $submitNote !== '') {
|
||||
@@ -84,8 +84,6 @@ class ApprovalFlowService
|
||||
$instance = Db::table('approval_instances')->where('id', $instanceId)->lockForUpdate()->first();
|
||||
if (!$instance) throw new BusinessException("审批实例未找到");
|
||||
if ($instance->status !== 'processing') {
|
||||
// return ['status' => 'noop', 'reason' => 'instance_not_processing', 'instance_status' => $instance->status];
|
||||
// throw new BusinessException("实例未处理");
|
||||
return ['status' => 'noop', 'msg' => '实例未处理'];
|
||||
}
|
||||
|
||||
@@ -94,12 +92,14 @@ class ApprovalFlowService
|
||||
|
||||
$steps = json_decode($flow->steps, true);
|
||||
$idx = (int)$instance->current_step;
|
||||
$round = (int)$instance->round;
|
||||
$step = $steps[$idx] ?? null;
|
||||
if (!$step) throw new BusinessException("当前步骤配置错误");
|
||||
|
||||
// 找到该用户在本步的 pending 记录(加锁)
|
||||
$pendingRecord = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('round', $round)
|
||||
->where('approver_id', $approverId)
|
||||
->where('step_index', $idx)
|
||||
->where('status', 'pending')
|
||||
@@ -110,21 +110,17 @@ class ApprovalFlowService
|
||||
// 已处理过?
|
||||
$anyRecord = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('round', $round)
|
||||
->where('approver_id', $approverId)
|
||||
->where('step_index', $idx)
|
||||
->first();
|
||||
if ($anyRecord && $anyRecord->status !== 'pending') {
|
||||
// return ['status' => 'noop', 'reason' => 'already_handled', 'record_status' => $anyRecord->status];
|
||||
// throw new BusinessException("已处理");
|
||||
return ['status' => 'noop', 'msg' => '已处理'];
|
||||
}
|
||||
// 步骤已推进
|
||||
if ((int)$instance->current_step !== $idx) {
|
||||
// return ['status' => 'noop', 'reason' => 'not_current_step', 'current_step' => (int)$instance->current_step];
|
||||
// throw new BusinessException("非当前步骤");
|
||||
return ['status' => 'noop', 'msg' => '非当前审批'];
|
||||
}
|
||||
// return ['status' => 'noop', 'reason' => 'no_pending_record'];
|
||||
return ['status' => 'noop', 'msg' => '无待处理记录'];
|
||||
}
|
||||
|
||||
@@ -139,18 +135,22 @@ class ApprovalFlowService
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
// 异步生成pdf文件 9.11 add
|
||||
if ($action === 'approve') {
|
||||
\Webman\RedisQueue\Redis::send('stock-order-pdf', ['id'=>$instance->biz_id]);
|
||||
}
|
||||
// 异步审批回调 9.23 add
|
||||
$approvalcallback = [
|
||||
'biz_id' => $instance->biz_id,
|
||||
'flow_type' => $instance->flow_type,
|
||||
'instance_id' => $instance->id,
|
||||
'initiator_id' => $instance->initiator_id,
|
||||
'status' => $action
|
||||
];
|
||||
\Webman\RedisQueue\Redis::send('approval-callback', $approvalcallback);
|
||||
|
||||
// 2) 聚合本步结论(any / all)
|
||||
$typeRaw = strtolower($step['type'] ?? 'all');
|
||||
$type = in_array($typeRaw, ['any','all']) ? $typeRaw : 'all';
|
||||
$outcome = $this->getStepOutcome($instanceId, $idx, $type); // 'pending' | 'approve' | 'reject'
|
||||
$outcome = $this->getStepOutcome($instanceId, $round, $idx, $type); // 'pending' | 'approve' | 'reject'
|
||||
|
||||
if ($outcome === 'pending') {
|
||||
// return ['status' => 'step_pending'];
|
||||
return ['status' => 'step_pending', 'msg' => '审批待定'];
|
||||
}
|
||||
|
||||
@@ -165,8 +165,7 @@ class ApprovalFlowService
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$this->sendNotification([$instance->initiator_id], $instance, 'reject', false);
|
||||
// return ['status' => 'completed', 'result' => 'reject'];
|
||||
return ['status' => 'completed', 'msg' => '已拒绝'];
|
||||
return ['status' => 'completed', 'msg' => '拒绝'];
|
||||
}
|
||||
|
||||
// 5) 通过 => 进入下一步或结束
|
||||
@@ -180,8 +179,7 @@ class ApprovalFlowService
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$this->sendNotification([$instance->initiator_id], $instance, 'approve', false);
|
||||
// return ['status' => 'completed', 'result' => 'approve'];
|
||||
return ['status' => 'completed', 'msg' => '已同意'];
|
||||
return ['status' => 'completed', 'msg' => '同意'];
|
||||
}
|
||||
|
||||
// 乐观推进 current_step
|
||||
@@ -191,7 +189,6 @@ class ApprovalFlowService
|
||||
->where('status', 'processing')
|
||||
->update(['current_step' => $nextIndex, 'updated_at' => $now]);
|
||||
if (!$affected) {
|
||||
// return ['status' => 'noop', 'reason' => 'concurrent_progressed'];
|
||||
return ['status' => 'noop', 'msg' => '并发进展'];
|
||||
}
|
||||
|
||||
@@ -199,12 +196,10 @@ class ApprovalFlowService
|
||||
$nextStep = $steps[$nextIndex];
|
||||
$nextApprovers = $this->resolveApprovers($nextStep, $instance, true);
|
||||
foreach ($nextApprovers as $uid) {
|
||||
$this->insertApprovalRecord($instanceId, $nextIndex, $uid);
|
||||
$this->insertApprovalRecord($instance, $nextIndex, $uid);
|
||||
}
|
||||
$this->sendNotification($nextApprovers, $instance, 'pending', false);
|
||||
$this->notifyCCs($nextStep, $instance, 'pending');
|
||||
|
||||
// return ['status' => 'next_step', 'step_name' => $nextStep['name'] ?? ('Step '.$nextIndex)];
|
||||
return ['status' => 'next_step', 'msg' => '进行下一步:'.$nextStep['name'] ?? ('Step '.$nextIndex)];
|
||||
});
|
||||
}
|
||||
@@ -253,6 +248,7 @@ class ApprovalFlowService
|
||||
$steps = json_decode($flow->steps, true) ?: [];
|
||||
$records = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('round', (int)$instance->round)
|
||||
->orderBy('step_index')->orderByRaw('COALESCE(approved_at, created_at) asc')
|
||||
->get()
|
||||
->groupBy('step_index');
|
||||
@@ -325,6 +321,7 @@ class ApprovalFlowService
|
||||
|
||||
Db::table('approval_records')
|
||||
->where('instance_id', $instance->id)
|
||||
->where('round', (int)$instance->round)
|
||||
->where('step_index', $instance->current_step)
|
||||
->where('status', 'pending')
|
||||
->update(['status' => 'timeout', 'approved_at' => $now, 'updated_at' => $now]);
|
||||
@@ -482,19 +479,19 @@ class ApprovalFlowService
|
||||
* any:有 reject => reject;否则有 approve => approve;否则 pending
|
||||
* all:有 reject => reject;有 pending => pending;否则(全 approved 或 approved+skipped/timeout)=> approve
|
||||
*/
|
||||
private function getStepOutcome(int $instanceId, int $stepIndex, string $type): string
|
||||
private function getStepOutcome(int $instanceId, int $round, int $stepIndex, string $type): string
|
||||
{
|
||||
$records = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('round', $round) // ★
|
||||
->where('step_index', $stepIndex)
|
||||
->get();
|
||||
|
||||
$pending = 0; $approved = 0; $rejected = 0;
|
||||
foreach ($records as $r) {
|
||||
if ($r->status === 'pending') { $pending++; }
|
||||
elseif ($r->status === 'approved'){ $approved++; }
|
||||
elseif ($r->status === 'rejected'){ $rejected++; }
|
||||
// skipped/timeout 不影响聚合结论
|
||||
if ($r->status === 'pending') $pending++;
|
||||
elseif ($r->status === 'approved') $approved++;
|
||||
elseif ($r->status === 'rejected') $rejected++;
|
||||
}
|
||||
|
||||
$type = strtolower($type);
|
||||
@@ -503,18 +500,18 @@ class ApprovalFlowService
|
||||
if ($approved > 0) return 'approve';
|
||||
return 'pending';
|
||||
}
|
||||
// all
|
||||
if ($rejected > 0) return 'reject';
|
||||
if ($pending > 0) return 'pending';
|
||||
return $approved > 0 ? 'approve' : 'pending';
|
||||
}
|
||||
|
||||
/** 关闭本步其余待办为 skipped */
|
||||
private function closeOtherPending(int $instanceId, int $stepIndex, array $keepApproverIds = []): void
|
||||
private function closeOtherPending(int $instanceId, int $round, int $stepIndex, array $keepApproverIds = []): void
|
||||
{
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$q = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('round', $round) // ★
|
||||
->where('step_index', $stepIndex)
|
||||
->where('status', 'pending');
|
||||
|
||||
@@ -524,59 +521,32 @@ class ApprovalFlowService
|
||||
}
|
||||
|
||||
/** 创建待办(去重) */
|
||||
private function insertApprovalRecord(int $instanceId, int $stepIndex, int $approverId): void
|
||||
private function insertApprovalRecord(object $instance, int $stepIndex, int $approverId): void
|
||||
{
|
||||
$round = (int)($instance->round ?? 1);
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
$exists = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('instance_id', (int)$instance->id)
|
||||
->where('round', $round) // ★ 限当前轮
|
||||
->where('step_index', $stepIndex)
|
||||
->where('approver_id', $approverId)
|
||||
->count() > 0;
|
||||
if (!$exists) {
|
||||
Db::table('approval_records')->insert([
|
||||
'instance_id' => $instanceId,
|
||||
'approver_id' => $approverId,
|
||||
'step_index' => $stepIndex,
|
||||
'action' => null,
|
||||
'status' => 'pending',
|
||||
'comment' => null,
|
||||
'approved_at' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
->where('status', 'pending')
|
||||
->exists();
|
||||
|
||||
/** 发送通知(接你自己的消息系统即可) */
|
||||
private function sendNotification2(array $userIds, object $instance, string $action, bool $isCC): void
|
||||
{
|
||||
$map = [
|
||||
'pending' => '待审批',
|
||||
'approve' => '已通过',
|
||||
'reject' => '已拒绝',
|
||||
'revoked' => '已撤回'
|
||||
];
|
||||
$prefix = $isCC ? '【抄送】' : '【审批】';
|
||||
$text = $map[$action] ?? $action;
|
||||
if ($exists) return;
|
||||
|
||||
$approvalType = array_flip(\app\common\service\SysDictService::pluckKeyValueByCode('approval_type'));
|
||||
|
||||
switch ($instance->flow_type) {
|
||||
case 'stock_orders': // 备货单
|
||||
$stockOrder = \app\common\model\StockOrders::find($instance->biz_id);
|
||||
$title = $prefix."备货单:{$stockOrder->order_no}";
|
||||
$flowType = $approvalType[$instance->flow_type];
|
||||
$content = "{$prefix}你有一条审批 {$text}:类型 {$flowType},业务单号 {$stockOrder->order_no}";
|
||||
break;
|
||||
case 'stock_orders_nullify': // 备货单作废
|
||||
break;
|
||||
}
|
||||
|
||||
noticePush([
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'recipient' => $userIds,
|
||||
'email' => 1
|
||||
Db::table('approval_records')->insert([
|
||||
'instance_id' => (int)$instance->id,
|
||||
'approver_id' => $approverId,
|
||||
'step_index' => $stepIndex,
|
||||
'round' => $round, // ★
|
||||
'action' => null,
|
||||
'status' => 'pending',
|
||||
'comment' => null,
|
||||
'approved_at' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -815,100 +785,6 @@ class ApprovalFlowService
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 极简:审批实例的时间轴(只返回每一步的总状态)
|
||||
*
|
||||
* @param int $instanceId
|
||||
* @return array<int, array{index:int,name:string,type:string,status:string}>
|
||||
*/
|
||||
public function getSimpleTimeline1(int $instanceId): array
|
||||
{
|
||||
// 基础数据
|
||||
$instance = Db::table('approval_instances')->where('id', $instanceId)->first();
|
||||
if (!$instance) throw new BusinessException('审批实例未找到');
|
||||
$flow = Db::table('approval_flows')->where('type', $instance->flow_type)->first();
|
||||
if (!$flow) throw new BusinessException('审批流程定义未找到');
|
||||
|
||||
$steps = json_decode($flow->steps, true) ?: [];
|
||||
$formData = json_decode($instance->form_data ?? '{}', true) ?: [];
|
||||
$currentStep = (int)$instance->current_step;
|
||||
|
||||
// 读出所有记录并分组
|
||||
$records = Db::table('approval_records as ar')
|
||||
->where('ar.instance_id', $instanceId)
|
||||
->orderBy('ar.step_index')
|
||||
->orderByRaw('COALESCE(ar.approved_at, ar.created_at) asc')
|
||||
->select('ar.*')
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$byStep = [];
|
||||
foreach ($records as $r) {
|
||||
$idx = (int)$r->step_index;
|
||||
$byStep[$idx][] = $r;
|
||||
}
|
||||
|
||||
$timeline = [];
|
||||
|
||||
foreach ($steps as $i => $meta) {
|
||||
$name = $meta['name'] ?? ('Step '.$i);
|
||||
$typeRaw = strtolower($meta['type'] ?? 'all');
|
||||
$type = in_array($typeRaw, ['any','all']) ? $typeRaw : 'all';
|
||||
$condStr = $meta['condition'] ?? null;
|
||||
$condOk = $condStr ? $this->evaluateCondition($condStr, $formData) : true;
|
||||
|
||||
$recs = $byStep[$i] ?? [];
|
||||
$hasRecs = !empty($recs);
|
||||
|
||||
// 默认状态
|
||||
$status = 'pending';
|
||||
|
||||
if ($hasRecs) {
|
||||
// 统计是否全部 timeout(且无 approve/reject/pending)
|
||||
$cnt = ['pending'=>0,'approved'=>0,'rejected'=>0,'timeout'=>0];
|
||||
foreach ($recs as $rr) {
|
||||
if (isset($cnt[$rr->status])) $cnt[$rr->status]++;
|
||||
}
|
||||
|
||||
// 用已有的聚合规则拿到结论
|
||||
$outcome = $this->getStepOutcome($instanceId, $i, $type); // 'pending'|'approve'|'reject'
|
||||
|
||||
if ($outcome === 'reject') {
|
||||
$status = 'rejected';
|
||||
} elseif ($outcome === 'approve') {
|
||||
$status = 'approved';
|
||||
} else {
|
||||
// 没有结论,再看是不是纯超时
|
||||
if ($cnt['timeout'] > 0 && $cnt['approved'] === 0 && $cnt['rejected'] === 0 && $cnt['pending'] === 0) {
|
||||
$status = 'timeout';
|
||||
} else {
|
||||
$status = 'processing';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 无记录:根据位置与条件判断展示
|
||||
if ($i < $currentStep) {
|
||||
$status = $condOk ? 'approved' : 'skipped';
|
||||
} elseif ($i === $currentStep && $instance->status === 'processing') {
|
||||
// 理论上当前步应有记录;防御性展示为 processing
|
||||
$status = 'processing';
|
||||
} else {
|
||||
$status = $condOk ? 'pending' : 'skipped';
|
||||
}
|
||||
}
|
||||
|
||||
$timeline[] = [
|
||||
'index' => (int)$i,
|
||||
'name' => $name,
|
||||
'type' => $type, // any | all
|
||||
'status' => $status, // approved | rejected | processing | pending | skipped | timeout
|
||||
];
|
||||
}
|
||||
|
||||
return $timeline;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 极简时间轴(含每步时间 & 申请人信息)
|
||||
*
|
||||
@@ -944,6 +820,7 @@ class ApprovalFlowService
|
||||
$steps = json_decode($flow->steps, true) ?: [];
|
||||
$formData = json_decode($instance->form_data ?? '{}', true) ?: [];
|
||||
$curStep = (int)$instance->current_step;
|
||||
$round = (int)$instance->round;
|
||||
|
||||
// 申请人
|
||||
$initiatorId = (int)$instance->initiator_id;
|
||||
@@ -955,6 +832,7 @@ class ApprovalFlowService
|
||||
// 审批记录
|
||||
$records = Db::table('approval_records as ar')
|
||||
->where('ar.instance_id', $instanceId)
|
||||
->where('ar.round', $round)
|
||||
->orderBy('ar.step_index')
|
||||
->orderByRaw('COALESCE(ar.approved_at, ar.created_at) asc')
|
||||
->select('ar.*')
|
||||
@@ -1027,7 +905,7 @@ class ApprovalFlowService
|
||||
$startedAt = $minCreated;
|
||||
|
||||
// 总结果
|
||||
$outcome = $this->getStepOutcome($instanceId, $i, $type); // 'pending'|'approve'|'reject'
|
||||
$outcome = $this->getStepOutcome($instanceId, $round, $i, $type); // 'pending'|'approve'|'reject'
|
||||
if ($outcome === 'reject') {
|
||||
$status = 'rejected';
|
||||
$finishedAt = $minRejectAt;
|
||||
@@ -1135,6 +1013,7 @@ class ApprovalFlowService
|
||||
}
|
||||
$steps = json_decode($flow->steps, true) ?: [];
|
||||
$idx = (int)$instance->current_step;
|
||||
$round = (int)$instance->round;
|
||||
$meta = $steps[$idx] ?? [];
|
||||
|
||||
$typeRaw = strtolower($meta['type'] ?? 'all');
|
||||
@@ -1148,6 +1027,7 @@ class ApprovalFlowService
|
||||
$pendingRows = Db::table('approval_records as ar')
|
||||
->leftJoin('user as u', 'ar.approver_id', '=', 'u.id')
|
||||
->where('ar.instance_id', $instance->id)
|
||||
->where('ar.round', $round)
|
||||
->where('ar.step_index', $idx)
|
||||
->where('ar.status', 'pending')
|
||||
->select('ar.approver_id', Db::raw("u.`{$userNameColumn}` as approver_name"))
|
||||
@@ -1156,6 +1036,7 @@ class ApprovalFlowService
|
||||
} else {
|
||||
$pendingRows = Db::table('approval_records')
|
||||
->where('instance_id', $instance->id)
|
||||
->where('round', $round)
|
||||
->where('step_index', $idx)
|
||||
->where('status', 'pending')
|
||||
->select('approver_id')
|
||||
@@ -1176,6 +1057,7 @@ class ApprovalFlowService
|
||||
// 先快速统计是否纯 timeout
|
||||
$stats = Db::table('approval_records')
|
||||
->where('instance_id', $instance->id)
|
||||
->where('round', $round)
|
||||
->where('step_index', $idx)
|
||||
->selectRaw("SUM(CASE WHEN status='pending' THEN 1 ELSE 0 END) as c_pending")
|
||||
->selectRaw("SUM(CASE WHEN status='approved' THEN 1 ELSE 0 END) as c_approved")
|
||||
@@ -1246,10 +1128,14 @@ class ApprovalFlowService
|
||||
->where('status', 'pending')
|
||||
->update(['status'=>'skipped','approved_at'=>$now,'updated_at'=>$now]);
|
||||
|
||||
// ★ 轮次 +1
|
||||
$newRound = ((int)$instance->round) + 1;
|
||||
|
||||
// 重新开启实例
|
||||
Db::table('approval_instances')->where('id', $instanceId)->update([
|
||||
'status' => 'processing',
|
||||
'current_step' => $firstIndex,
|
||||
'round' => $newRound,
|
||||
'form_data' => json_encode($formData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
'finished_at' => null,
|
||||
'deadline_at' => $deadlineAt,
|
||||
@@ -1265,12 +1151,13 @@ class ApprovalFlowService
|
||||
'initiator_id' => (int)$instance->initiator_id,
|
||||
'biz_type' => (string)$instance->biz_type,
|
||||
'biz_id' => (string)$instance->biz_id,
|
||||
'round' => $newRound,
|
||||
];
|
||||
$approvers = $this->resolveApprovers($firstStep, $instanceLite, true);
|
||||
if (empty($approvers)) throw new BusinessException('重提后首步未解析到审批人');
|
||||
|
||||
foreach ($approvers as $uid) {
|
||||
$this->insertApprovalRecord($instanceId, $firstIndex, (int)$uid);
|
||||
$this->insertApprovalRecord($instanceLite, $firstIndex, (int)$uid);
|
||||
}
|
||||
|
||||
$extra = $appealText !== '' ? ['appeal' => $appealText] : [];
|
||||
@@ -1469,6 +1356,7 @@ class ApprovalFlowService
|
||||
// 锁定来源人的 pending 记录(必须是“自己名下”的记录)
|
||||
$record = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('round', (int)$instance->round)
|
||||
->where('step_index', $stepIndex)
|
||||
->where('approver_id', $fromUserId)
|
||||
->where('status', 'pending')
|
||||
@@ -1484,6 +1372,7 @@ class ApprovalFlowService
|
||||
// 若目标人在本步已有 pending,合并:本记录设为 skipped,保留目标那条
|
||||
$target = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('round', (int)$instance->round)
|
||||
->where('step_index', $stepIndex)
|
||||
->where('approver_id', $toUserId)
|
||||
->where('status', 'pending')
|
||||
@@ -1583,6 +1472,7 @@ class ApprovalFlowService
|
||||
// 锁定来源人的 pending 记录
|
||||
$record = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('round', (int)$instance->round)
|
||||
->where('step_index', $stepIndex)
|
||||
->where('approver_id', $fromUserId)
|
||||
->where('status', 'pending')
|
||||
@@ -1595,6 +1485,7 @@ class ApprovalFlowService
|
||||
// 若目标已有 pending:合并(本记录置为 skipped)
|
||||
$target = Db::table('approval_records')
|
||||
->where('instance_id', $instanceId)
|
||||
->where('round', (int)$instance->round)
|
||||
->where('step_index', $stepIndex)
|
||||
->where('approver_id', $toUserId)
|
||||
->where('status', 'pending')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -101,8 +101,10 @@ class IndexController
|
||||
|
||||
public function test(Request $request)
|
||||
{
|
||||
$service = new \app\crm\service\StockOrdersService();
|
||||
$result = $service->createdPdfFile(35);
|
||||
|
||||
$info = \app\common\model\PurchaseOrders::find(14);
|
||||
$service = new \app\common\service\PurchaseOrdersService();
|
||||
$result = $service->startApproval($info);
|
||||
|
||||
return json($result);
|
||||
}
|
||||
|
||||
+2
-1
@@ -119,7 +119,8 @@ if (!function_exists('flg')) {
|
||||
if ($isFs) {
|
||||
$data = [
|
||||
'content' => $eventData,
|
||||
'time' => date('Y-m-d H:i:s', time())
|
||||
'time' => date('Y-m-d H:i:s', time()),
|
||||
'source' => getenv('ENVIRONMENT')
|
||||
];
|
||||
RedisQueueRedis::send("server", $data);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace app\queue\redis;
|
||||
|
||||
use support\exception\BusinessException;
|
||||
use Webman\RedisQueue\Consumer;
|
||||
|
||||
class ApprovalCallback implements Consumer
|
||||
{
|
||||
// 要消费的队列名
|
||||
public $queue = 'approval-callback';
|
||||
|
||||
// 连接名,对应 plugin/webman/redis-queue/redis.php 里的连接`
|
||||
public $connection = 'default';
|
||||
|
||||
// 消费
|
||||
public function consume($data)
|
||||
{
|
||||
try {
|
||||
match ($data['flow_type']) {
|
||||
'stock_orders' => $this->approvalStockOrders($data),
|
||||
'purchase_orders' => $this->approvalPurchaseOrders($data),
|
||||
default => throw new BusinessException('未知的审批类型,无法执行回调操作')
|
||||
};
|
||||
return true;
|
||||
} catch (\Throwable $th) {
|
||||
flg('审批回调异常:'.$th->getFile()."|".$th->getLine()."|".$th->getMessage(), false);
|
||||
throw new BusinessException($th->getFile()."|".$th->getLine()."|".$th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 消费失败回调
|
||||
/*
|
||||
$package = [
|
||||
'id' => 1357277951, // 消息ID
|
||||
'time' => 1709170510, // 消息时间
|
||||
'delay' => 0, // 延迟时间
|
||||
'attempts' => 2, // 消费次数
|
||||
'queue' => 'send-mail', // 队列名
|
||||
'data' => ['to' => 'tom@gmail.com', 'content' => 'hello'], // 消息内容
|
||||
'max_attempts' => 5, // 最大重试次数
|
||||
'error' => '错误信息' // 错误信息
|
||||
]
|
||||
*/
|
||||
public function onConsumeFailure(\Throwable $e, $package)
|
||||
{
|
||||
echo "consume failure\n";
|
||||
echo $e->getMessage() . "\n";
|
||||
// 无需反序列化
|
||||
var_export($package);
|
||||
}
|
||||
|
||||
/**
|
||||
* 备货单处理
|
||||
*/
|
||||
private function approvalStockOrders($data)
|
||||
{
|
||||
// 生成PDF文件
|
||||
$service = new \app\crm\service\StockOrdersService();
|
||||
$result = $service->createdPdfFile($data['biz_id']);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 采购单处理
|
||||
*/
|
||||
private function approvalPurchaseOrders($data)
|
||||
{
|
||||
$udata['id'] = $data['biz_id'];
|
||||
if ($data['status'] === 'approve') {
|
||||
$udata['status'] = 2;
|
||||
}
|
||||
|
||||
if ($data['status'] === 'reject') {
|
||||
$udata['status'] = 3;
|
||||
}
|
||||
|
||||
$service = new \app\common\service\PurchaseOrdersService();
|
||||
$result = $service->updateStatus($udata);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,12 @@ class Server implements Consumer
|
||||
public function consume($data)
|
||||
{
|
||||
try {
|
||||
$source = $data['source'] === 'development' ? '-- 开发环境 --' : '** 生产环境 **';
|
||||
$webhookUrl = 'https://open.feishu.cn/open-apis/bot/v2/hook/806c2e9d-6ca2-4345-a459-69bb2651706b';
|
||||
$message = "====== ======\n";
|
||||
$message .= $data['content']."\n";
|
||||
$message .= "时间:".date('Y-m-d H:i:s', time())."\n";
|
||||
$message .= "来源:".$source."\n";
|
||||
$message .= "====== ======";
|
||||
sendFeishuTextMessage($webhookUrl, $message);
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user