Skip to content

Commit

Permalink
Merge pull request #2 from WoSai/feature/dingtalk
Browse files Browse the repository at this point in the history
process instance
  • Loading branch information
aoreki authored Mar 31, 2021
2 parents 5bb8c60 + 8d61e26 commit 489fa21
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 12 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
# Dependency directories (remove the comment below to include it)
vendor/

.idea/
.idea/
.env
60 changes: 57 additions & 3 deletions dingtalk/dingtalk.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func (ding *Client) GetUserInfoV2(ctx context.Context, req *RequestUserGet) (*Re
}

// 根据手机号获取userid v2 https://ding-doc.dingtalk.com/document#/org-dev-guide/query-users-by-phone-number
func (ding *Client) GetUserInfoByMobileV2(ctx context.Context, mobile string) (string, *http.Response, error){
func (ding *Client) GetUserInfoByMobileV2(ctx context.Context, mobile string) (string, *http.Response, error) {
ret := new(ResponseUserByMobile)
var res *http.Response
var err error
Expand All @@ -207,7 +207,7 @@ func (ding *Client) GetUserInfoByMobileV2(ctx context.Context, mobile string) (s
}

// 获取指定用户的所有父部门列表 https://ding-doc.dingtalk.com/document#/org-dev-guide/obtains-the-list-of-all-parent-departments-of-a-user
func (ding *Client) ListParentDeptByUserV2 (ctx context.Context, userid string) (*DeptListParent, *http.Response, error){
func (ding *Client) ListParentDeptByUserV2(ctx context.Context, userid string) (*DeptListParent, *http.Response, error) {
ret := new(ResponseGetUserIdByUnionid)
var res *http.Response
var err error
Expand All @@ -225,7 +225,7 @@ func (ding *Client) ListParentDeptByUserV2 (ctx context.Context, userid string)
}

// 获取部门详情 https://ding-doc.dingtalk.com/document#/org-dev-guide/queries-department-details-v1
func (ding *Client) GetDepartment(ctx context.Context, req *RequestDepartmentInfo) (*DepartmentInfo, *http.Response, error){
func (ding *Client) GetDepartment(ctx context.Context, req *RequestDepartmentInfo) (*DepartmentInfo, *http.Response, error) {
ret := new(ResponseDeptInfo)
var res *http.Response
var err error
Expand All @@ -245,3 +245,57 @@ func (ding *Client) GetDepartment(ctx context.Context, req *RequestDepartmentInf
})
return ret.DepartmentInfo, res, err
}

// 发起审批实例 https://developers.dingtalk.com/document/app/initiate-approval
func (ding *Client) CreateProcessInstance(ctx context.Context, req *RequestCreateProcessInstance) (string, *http.Response, error) {
ret := new(ResponseCreateProcessInstance)
var err error
var res *http.Response

err = ding.RetryOnAccessTokenExpired(ctx, 1, func() error {
res, _, err = ding.client.PostWithContext(
ctx,
ding.url+"/topapi/processinstance/create",
requests.Params{Query: requests.Any{"access_token": ding.AccessToken()}, Json: req},
UnmarshalAndParseError(ret),
)
return err
})
return ret.ProcessInstanceID, res, err
}

// 获取审批实例详情 https://developers.dingtalk.com/document/app/obtains-the-details-of-a-single-approval-instance
func (ding *Client) GetProcessInstance(ctx context.Context, processInstanceID string) (*ProcessInstance, *http.Response, error) {
ret := new(ResponseGetProcessInstance)
var err error
var res *http.Response

err = ding.RetryOnAccessTokenExpired(ctx, 1, func() error {
res, _, err = ding.client.PostWithContext(
ctx,
ding.url+"/topapi/processinstance/get",
requests.Params{Query: requests.Any{"access_token": ding.AccessToken()}, Json: requests.Any{"process_instance_id": processInstanceID}},
UnmarshalAndParseError(ret),
)
return err
})
return ret.ProcessInstance, res, err
}

// 获取部门详情,可以得到部门主管
func (ding *Client) GetDepartmentV2(ctx context.Context, deptID int) (*DepartmentInfoV2, *http.Response, error) {
ret := new(ResponseDeptInfoV2)
var res *http.Response
var err error

err = ding.RetryOnAccessTokenExpired(ctx, 1, func() error {
res, _, err = ding.client.PostWithContext(
ctx,
ding.url+"/topapi/v2/department/get",
requests.Params{Query: requests.Any{"access_token": ding.AccessToken()}, Json: &RequestDepartmentInfoV2{DeptID: deptID}},
UnmarshalAndParseError(ret),
)
return err
})
return ret.Result, res, err
}
71 changes: 63 additions & 8 deletions dingtalk/dingtalk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package dingtalk

import (
"context"
"encoding/json"
"fmt"
"github.com/stretchr/testify/assert"
"os"
"testing"
Expand All @@ -12,16 +14,19 @@ var ctx = context.Background()
var testUser *ResponseGetUserInfo

var (
AgentID = os.Getenv("AgentID")
AppKey = os.Getenv("AppKey")
AgentID = os.Getenv("AgentID")
AppKey = os.Getenv("AppKey")
AppSecret = os.Getenv("AppSecret")
UserID = os.Getenv("UserID")
UserID = os.Getenv("UserID")
)

func init() {
func init() {
DingClient = NewClient(Option{AgentID: AgentID, AppKey: AppKey, AppSecret: AppSecret})
var err error
testUser, _ , err = DingClient.GetUserInfoV2(ctx, &RequestUserGet{UserID: UserID})
_, _, err := DingClient.GetAccessToken(ctx)
if err != nil {
panic("get access token fail:" + err.Error())
}
testUser, _, err = DingClient.GetUserInfoV2(ctx, &RequestUserGet{UserID: UserID})
if err != nil {
panic("userid not exit" + err.Error())
}
Expand Down Expand Up @@ -62,13 +67,13 @@ func TestClient_GetUserInfoByMobileV2(t *testing.T) {
}

func TestClient_GetUserInfoV2(t *testing.T) {
user, _ , err := DingClient.GetUserInfoV2(ctx, &RequestUserGet{UserID: testUser.Result.UserID})
user, _, err := DingClient.GetUserInfoV2(ctx, &RequestUserGet{UserID: testUser.Result.UserID})
assert.Nil(t, err)
assert.Equal(t, user.Result.UserID, testUser.Result.UserID)
}

func TestClient_ListParentDeptByUserV2(t *testing.T) {
_, _ , err := DingClient.ListParentDeptByUserV2(ctx, testUser.Result.UserID)
_, _, err := DingClient.ListParentDeptByUserV2(ctx, testUser.Result.UserID)
assert.Nil(t, err)
}

Expand All @@ -77,4 +82,54 @@ func TestClient_GetOrganizationUserCount(t *testing.T) {
assert.Nil(t, err)
}

func TestClient_CreateProcessInstance(t *testing.T) {
req := &RequestCreateProcessInstance{
FormComponentValues: []*FormComponentValue{
{
Name: "补卡时间",
Value: "2021-03-31 09:00",
},
{
Name: "补卡理由",
Value: "忘打卡",
},
},
AgentID: AgentID,
DeptID: "477274342",
ProcessCode: "PROC-0F200284-842E-46FF-9ACC-64DB3176150C",
OriginatorUserID: UserID,
ApproversV2: []ProcessApprovers{
{
TaskActionType: "OR",
UserIDs: []string{UserID, "1824661867777911"},
},
{
TaskActionType: "NONE",
UserIDs: []string{UserID},
},
},
}
id, _, _ := DingClient.CreateProcessInstance(ctx, req)
fmt.Println(id)
}

func TestClient_GetProcessInstance(t *testing.T) {
//"f4b924d1-b13b-4dc1-ae5a-aea4716ecb5c"
//"01b3a55b-d92d-40c7-ae70-87b13daf11e5"
pi, _, _ := DingClient.GetProcessInstance(ctx, "01b3a55b-d92d-40c7-ae70-87b13daf11e5")
b, _ := json.Marshal(pi)
fmt.Println(string(b))
}

func TestClient_1(t *testing.T) {
// 获取用户父部门列表
res, _, _ := DingClient.ListParentDeptByUserV2(ctx, UserID)
b, _ := json.Marshal(res)
fmt.Println(string(b))
for _, dept := range res.ParentDeptList[0].ParentDeptIdList {
// 获取部门详情
resp, _, _ := DingClient.GetDepartmentV2(ctx, dept)
b, _ = json.Marshal(resp)
fmt.Println(string(b))
}
}
135 changes: 135 additions & 0 deletions dingtalk/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,125 @@ type (
BasicResponse `json:",inline"`
*DepartmentInfo
}

RequestDepartmentInfoV2 struct {
DeptID int `json:"dept_id"`
Language string `json:"language,omitempty"`
}

DepartmentInfoV2 struct {
DeptID int `json:"dept_id"`
Name string `json:"name,omitempty"`
ParentID int `json:"parent_id,omitempty"`
SourceIdentifier string `json:"source_identifier,omitempty"`
CreateDeptGroup bool `json:"create_dept_group,omitempty"`
AutoAddUser bool `json:"auto_add_user,omitempty"`
FromUnionOrg bool `json:"from_union_org,omitempty"`
Tags string `json:"tags,omitempty"`
Order int `json:"order,omitempty"`
DeptGroupChatID string `json:"dept_group_chat_id,omitempty"`
GroupContainSubDept bool `json:"group_contain_sub_dept,omitempty"`
OrgDeptOwner string `json:"org_dept_owner,omitempty"`
DeptManagerUseridList []string `json:"dept_manager_userid_list,omitempty"`
OuterDept bool `json:"outer_dept,omitempty"`
OuterPermitDepts []int `json:"outer_permit_depts,omitempty"`
OuterPermitUsers []string `json:"outer_permit_users,omitempty"`
HideDept bool `json:"hide_dept,omitempty"`
UserPermits []string `json:"user_permits,omitempty"`
DeptPermits []int `json:"dept_permits,omitempty"`
}

ResponseDeptInfoV2 struct {
BasicResponse `json:",inline"`
Result *DepartmentInfoV2 `json:"result,omitempty"`
}

// 钉钉的时间格式
DingTime struct {
time.Time
}

FormComponentValue struct {
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"`
ExtValue string `json:"ext_value,omitempty"`
ID string `json:"id,omitempty"`
ComponentType string `json:"component_type,omitempty"`
}

ProcessApprovers struct {
TaskActionType string `json:"task_action_type,omitempty"`
UserIDs []string `json:"user_ids,omitempty"`
}

// 审批请求参数
RequestCreateProcessInstance struct {
FormComponentValues []*FormComponentValue `json:"form_component_values,omitempty"`
AgentID string `json:"agent_id,omitempty"`
DeptID string `json:"dept_id,omitempty"`
ProcessCode string `json:"process_code,omitempty"`
OriginatorUserID string `json:"originator_user_id,omitempty"` // 审批发起人ID
ApproversV2 []ProcessApprovers `json:"approvers_v2,omitempty"`
CCList string `json:"cc_list,omitempty"` // 抄送人userid列表
CCPosition string `json:"cc_position,omitempty"` // 抄送时间,分为(START, FINISH, START_FINISH)
}

ResponseCreateProcessInstance struct {
BasicResponse `json:",inline"`
ProcessInstanceID string `json:"process_instance_id,omitempty"`
}

ProcessAttachment struct {
FileName string `json:"file_name,omitempty"`
FileSize string `json:"file_size,omitempty"`
FileID string `json:"file_id,omitempty"`
FileType string `json:"file_type,omitempty"`
}

ProcessOperationRecord struct {
UserID string `json:"user_id,omitempty"`
Date DingTime `json:"date,omitempty"`
OperationType string `json:"operation_type,omitempty"`
OperationResult string `json:"operation_result,omitempty"`
Remark string `json:"remark,omitempty"`
Attachments []*ProcessAttachment `json:"attachments,omitempty"`
}

ProcessTask struct {
UserID string `json:"userid,omitempty"`
TaskStatus string `json:"task_status,omitempty"`
TaskResult string `json:"task_result,omitempty"`
CreateTime DingTime `json:"create_time,omitempty"`
FinishTime DingTime `json:"finish_time,omitempty"`
TaskID string `json:"taskid,omitempty"`
URL string `json:"url,omitempty"`
}

// 审批实例详情
ProcessInstance struct {
Title string `json:"title,omitempty"`
CreateTime DingTime `json:"create_time,omitempty"`
FinishTime DingTime `json:"finish_time,omitempty"`
OriginatorUserID string `json:"originator_userid,omitempty"`
OriginatorDeptID string `json:"originator_dept_id,omitempty"`
Status string `json:"status,omitempty"` // RUNNING审批中COMPLETED完成
ApproverUserIDs []string `json:"approver_userids,omitempty"`
CCUserIDs []string `json:"cc_userids,omitempty"`
Result string `json:"result,omitempty"` // agree同意refuse拒绝
BusinessID string `json:"business_id,omitempty"`
OperationRecords []*ProcessOperationRecord `json:"operation_records,omitempty"`
Tasks []*ProcessTask `json:"tasks,omitempty"`
OriginatorDeptName string `json:"originator_dept_name,omitempty"`
BizAction string `json:"biz_action,omitempty"`
AttachedProcessInstanceIDs []string `json:"attached_process_instance_ids,omitempty"`
FormComponentValues []*FormComponentValue `json:"form_component_values,omitempty"`
MainProcessInstanceID string `json:"main_process_instance_id,omitempty"`
}

ResponseGetProcessInstance struct {
BasicResponse `json:",inline"`
ProcessInstance *ProcessInstance `json:"process_instance,omitempty"`
}
)

func (ts *UnixTimestamp) UnmarshalJSON(data []byte) error {
Expand All @@ -228,3 +347,19 @@ func (ts *UnixTimestamp) Time() time.Time {
func (ts *UnixTimestamp) MarshalJSON() ([]byte, error) {
return json.Marshal(ts.ts)
}

func (dt *DingTime) UnmarshalJSON(b []byte) error {
if string(b) == "null" {
return nil
}
ti, err := time.Parse("\"2006-01-02 15:04:05\"", string(b))
if err != nil {
return err
}
dt.Time = ti
return nil
}

func (dt DingTime) MarshalJSON() ([]byte, error) {
return []byte(dt.Time.Format("\"2006-01-02 15:04:05\"")), nil
}

0 comments on commit 489fa21

Please # to comment.