Browse Source

feature(交付工单): 硬件交付工单创建功能实现(带钉钉审批)

lk 2 years ago
parent
commit
757cbb4e8b

+ 19 - 0
opms_parent/app/handler/dingtalk/ding_event.go

@@ -260,6 +260,25 @@ func (h *DingHandler) handleBpmsInstanceChange(msg *message.MixMessage, ctx *din
 			return err.Error()
 		}
 		return "success"
+	case model.DeliverOrderCreate:
+		if msg.ProcessType == "finish" || msg.ProcessType == "terminate" {
+			srv, err := workService.NewDeliverOrderService(ctx.SubsMessage.Ctx)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+			err = srv.DeliverOrderNotify(instance, msg)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+		}
+		err = s.Update(instance, msg)
+		if err != nil {
+			glog.Error(err)
+			return err.Error()
+		}
+		return "success"
 	case model.ProjectCreate:
 		if msg.ProcessType == "finish" || msg.ProcessType == "terminate" {
 			srv, err := projService.NewBusinessService(ctx.SubsMessage.Ctx)

+ 14 - 5
opms_parent/app/model/work/deliver_order.go

@@ -5,6 +5,7 @@
 package work
 
 import (
+	contractmodel "dashoo.cn/micro/app/model/contract"
 	"dashoo.cn/micro/app/model/work/internal"
 	"dashoo.cn/opms_libary/request"
 	"github.com/gogf/gf/os/gtime"
@@ -46,7 +47,9 @@ type DeliverOrderListReq struct {
 }
 
 type DeliverOrderAddReq struct {
-	ContractId int `json:"contractId" v:"required#请输入合同ID"` // 关联合同ID
+	OrderTypeCode string                 `json:"orderTypeCode"`
+	ContractId    int                    `json:"contractId" v:"required#请输入合同ID"`        // 关联合同ID
+	FormData      []DingTalkFormItemData `json:"formData"         v:"required#表单数据不能为空"` // 表单数据
 }
 
 type DeliverOrderUpdateReq struct {
@@ -60,13 +63,19 @@ type DeliverOrderUpdateReq struct {
 
 type DeliverOrderFinishReq struct {
 	OrderId      int    `json:"orderId"     v:"min:1#工单不能为空"` //
-	FinishRemark string `json:"finishRemark"`                       // 完成信息
+	FinishRemark string `json:"finishRemark"`                 // 完成信息
 }
 
 // StartReq 启动
 type StartReq struct {
 	OrderId              int         `json:"orderId"     v:"min:1#工单不能为空"` //
-	RequiredDeliveryTime *gtime.Time `json:"requiredDeliveryTime"`               // 要求发货时间
-	ReceivingInfo        string      `json:"receivingInfo"`                      // 收货信息
-	SpecialRequirements  string      `json:"specialRequirements"`                // 特殊要求说明
+	RequiredDeliveryTime *gtime.Time `json:"requiredDeliveryTime"`         // 要求发货时间
+	ReceivingInfo        string      `json:"receivingInfo"`                // 收货信息
+	SpecialRequirements  string      `json:"specialRequirements"`          // 特殊要求说明
+}
+
+type ProductInfo struct {
+	ProductLine string
+	Products    []*contractmodel.CtrContractProduct
+	Remark      string
 }

+ 18 - 17
opms_parent/app/model/workflow/plat_workflow.go

@@ -11,23 +11,24 @@ import (
 
 // BizType 业务类型(10客户20项目创建30合同创建)
 const (
-	CustomerReceive  = "11" // 领取公海客户
-	CustomerPublic   = "12" // 客户移回公海
-	CustomerTrans    = "13" // 转移客户
-	ProjectCreate    = "20" // 项目创建
-	ProjectUpGrade   = "21" // 项目升级审批
-	ProjectDownGrade = "22" // 项目降级审批
-	ProjectTransfer  = "23" // 项目转移项目审批
-	ProjectToReserve = "24" // 项目转为储备项目审批
-	ProjectPersonnel = "25" // 项目协同人员审批
-	ContractCreate   = "30" // 合同创建
-	ContractInvoice  = "31" // 申请发票
-	PlatTaskApproval = "40" // 督办任务审批
-	DistProxyCreate  = "51" // 创建代理商
-	DistToProxy      = "52" // 经销商转代理商
-	DistProxyRenew   = "53" // 代理商续签
-	DistToDist       = "54" // 代理商转经销商
-	WorkOrderCreate  = "61" // 工单创建
+	CustomerReceive    = "11" // 领取公海客户
+	CustomerPublic     = "12" // 客户移回公海
+	CustomerTrans      = "13" // 转移客户
+	ProjectCreate      = "20" // 项目创建
+	ProjectUpGrade     = "21" // 项目升级审批
+	ProjectDownGrade   = "22" // 项目降级审批
+	ProjectTransfer    = "23" // 项目转移项目审批
+	ProjectToReserve   = "24" // 项目转为储备项目审批
+	ProjectPersonnel   = "25" // 项目协同人员审批
+	ContractCreate     = "30" // 合同创建
+	ContractInvoice    = "31" // 申请发票
+	PlatTaskApproval   = "40" // 督办任务审批
+	DistProxyCreate    = "51" // 创建代理商
+	DistToProxy        = "52" // 经销商转代理商
+	DistProxyRenew     = "53" // 代理商续签
+	DistToDist         = "54" // 代理商转经销商
+	WorkOrderCreate    = "61" // 支持工单创建
+	DeliverOrderCreate = "62" // 交付工单创建
 )
 
 // PlatWorkflow is the golang structure for table plat_workflow.

+ 2 - 2
opms_parent/app/service/base/base_product.go

@@ -41,10 +41,10 @@ func (s *productService) GetList(req *model.ProductSearchReq) (total int, produc
 		Dao = Dao.Where("prod_class = ?", req.ProdClass)
 	}
 	if req.OnlyHardware {
-		Dao = Dao.Where("prod_class in (40,60)", req.ProdClass)
+		Dao = Dao.Where("prod_class in (40,50,60)")
 	}
 	if req.OnlySoftware {
-		Dao = Dao.Where("prod_class in (10,20,30)", req.ProdClass)
+		Dao = Dao.Where("prod_class in (10,20,30)")
 	}
 
 	total, err = Dao.Count()

+ 1 - 1
opms_parent/app/service/contract/ctr_contract.go

@@ -799,7 +799,7 @@ func ContractApplyApproval(ctx context.Context, flow *workflowModel.PlatWorkflow
 	}
 
 	return contractDao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error {
-		_, err = worksrv.DeliverOrderAdd(tx, contractId, request.UserInfo{})
+		_, err = worksrv.DeliverOrderAdd(tx, contractId, request.UserInfo{}, nil)
 		return err
 	})
 }

+ 200 - 13
opms_parent/app/service/work/deliver_order.go

@@ -2,10 +2,16 @@ package work
 
 import (
 	"context"
+	model "dashoo.cn/micro/app/model/base"
+	workflowModel "dashoo.cn/micro/app/model/workflow"
+	workflowService "dashoo.cn/micro/app/service/workflow"
+	"dashoo.cn/opms_libary/plugin/dingtalk/workflow"
 	"database/sql"
 	"fmt"
 	"github.com/gogf/gf/os/glog"
 	"github.com/gogf/gf/util/gconv"
+	"strconv"
+	"strings"
 
 	basedao "dashoo.cn/micro/app/dao/base"
 	contractdao "dashoo.cn/micro/app/dao/contract"
@@ -15,6 +21,7 @@ import (
 	contractmodel "dashoo.cn/micro/app/model/contract"
 	work "dashoo.cn/micro/app/model/work"
 	"dashoo.cn/micro/app/service"
+	"dashoo.cn/opms_libary/plugin/dingtalk/message"
 
 	"dashoo.cn/opms_libary/micro_srv"
 	"dashoo.cn/opms_libary/myerrors"
@@ -222,16 +229,99 @@ func (s DeliverOrderService) Add(ctx context.Context, req *work.DeliverOrderAddR
 		return nil, myerrors.TipsError(validErr.Current().Error())
 	}
 
-	var id = []int{}
+	var productInfo work.ProductInfo
+
+	var products []*model.BaseProduct
+	err := s.Dao.DB.Model("base_product").Scan(&products)
+	if err != nil {
+		return nil, err
+	}
+
+	// 处理产品线
+	var pl string
+	for _, v := range req.FormData {
+		if v.Name == "产品线" {
+			pl, _ = v.Value.(string)
+		}
+		if v.Name == "备注" {
+			productInfo.Remark, _ = v.Value.(string)
+		}
+		if v.Name == "产品信息" {
+			pts := v.Value.([]interface{})
+			for _, fields := range pts {
+				var product contractmodel.CtrContractProduct
+				prodNum := 0
+				prodCode := ""
+				prodName := ""
+				for _, field := range fields.([]interface{}) {
+					data := field.(map[string]interface{})
+					if data["name"] == "产品名称" {
+						prodName = data["value"].(string)
+					}
+					if data["name"] == "产品型号" {
+						prodCode = data["value"].(string)
+					}
+					if data["name"] == "数量" {
+						prodNum = gconv.Int(data["value"])
+					}
+				}
+
+				product.ProdNum = prodNum
+				product.ProdCode = prodCode
+				product.ProdName = prodName
+				for _, p := range products {
+					if p.ProdCode == product.ProdCode && p.ProdName == product.ProdName {
+						product.ProdClass = p.ProdClass
+					}
+				}
+				productInfo.Products = append(productInfo.Products, &product)
+			}
+		}
+	}
+	if pl != "" {
+		productLine, err := service.GetDictDataByType(ctx, "sys_product_line")
+		if err != nil {
+			return nil, err
+		}
+		productLineMap := map[string]string{}
+		for k, v := range productLine {
+			productLineMap[v] = k
+		}
+		productInfo.ProductLine = productLineMap[pl]
+	}
+
+	var id []int
 	txerr := s.Dao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error {
 		var err error
-		id, err = DeliverOrderAdd(tx, req.ContractId, s.userInfo)
+		id, err = DeliverOrderAdd(tx, req.ContractId, s.userInfo, &productInfo)
+		if err != nil {
+			return err
+		}
+
+		// 提交工单 审批
+		workflowSrv, _ := workflowService.NewFlowService(ctx)
+		bizCode := gconv.String(id[0]) + ":" + req.OrderTypeCode
+		formComponentValues := make([]*workflow.StartProcessInstanceRequestFormComponentValues, 0)
+		if err = gconv.Structs(req.FormData, &formComponentValues); err != nil {
+			return err
+		}
+
+		workflowId, err := workflowSrv.StartProcessInstance(bizCode, workflowModel.DeliverOrderCreate, "", &workflow.StartProcessInstanceRequest{
+			ProcessCode:         &req.OrderTypeCode,
+			FormComponentValues: formComponentValues,
+		})
+		g.Log().Info("工单审批流ID ", workflowId)
+		if err != nil {
+			g.Log().Error(err)
+			return err
+		}
+
 		return err
 	})
 	return id, txerr
 }
 
-func DeliverOrderAdd(tx *gdb.TX, contractId int, userInfo request.UserInfo) ([]int, error) {
+func DeliverOrderAdd(tx *gdb.TX, contractId int, userInfo request.UserInfo, productInfo *work.ProductInfo) ([]int, error) {
 	var c contractmodel.CtrContract
 	err := tx.GetStruct(&c, "select * from ctr_contract where id = ?", contractId)
 	if err == sql.ErrNoRows {
@@ -242,12 +332,18 @@ func DeliverOrderAdd(tx *gdb.TX, contractId int, userInfo request.UserInfo) ([]i
 	}
 
 	var product []*contractmodel.CtrContractProduct
-	err = tx.GetStructs(&product, "select * from ctr_contract_product where contract_id = ?", contractId)
-	if err == sql.ErrNoRows {
-		return nil, myerrors.TipsError(fmt.Sprintf("合同产品为空: %d", contractId))
-	}
-	if err != nil {
-		return nil, err
+	remark := ""
+	if productInfo == nil {
+		err = tx.GetStructs(&product, "select * from ctr_contract_product where contract_id = ?", contractId)
+		if err == sql.ErrNoRows {
+			return nil, myerrors.TipsError(fmt.Sprintf("合同产品为空: %d", contractId))
+		}
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		product = append(product, productInfo.Products...)
+		remark = productInfo.Remark
 	}
 
 	var deliverSoft *work.DeliverOrder
@@ -263,7 +359,8 @@ func DeliverOrderAdd(tx *gdb.TX, contractId int, userInfo request.UserInfo) ([]i
 		if p.ProdClass == "10" || p.ProdClass == "20" || p.ProdClass == "30" {
 			orderType = "10"
 		}
-		if p.ProdClass == "40" || p.ProdClass == "60" {
+		// 参考218上的产品类型设置
+		if p.ProdClass == "40" || p.ProdClass == "50" || p.ProdClass == "60" {
 			orderType = "20"
 		}
 
@@ -272,10 +369,15 @@ func DeliverOrderAdd(tx *gdb.TX, contractId int, userInfo request.UserInfo) ([]i
 		if orderType == "20" {
 			projectManId, projectManName, deliverManId, deliverManName = projectManId1, projectManName1, deliverManId1, deliverManName1
 		}
+		line := c.ProductLine
+		if productInfo != nil {
+			line = productInfo.ProductLine
+		}
 
+		// 交付状态(0发起 10项目立项 15进行中 20 完成 30审批拒绝40关闭)
 		o := work.DeliverOrder{
 			OrderCode:      fmt.Sprintf("%s%s", c.ContractCode, orderType),
-			OrderStatus:    "10",
+			OrderStatus:    "0",
 			OrderType:      orderType,
 			CustId:         c.CustId,
 			CustName:       c.CustName,
@@ -287,8 +389,8 @@ func DeliverOrderAdd(tx *gdb.TX, contractId int, userInfo request.UserInfo) ([]i
 			ProjectManName: projectManName,
 			DeliverManId:   deliverManId,
 			DeliverManName: deliverManName,
-			Product:        c.ProductLine,
-			Remark:         "",
+			Product:        line,
+			Remark:         remark,
 			CreatedBy:      int(userInfo.Id),
 			CreatedName:    userInfo.NickName,
 			CreatedTime:    gtime.Now(),
@@ -349,6 +451,91 @@ func DeliverOrderAdd(tx *gdb.TX, contractId int, userInfo request.UserInfo) ([]i
 	return id, nil
 }
 
+// DeliverOrderNotify 工单 审批结果通知
+func (s *DeliverOrderService) DeliverOrderNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
+	bizCode := strings.Split(flow.BizCode, ":")
+	if len(bizCode) != 2 {
+		return fmt.Errorf("工单审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id)
+	}
+	workOrderId := bizCode[0]
+	if msg.ProcessType != "finish" && msg.ProcessType != "terminate" {
+		return fmt.Errorf("无法识别的 ProcessType :%s", msg.ProcessType)
+	}
+	if msg.Result != "agree" && msg.Result != "refuse" && msg.Result != "" {
+		return fmt.Errorf("无法识别的 Result :%s", msg.Result)
+	}
+	fmt.Println(msg)
+
+	workOrder, err := s.Dao.WherePri(workOrderId).One()
+	if err != nil {
+		return err
+	}
+	if workOrder == nil {
+		return fmt.Errorf("工单不存在:%s Id: %d", flow.BizCode, flow.Id)
+	}
+
+	var data = g.Map{}
+	// 工单状态(10发起20审批中30审批通过40审批拒绝50关闭)
+	// 交付状态(0发起 10项目立项 15进行中 20 完成 30审批拒绝40关闭)
+	if msg.ProcessType == "terminate" {
+		data[s.Dao.C.OrderStatus] = "40"
+	}
+	if msg.ProcessType == "finish" && msg.Result == "refuse" {
+		data[s.Dao.C.OrderStatus] = "30"
+	}
+	if msg.ProcessType == "finish" && msg.Result == "agree" {
+		data[s.Dao.C.OrderStatus] = "10"
+	}
+
+	if data[s.Dao.C.OrderStatus] == "10" {
+		s.workOrderSendMsg(workOrder, "交付工单审批通过提醒", fmt.Sprintf("<p>工单:%s 已审批通过</p>", workOrder.OrderCode))
+	}
+
+	// 项目修改
+	_, err = s.Dao.WherePri(workOrder.Id).Update(fmt.Sprintf("order_status='%v'", data[s.Dao.C.OrderStatus]))
+	if err != nil {
+		return err
+	}
+	return err
+}
+
+func (s *DeliverOrderService) workOrderSendMsg(order *work.DeliverOrder, title, content string) {
+	recvUserIds := []int{}
+	if order.ProjectManId != 0 {
+		recvUserIds = append(recvUserIds, order.ProjectManId)
+	}
+	if order.DeliverManId != 0 {
+		recvUserIds = append(recvUserIds, order.DeliverManId)
+	}
+	contract, err := s.ContractDao.Where(fmt.Sprintf("id='%v'", order.ContractId)).One()
+	if err != nil {
+		glog.Error(err)
+	}
+	if contract != nil {
+		recvUserIds = append(recvUserIds, contract.InchargeId)
+	}
+	recvUserIds = service.SliceIntDeduplication(recvUserIds)
+	if len(recvUserIds) == 0 {
+		return
+	}
+	recvUserIdString := []string{}
+	for _, uid := range recvUserIds {
+		recvUserIdString = append(recvUserIdString, strconv.Itoa(uid))
+	}
+	msg := g.MapStrStr{
+		"msgTitle":    title,
+		"msgContent":  content,
+		"msgType":     "20",
+		"recvUserIds": strings.Join(recvUserIdString, ","),
+		"msgStatus":   "10",
+		"sendType":    "10",
+	}
+	fmt.Println(title, strings.Join(recvUserIdString, ","))
+	if err := service.CreateSystemMessage(msg); err != nil {
+		g.Log().Error("交付工单 %s 提醒异常:%s", title, err)
+	}
+}
+
 func getProjectUser(tx *gdb.TX, c *contractmodel.CtrContract, isDeliver bool) (int, string, int, string) {
 	projectManId, projectManName, deliverManId, deliverManName := 0, "", 0, ""
 	// 根据产品线,设置项目经理:  10 BIOBANK; 20 CELLSOP; 30 LIMS+基因; 40 智能硬件; 50 液氮罐; 60 MCS;