@Chiang
2019-09-21T16:35:36.000000Z
字数 10659
阅读 1080
SCM
参考文档
1.钉钉后台设置审批模板 form_component_values[1]
2.钉钉后台设置审批人流程 process_code[2]
3.系统调用钉钉开放平台审批流接口的业务流程
4.注册业务事件回调接口
1.安装 EasyDingTalk 包
$ composer require mingyoung/dingtalk:^2.0
2.基本参数设置
use EasyDingTalk\Application;
$config = [
/*
|-----------------------------------------------------------
| 【必填】企业 corpId
|-----------------------------------------------------------
*/
'corp_id' => 'xxxxxxxxxxx',
/*
|-----------------------------------------------------------
| 【必填】应用 AppKey
|-----------------------------------------------------------
*/
'app_key' => 'xxxxxxxxxxx',
/*
|-----------------------------------------------------------
| 【必填】应用 AppSecret
|-----------------------------------------------------------
*/
'app_secret' => 'xxxxxxxxxxx',
/*
|-----------------------------------------------------------
| 【选填】加解密
|-----------------------------------------------------------
| 此处的 `token` 和 `aes_key` 用于事件通知的加解密
| 如果你用到事件回调功能,需要配置该两项
*/
'token' => 'xxxxxxxxxxx',
'aes_key' => 'xxxxxxxxxxx',
/*
|-----------------------------------------------------------
| 【选填】后台免登配置信息
|-----------------------------------------------------------
| 如果你用到应用管理后台免登功能,需要配置该项
*/
'sso_secret' => 'xxxxxxxxxxx',
/*
|-----------------------------------------------------------
| 【选填】第三方网站 OAuth 授权
|-----------------------------------------------------------
| 如果你用到扫码登录、钉钉内免登和密码登录第三方网站,需要配置该项
*/
'oauth' => [
/*
|-------------------------------------------
| `app-01` 为你自定义的名称,不要重复即可
|-------------------------------------------
| 数组内需要配置 `client_id`, `client_secret`, `scope` 和 `redirect` 四项
|
| `client_id` 为钉钉登录应用的 `appId`
| `client_secret` 为钉钉登录应用的 `appSecret`
| `scope`:
| - 扫码登录第三方网站和密码登录第三方网站填写 `snsapi_login`
| - 钉钉内免登第三方网站填写 `snsapi_auth`
| `redirect` 为回调地址
*/
'app-01' => [
'client_id' => 'xxxxxxxxxxx',
'client_secret' => 'xxxxxxxxxxx',
'scope' => 'snsapi_login',
'redirect' => 'https://easydingtalk.org/callback',
],
/*
|-------------------------------------------
| 可配置多个 OAuth 应用,数组内内容同上
|-------------------------------------------
*/
'app-02' => [
// ...
]
]
];
$app = new Application($config);
/**
* 提交审批, 获取审批实例ID,保存
* @param $process_code 审批流的唯一码,process_code就在审批流编辑的页面URL中
* @param $originator_user_id 审批实例发起人的userid
* @param $dept_id 发起人所在的部门,如果发起人属于根部门,传-1
* @param $form_component_values 审批流表单参数
* @return mixed
*/
static function sendInstance($process_code, $originator_user_id, $dept_id, $form_component_values)
{
$params = [];
$params['process_code'] = $process_code;
$params['originator_user_id'] = $originator_user_id;
$params['dept_id'] = $dept_id;
$params['form_component_values'] = $form_component_values;
//发起审批,这里会返回实例ID
$app = new Application(config('ding.config'));
$data = $app->process->create($params);
if ($data['errcode'] == 0) {
return $data['process_instance_id'];
} else {
hawk($data['errmsg']);
}
}
/**
* 根据实例ID, 获取审批流程
* @param $id
* @return mixed
*/
static function getInstance($id)
{
// $id = '198d5cbd-918a-465c-81ab-512e33d5a0c6'; //实例ID
$app = new Application(config('ding.config'));
$data = $app->process->get($id);
return $data;
}
1.注册业务事件回调
/**
* 注册地址
* http://api.scm.test.kuaigang.net/api/ding/register
*/
public function registerInstance()
{
$params = [
'call_back_tag' => ['bpms_task_change', 'bpms_instance_change'],//这里是审批的标签
'url' => 'http://api.scm.test.kuaigang.net/api/ding/push',//这里是自己定义的回调推送地址
];
$app = new Application(config('ding.config'));
$app->callback->register($params);//注册
// $app->callback->update($params);//修改
// $app->callback->delete();//删除
// $app->callback->failed();//获取回调失败结果
$list = $app->callback->list();//列表
var_dump($list);die;
}
2.查询事件回调地址方法
- 这里需要注意的是由于我们注册业务事件回调的时候添加了两个审批标签所以这里会回调两次具体业务需要判断是哪一个审批标签的然后执行回写操作
/**
* 审批推送
* 事件推送自动更新审批列表
* 同时修改关联的主表状态
* 判断是否作废
* @return mixed
*/
public function pushInstance()
{
// 获取 server 实例
$app = new Application(config('ding.config'));
$server = $app->server;
// return $server->serve();//这里是验证回调地址返回success加密json
$server->push(function ($payload) {
// 此处 $payload 为钉钉推送事件解密后的内容,为数组形式
/**
* 比如测试回调 URL 事件,$payload 内容为:
*
* $payload = [
* "EventType" => "check_url",
* ]
*/
$type = $payload['EventType'];
Log::info(date('Y-m-d H:i:s').$type);
// ...
// 可根据内容处理你对应的业务逻辑
//审批实例ID
$process_instance_id = $payload['processInstanceId'];
//审批实例详情
$process_instance_details = $this->getInstance($process_instance_id);
try {
//1.这里写入ding_approval_list表中
$instance_obj = DB::table(config('alias.ding_approval_list'))->where(['process_instance_id' => $process_instance_id])->update(['instance_details' => json_encode($process_instance_details)]);
$bill_num = DB::table(config('alias.ding_approval_list'))->where([['process_instance_id', $process_instance_id],['status', 1]])->value('bill_num');
$bill_num_type = substr($bill_num, 0, 4);
//2.根据具体单据号 回写具体主表数据,各个模块写接口
if ($bill_num_type == 'XSJH') {
$sales_plan = new SalesPlan();
$sales_plan->backInstance($process_instance_details, $bill_num);
//判断审批状态,审批不通过执行回写接口,调用审批作废接口...
if ($process_instance_details['process_instance']['result'] == 'refuse') {
$data['bill_num'] = $bill_num;
$sales_plan->cancelInstance($data, 4);//审核不通过
}
}
//开票额度控制
if ($bill_num_type == 'KPED' && $type == 'bpms_instance_change' && $payload['type'] == 'finish' ) {
Ding::send( json_encode($payload) );
(new InvoiceLimitRecord())->checkCallBack($payload, $bill_num);
}
//todo...
// switch ($bill_num_type) {
// case 'XSJH':
// $sales_plan = new SalesPlan();
// $sales_plan->backInstance($process_instance_details, $bill_num);
//
// //判断审批状态,审批不通过执行回写接口,调用审批作废接口...
// if ($process_instance_details['process_instance']['result'] == 'refuse') {
// $data['bill_num'] = $bill_num;
// $sales_plan->cancelInstance($data, 4);//审核不通过
// }
//
// break;
//
// //todo ....
// }
} catch (QueryException $e) {
Log::info(date('Y-m-d H:i:s').'-钉钉回调error-'.$e->getMessage());
}
});
return $server->serve();
}
3.回调事件列表
如果注册回调事件时包含审批事件“bpms_task_change”,“bpms_instance_change”,当审批事件发生后,钉钉服务器会向回调url推送事件。
/**
* 审批
* 1.审批列表查询数据
* 2.有数据状态置0
* 3.没有添加数据,钉钉提交审批,获取审批详情,保存到审批列表
* 4.回写当前审批状态
* @param $input
*/
public function approve($input)
{
$user = obj2array($this->auth->getUser());
$this->validate($input,'approve');
//1.准备参数
$bill_num = $input['bill_num'];
// $process_code = ''; // 审批流的唯一码,process_code就在审批流编辑的页面URL中
// $originator_user_id = $user['originator_user_id']; // 审批实例发起人的userid
// $dept_id = $user['dept_id']; // 发起人所在的部门,如果发起人属于根部门,传-1
$process_code = config('ding.process_code'); // 审批流的唯一码,process_code就在审批流编辑的页面URL中
$originator_user_id = '084462401933296495'; // 审批实例发起人的userid
$dept_id = '3162029'; // 发起人所在的部门,如果发起人属于根部门,传-1
$form_component_values = [ // 审批流表单参数
['name' => '标题', 'value' => '222test销售计划标题'],
['name' => '描述', 'value' => '222test销售计划内容'],
['name' => '品名', 'value' => '222test销售计划内容'],
['name' => '材质', 'value' => '222test销售计划内容'],
['name' => '规格', 'value' => '222test销售计划内容'],
['name' => '产地', 'value' => '222test销售计划内容'],
['name' => '运输方式', 'value' => '222test销售计划内容'],
['name' => '发货方式', 'value' => '222test销售计划内容'],
['name' => '类型', 'value' => '222test销售计划内容'],
];
//2.钉钉提交审批,获取审批实例ID
$process_instance_id = Ding::sendInstance($process_code, $originator_user_id, $dept_id, $form_component_values);
//3.获取审批详情
$process_instance_details = Ding::getInstance($process_instance_id);
//4.存入审批列表
$time = date('Y-m-d H:i:s');
$data = [];
$data['bill_num'] = $bill_num;
$data['process_instance_id'] = $process_instance_id;
$data['instance_details'] = json_encode($process_instance_details);
$data['status'] = 1;
$data['instance_user_id'] = $user['user_id'];
$data['created_at'] = $time;
$data['updated_at'] = $time;
DB::beginTransaction();
try {
DB::table(config('alias.ding_approval_list'))->insert($data);
//5.回写当前审批状态
$this->backInstance($process_instance_details, $bill_num);
DB::commit();
} catch (QueryException $e) {
DB::rollBack();
hawk($e->getMessage());
}
return 1;
}
/**
* 审批流程
* 根据 bill_num查询审批列表数据
* @param $input
* @return mixed
*/
public function processApprove($input)
{
$this->validate($input,'approve');
$bill_num = $input['bill_num'];
$instance_details = DB::table(config('alias.ding_approval_list'))->where([['bill_num', $bill_num], ['status', 1]])->value('instance_details');
if (!$instance_details) {
hawk(config('error.restful.449'));
}
return $instance_details;
}
/**
* 审批作废
* 审批状态 1-未审 2-在审 3-已审 4-弃审 5-作废
* 主表审批状态改为作废,审批不通过
* 审批表里状态改为 => status=0
* @param $input
* @param int $status
* @return int
*/
public function cancelApprove($input, $status = 5)
{
$bill_num = $input['bill_num'];
//根据主表查出原有明细表数据数组
$details_id_tf_arr = DB::table($this->table_details)->where([['bill_num_sales_plan', $input['bill_num']], ['status', 1]])->pluck('id')->toArray();
//筛选出明细数据(判断数据是否可以编辑,weight_exec>0不可编辑,货齐不可编辑)
if ($this->tfEditCancelApprove($details_id_tf_arr, $input['bill_num'])) {hawk(config('error.restful.450'));}
$data = [];
$data['audit_type'] = $status;
DB::beginTransaction();
try {
//修改主表状态
DB::table($this->table)->where(['bill_num' => $bill_num])->update($data);
//修改审批表里的状态
DB::table(config('alias.ding_approval_list'))->where(['bill_num' => $bill_num])->update(['status' => 0]);
//todo 如果有引用,作废数据回写引用
DB::commit();
} catch (QueryException $e) {
DB::rollBack();
hawk($e->getMessage());
}
return 1;
}
/**
* 审批回写主表接口
* audit_type 审批状态
* audit_userid 审核人
* audit_date 审批时间
* audit_remark 审核备注
* @param $param
* @param $bill_num
*/
public function backInstance($param, $bill_num)
{
$data = [];
$audit_type = 2;//审批状态 1-未审 2-在审 3-已审 4-弃审 5-作废
$result = $param['process_instance']['result']; //审批结果,分为 agree 和 refuse
if ($result == 'agree') {
$audit_type = 3;
} elseif ($result == 'refuse') {
$audit_type = 4;
} else {
$audit_type = 2;
}
// switch ($result) {
// case 'agree':
// $audit_type = 3;
// break;
// case 'refuse':
// $audit_type = 4;
// break;
// default:
// $audit_type = 2;
// break;
// }
$data['audit_type'] = $audit_type;
$operation_records = end($param['process_instance']['operation_records']);
//todo 这里是钉钉user_id,需要查询关联本地ID
$ding_user_id = $operation_records['userid'];
$audit_userid = DB::table(config('alias.admin'))->where(['ding_user_id' => $ding_user_id])->value('id');
// $data['audit_userid'] = $audit_userid;
$data['audit_userid'] = 1;
$data['audit_date'] = $operation_records['date'];
$data['audit_remark'] = isset($operation_records['remark'])?$operation_records['remark']:'';
DB::table($this->table)->where('bill_num', $bill_num)->update($data);
}
CREATE TABLE `ding_approval_list` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`bill_num` varchar(64) NOT NULL DEFAULT '' COMMENT '单据号',
`process_instance_id` varchar(64) NOT NULL DEFAULT '' COMMENT '审批实例id',
`instance_details` text NOT NULL COMMENT '审批实例详情',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态(0: 删除,1:正常)',
`instance_user_id` int(11) NOT NULL DEFAULT '0' COMMENT '提交审核人',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COMMENT='钉钉审批表';