package service import ( "context" "database/sql" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "strconv" "strings" "sync" "time" basedao "dashoo.cn/micro/app/dao/base" dao "dashoo.cn/micro/app/dao/contract" custdao "dashoo.cn/micro/app/dao/cust" projdao "dashoo.cn/micro/app/dao/proj" workflowdao "dashoo.cn/micro/app/dao/workflow" model "dashoo.cn/micro/app/model/contract" proj "dashoo.cn/micro/app/model/proj" workflowModel "dashoo.cn/micro/app/model/workflow" "dashoo.cn/micro/app/service" baseService "dashoo.cn/micro/app/service/base" projsrv "dashoo.cn/micro/app/service/proj" worksrv "dashoo.cn/micro/app/service/work" workflowService "dashoo.cn/micro/app/service/workflow" "dashoo.cn/opms_libary/micro_srv" "dashoo.cn/opms_libary/multipart" "dashoo.cn/opms_libary/myerrors" "dashoo.cn/opms_libary/plugin/dingtalk" "dashoo.cn/opms_libary/plugin/dingtalk/message" "dashoo.cn/opms_libary/plugin/dingtalk/workflow" "dashoo.cn/opms_libary/request" "dashoo.cn/opms_libary/utils" "github.com/gogf/gf/database/gdb" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gcron" "github.com/gogf/gf/os/glog" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/util/gvalid" ) type CtrContractService struct { Dao *dao.CtrContractDao ProjBusinessDao *projdao.ProjBusinessDao CustomerDao *custdao.CustCustomerDao CtrProductDao *dao.CtrContractProductDao ProductDao *basedao.BaseProductDao DynamicsDao *dao.CtrContractDynamicsDao WorkflowDao *workflowdao.PlatWorkflowDao AppendDao *dao.CtrContractAppendDao GoalDao *dao.CtrContractGoalDao Tenant string userInfo request.UserInfo DataScope g.Map `json:"dataScope"` } var mtx sync.Mutex func NewCtrContractService(ctx context.Context) (*CtrContractService, error) { tenant, err := micro_srv.GetTenant(ctx) if err != nil { err = myerrors.TipsError(fmt.Sprintf("获取租户码异常:%s", err.Error())) return nil, err //fmt.Errorf("获取租户码异常:%s", err.Error()) } // 获取用户信息 userInfo, err := micro_srv.GetUserInfo(ctx) if err != nil { return nil, fmt.Errorf("获取用户信息异常:%s", err.Error()) } return &CtrContractService{ Dao: dao.NewCtrContractDao(tenant), ProjBusinessDao: projdao.NewProjBusinessDao(tenant), CustomerDao: custdao.NewCustCustomerDao(tenant), CtrProductDao: dao.NewCtrContractProductDao(tenant), ProductDao: basedao.NewBaseProductDao(tenant), DynamicsDao: dao.NewCtrContractDynamicsDao(tenant), WorkflowDao: workflowdao.NewPlatWorkflowDao(tenant), AppendDao: dao.NewCtrContractAppendDao(tenant), GoalDao: dao.NewCtrContractGoalDao(tenant), Tenant: tenant, userInfo: userInfo, DataScope: userInfo.DataScope, }, nil } func (s CtrContractService) Get(ctx context.Context, id int) (*model.CtrContractGetRsp, error) { ent, err := s.Dao.Where("Id = ?", id).One() if err != nil { return nil, err } if ent == nil { return nil, myerrors.TipsError("合同不存在") } product, err := s.CtrProductDao.Where("contract_id = ?", id).All() if err != nil { return nil, err } if product == nil { product = []*model.CtrContractProduct{} } return &model.CtrContractGetRsp{ CtrContract: *ent, Product: product, }, nil } func (s CtrContractService) DynamicsList(ctx context.Context, req *model.CtrContractDynamicsListReq) (int, interface{}, error) { dao := &s.DynamicsDao.CtrContractDynamicsDao if req.SearchText != "" { likestr := fmt.Sprintf("%%%s%%", req.SearchText) dao = dao.Where("(opn_people LIKE ? || opn_content LIKE ?)", likestr, likestr) } if req.ContractId != 0 { dao = dao.Where("contract_id = ?", req.ContractId) } if req.OpnPeopleId != 0 { dao = dao.Where("opn_people_id = ?", req.OpnPeopleId) } if req.OpnPeople != "" { likestr := fmt.Sprintf("%%%s%%", req.OpnPeople) dao = dao.Where("opn_people like ?", likestr) } if req.OpnType != "" { dao = dao.Where("opn_type = ?", req.OpnType) } // if req.OpnContent != "" { // likestr := fmt.Sprintf("%%%s%%", req.OpnContent) // dao = dao.Where("opn_content like ?", likestr) // } if req.BeginTime != "" { dao = dao.Where("created_time > ?", req.BeginTime) } if req.EndTime != "" { dao = dao.Where("created_time < ?", req.EndTime) } total, err := dao.Count() if err != nil { return 0, nil, err } if req.PageNum != 0 { dao = dao.Page(req.GetPage()) } orderby := "created_time desc" if req.OrderBy != "" { orderby = req.OrderBy } dao = dao.Order(orderby) ents := []*model.CtrContractDynamics{} err = dao.Structs(&ents) if err != nil && err != sql.ErrNoRows { return 0, nil, err } ret := map[string][]*model.CtrContractDynamics{} for _, ent := range ents { date := ent.OpnDate.Format("Y-m-d") ret[date] = append(ret[date], ent) } return total, ret, err } func (s CtrContractService) List(ctx context.Context, req *model.CtrContractListReq) (int, []*model.CtrContractListRsp, error) { ctx = context.WithValue(ctx, "contextService", s) dao := s.Dao.DataScope(ctx, "incharge_id").As("a") if req.SearchText != "" { likestr := fmt.Sprintf("%%%s%%", req.SearchText) dao = dao.Where("(a.contract_code LIKE ? || a.contract_name LIKE ? || a.cust_name LIKE ? || a.nbo_name LIKE ?)", likestr, likestr, likestr, likestr) } if req.ContractCode != "" { likestr := fmt.Sprintf("%%%s%%", req.ContractCode) dao = dao.Where("a.contract_code like ?", likestr) } if req.ContractName != "" { likestr := fmt.Sprintf("%%%s%%", req.ContractName) dao = dao.Where("a.contract_name like ?", likestr) } if req.CustId != 0 { dao = dao.Where("a.cust_id = ?", req.CustId) } if req.CustName != "" { likestr := fmt.Sprintf("%%%s%%", req.CustName) dao = dao.Where("a.cust_name like ?", likestr) } if req.NboId != 0 { dao = dao.Where("a.nbo_id = ?", req.NboId) } if req.NboName != "" { likestr := fmt.Sprintf("%%%s%%", req.NboName) dao = dao.Where("a.nbo_name like ?", likestr) } if req.ApproStatus != "" { dao = dao.Where("a.appro_status = ?", req.ApproStatus) } if req.ContractType != "" { dao = dao.Where("a.contract_type = ?", req.ContractType) } // if req.ContractStartTime != nil { // dao = dao.Where("a.contract_start_time > ?", req.ContractStartTime) // } // if req.ContractEndTime != nil { // dao = dao.Where("a.contract_end_time < ?", req.ContractEndTime) // } if req.InchargeId != 0 { dao = dao.Where("a.incharge_id = ?", req.InchargeId) } if req.InchargeName != "" { likestr := fmt.Sprintf("%%%s%%", req.InchargeName) dao = dao.Where("a.incharge_name like ?", likestr) } if req.SignatoryId != 0 { dao = dao.Where("a.signatory_id = ?", req.SignatoryId) } if req.SignatoryName != "" { likestr := fmt.Sprintf("%%%s%%", req.SignatoryName) dao = dao.Where("a.signatory_name like ?", likestr) } if req.DistributorId != 0 { dao = dao.Where("a.distributor_id = ?", req.DistributorId) } if req.DistributorName != "" { likestr := fmt.Sprintf("%%%s%%", req.DistributorName) dao = dao.Where("a.distributor_name like ?", likestr) } if req.BeginTime != "" { dao = dao.Where("a.created_time > ?", req.BeginTime) } if req.EndTime != "" { dao = dao.Where("a.created_time < ?", req.EndTime) } if req.ContractEndTimeStart != "" { dao = dao.Where("a.contract_end_time >= ?", req.ContractEndTimeStart) } if req.ContractEndTimeEnd != "" { dao = dao.Where("a.contract_end_time <= ?", req.ContractEndTimeEnd) } if req.CustProvinceId != 0 { dao = dao.Where("a.cust_province_id = ?", req.CustProvinceId) } if req.CustCityId != 0 { dao = dao.Where("a.cust_city_id = ?", req.CustCityId) } if req.ProductLine != "" { dao = dao.Where("a.product_line = ?", req.ProductLine) } total, err := dao.Count() if err != nil { return 0, nil, err } if req.PageNum != 0 { dao = dao.Page(req.GetPage()) } orderby := "a.contract_sign_time desc" if req.OrderBy != "" { orderby = req.OrderBy } dao = dao.Order(orderby) ents := []*model.CtrContractListRsp{} err = dao.Structs(&ents) if err != nil && err != sql.ErrNoRows { return 0, nil, err } return total, ents, err } func (s CtrContractService) BindProduct(tx *gdb.TX, id int, code string, product []model.CtrAddProduct) error { var amount float64 for _, p := range product { amount += (p.TranPrice * float64(p.ProdNum)) } _, err := tx.Delete("ctr_contract_product", "contract_id = ?", id) if err != nil { return err } tocreate := []model.CtrContractProduct{} for _, p := range product { product, err := s.ProductDao.Where("id = ?", p.ProdId).One() if err != nil { return err } if product == nil { return myerrors.TipsError(fmt.Sprintf("产品: %d 不存在", p.ProdId)) } tocreate = append(tocreate, model.CtrContractProduct{ ContractId: id, ContractCode: code, ProdId: p.ProdId, ProdCode: product.ProdCode, ProdName: product.ProdName, ProdClass: product.ProdClass, ProdNum: p.ProdNum, MaintTerm: p.MaintTerm, SugSalesPrice: p.SugSalesPrice, TranPrice: p.TranPrice, ContractPrive: amount, Remark: p.Remark, CreatedBy: int(s.userInfo.Id), CreatedName: s.userInfo.NickName, CreatedTime: gtime.Now(), UpdatedBy: int(s.userInfo.Id), UpdatedName: s.userInfo.NickName, UpdatedTime: gtime.Now(), }) } if len(tocreate) != 0 { _, err = tx.Insert("ctr_contract_product", tocreate) if err != nil { return err } } return nil } func (s CtrContractService) AddDynamicsByCurrentUser(tx *gdb.TX, contractId int, opnType string, content map[string]interface{}) error { contentByte, err := json.Marshal(content) if err != nil { return err } _, err = tx.InsertAndGetId("ctr_contract_dynamics", model.CtrContractDynamics{ ContractId: contractId, OpnPeopleId: s.userInfo.Id, OpnPeople: s.userInfo.NickName, OpnDate: gtime.Now(), OpnType: opnType, OpnContent: string(contentByte), Remark: "", CreatedBy: s.userInfo.Id, CreatedName: s.userInfo.NickName, CreatedTime: gtime.Now(), UpdatedBy: s.userInfo.Id, UpdatedName: s.userInfo.NickName, UpdatedTime: gtime.Now(), }) return err } func (s CtrContractService) Add(ctx context.Context, req *model.CtrContractAddReq) (int, error) { validErr := gvalid.CheckStruct(ctx, req, nil) if validErr != nil { return 0, myerrors.TipsError(validErr.Current().Error()) } if len(req.Product) == 0 { return 0, myerrors.TipsError("产品不能为空") } for _, p := range req.Product { if p.ProdNum < 1 { return 0, myerrors.TipsError("产品数量必须大于 0") } } // c, err := s.Dao.Where("contract_name = ?", req.ContractName).One() // if err != nil { // return 0, err // } // if c != nil { // return 0, myerrors.TipsError(fmt.Sprintf("合同名称:%s 已存在", req.ContractName)) // } nbo, err := s.ProjBusinessDao.Where("id = ?", req.NboId).One() if err != nil { return 0, err } if nbo == nil { return 0, myerrors.TipsError("项目不存在") } // c, err = s.Dao.Where("nbo_id = ?", req.NboId).One() // if err != nil { // return 0, err // } // if c != nil { // return 0, myerrors.TipsError("所选项目已添加合同") // } var sequence int if req.ContractType == "XS" { // 销售合同 sequence, err = service.SequenceYearRest(s.Dao.DB, "contract_code_xs") if err != nil { return 0, err } } else if req.ContractType == "JS" { // 技术合同 sequence, err = service.SequenceYearRest(s.Dao.DB, "contract_code_js") if err != nil { return 0, err } } else { return 0, myerrors.TipsError("不支持的合同类型") } if req.ContractCode == "" { req.ContractCode = fmt.Sprintf("DH%s%s-%03d", req.ContractType, time.Now().Format("0601"), sequence) } c, err := s.Dao.Where("contract_code = ?", req.ContractCode).One() if err != nil { return 0, err } if c != nil { return 0, myerrors.TipsError(fmt.Sprintf("合同编号:%s 已存在", req.ContractCode)) } var contractAmount float64 for _, p := range req.Product { contractAmount += (p.TranPrice * float64(p.ProdNum)) } ctr := model.CtrContract{ ContractCode: req.ContractCode, ContractName: req.ContractName, CustId: nbo.CustId, CustName: nbo.CustName, NboId: nbo.Id, NboName: nbo.NboName, IsBig: nbo.IsBig, ProductLine: nbo.ProductLine, CustProvinceId: nbo.CustProvinceId, CustProvince: nbo.CustProvince, CustCityId: nbo.CustCityId, CustCity: nbo.CustCity, ApproStatus: "10", ContractType: req.ContractType, ContractAmount: contractAmount, InvoiceAmount: 0, CollectedAmount: 0, ContractStartTime: req.ContractStartTime, ContractEndTime: req.ContractEndTime, ContractSignTime: req.ContractSignTime, InchargeId: req.InchargeId, InchargeName: req.InchargeName, SignatoryId: req.SignatoryId, SignatoryName: req.SignatoryName, SignatoryType: req.SignatoryType, SignatoryUnit: req.SignatoryUnit, EarnestMoney: req.EarnestMoney, CustSignatoryId: req.CustSignatoryId, CustSignatoryName: req.CustSignatoryName, DistributorId: req.DistributorId, DistributorName: req.DistributorName, Remark: req.Remark, ServiceFeeAgreement: req.ServiceFeeAgreement, CreatedBy: int(s.userInfo.Id), CreatedName: s.userInfo.NickName, CreatedTime: gtime.Now(), UpdatedBy: int(s.userInfo.Id), UpdatedName: s.userInfo.NickName, UpdatedTime: gtime.Now(), } var id int txerr := s.Dao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { ctrid, err := tx.InsertAndGetId("ctr_contract", ctr) if err != nil { return err } err = s.BindProduct(tx, int(ctrid), ctr.ContractCode, req.Product) if err != nil { return err } err = s.AddDynamicsByCurrentUser(tx, int(ctrid), "创建合同", map[string]interface{}{}) if err != nil { return err } _, err = tx.Update("proj_business", map[string]interface{}{ "nbo_type": projsrv.StatusDeal, }, "id = ?", nbo.Id) if err != nil { return err } id = int(ctrid) return nil }) return id, txerr } var ContractApplyProcessCode = "PROC-7057E20A-2066-4644-9B35-9331E4DA912C" // 创建合同 func (s CtrContractService) Commit(ctx context.Context, req *model.CtrContractCommitReq) error { validErr := gvalid.CheckStruct(ctx, req, nil) if validErr != nil { return myerrors.TipsError(validErr.Current().Error()) } if !(req.ContractModel == "大数模板" || req.ContractModel == "客户模板") { return myerrors.TipsError("合同模板不合法") } if !(req.Terms == "接纳全部条款" || req.Terms == "不接纳全部条款") { return myerrors.TipsError("条款情况不合法") } if req.PayTerms == "" { return myerrors.TipsError("付款条件不能为空") } if len(req.File) == 0 { return myerrors.TipsError("附件不能为空") } ent, err := s.Dao.Where("id = ?", req.Id).One() if err != nil { return err } if ent == nil { return myerrors.TipsError(fmt.Sprintf("合同不存在: %d", req.Id)) } fileinfoByte, err := json.Marshal(req.File) if err != nil { return err } workflowSrv, err := workflowService.NewFlowService(ctx) if err != nil { return err } bizCode := strconv.Itoa(ent.Id) _, err = workflowSrv.StartProcessInstance(bizCode, "30", "", &workflow.StartProcessInstanceRequest{ ProcessCode: &ContractApplyProcessCode, FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{ { Id: utils.String("DDSelectField_ESX8H30W3VK0"), Name: utils.String("合同模板"), Value: utils.String(req.ContractModel), }, { Id: utils.String("DDSelectField_13IQX96C2KAK0"), Name: utils.String("条款情况"), Value: utils.String(req.Terms), }, { Id: utils.String("TextField_1A5SA7VOG5TS0"), Name: utils.String("合同编号"), Value: utils.String(ent.ContractCode), }, { Id: utils.String("TextField_1EX61DPS3LA80"), Name: utils.String("客户名称"), Value: utils.String(ent.CustName), }, { Id: utils.String("MoneyField_X1XV4KIR0GW0"), Name: utils.String("合同金额(元)"), Value: utils.String(strconv.FormatFloat(ent.ContractAmount, 'f', 2, 64)), }, { Id: utils.String("TextareaField_1WZ5ILKBUVSW0"), Name: utils.String("付款条件"), Value: utils.String(req.PayTerms), }, { Id: utils.String("DDAttachment_1051KJYC3MBK0"), Name: utils.String("附件"), // Details: productForm, Value: utils.String(string(fileinfoByte)), }, }, }) if err != nil { return err } _, err = s.Dao.Where("id = ?", ent.Id).Data(map[string]interface{}{ "appro_status": 20, }).Update() return err } // var spaceId = "21042518430" var spaceId = "21077726250" func (s CtrContractService) CommitWithFile(ctx context.Context, formData *multipart.Form) error { if s.userInfo.DingtalkUid == "" { return fmt.Errorf("该用户钉钉 uid 为空") } if len(formData.File) == 0 { return myerrors.TipsError("文件不能为空") } if _, ok := formData.File["file"]; !ok { return myerrors.TipsError("文件不能为空") } if formData.File["file"].FileName == "" { return fmt.Errorf("文件名称不能为空") } if formData.File["file"].File == nil { return fmt.Errorf("文件不能为空") } if formData.File["file"].File.Name() == "" { return fmt.Errorf("文件路径不能为空") } contractId, err := strconv.Atoi(formData.Value["contractId"]) if err != nil { return fmt.Errorf("合同 Id 不合法 %s", formData.Value["contractId"]) } //fmt.Println(args.File.Name(), args.FileName, args.FileSize, args.Meta) //fmt.Println(spaceId, s.userInfo.DingtalkId, args.FileName, args.File.Name()) // resp, err := s.UploadFile("21042518430", "8xljy04PZiS9iPxp5PhDnUzQiEiE", "引物导入模板-000000.xlsx", "/Users/chengjian/Downloads/引物导入模板.xlsx") resp, err := dingtalk.Client.GetStorage().UploadFile(spaceId, s.userInfo.DingtalkId, formData.File["file"].FileName, formData.File["file"].File.Name()) if err != nil { return fmt.Errorf("钉钉上传文件异常 %s", err.Error()) } err = s.Commit(ctx, &model.CtrContractCommitReq{ Id: contractId, ContractModel: formData.Value["contractModel"], Terms: formData.Value["terms"], PayTerms: formData.Value["payTerms"], File: []model.DingFileInfo{ { SpaceId: resp.Dentry.SpaceId, FileId: resp.Dentry.Id, FileName: resp.Dentry.Name, FileSize: resp.Dentry.Size, FileType: resp.Dentry.Extension, }, }, }) if err != nil { return err } // workflow, err := s.WorkflowDao.Where("id = ?", workflowId).One() // if err != nil { // return err // } // instance, err := dingtalk.Client.GetWorkflow().QueryProcessInstanceDetail(workflow.ProcessInstId) // if err != nil { // return fmt.Errorf("查询审批实例详情错误: %s", err.Error()) // } // fmt.Println(workflow.ProcessInstId, instance.Result.ApproverUserIds) // approverUserIds := g.Config().GetStrings("dingtalk.approver-user-ids") // fmt.Println(approverUserIds) // for _, uid := range approverUserIds { // resp, err := dingtalk.Client.GetStorage().AddPermission( // dingtalk.Client.Context.CorpId, spaceId, uid, "DOWNLOADER", "USER") // if err != nil { // return fmt.Errorf("添加审核附件权限异常: %s", err.Error()) // } // fmt.Println(uid, resp) // } appendSrv, err := NewCtrContractAppendService(ctx) if err != nil { return err } _, err = appendSrv.Add(ctx, &model.CtrContractAppendAddReq{ ContractId: contractId, FileName: resp.Dentry.Name, FileType: resp.Dentry.Extension, FileUrl: strings.Join([]string{"dingtalk", resp.Dentry.SpaceId, resp.Dentry.Id}, ":"), Remark: "", }) if err != nil { return err } return nil } func (s CtrContractService) CommitWithFileUrl(ctx context.Context, req *model.CtrContractCommitWithFileUrlReq) error { validErr := gvalid.CheckStruct(ctx, req, nil) if validErr != nil { return myerrors.TipsError(validErr.Current().Error()) } fileinfoByte, err := baseService.UploadDingtalk(s.userInfo.DingtalkId, req.FileUrl, req.FileName) if err != nil { return err } var fileinfo = []model.DingFileInfo{} err = json.Unmarshal(fileinfoByte, &fileinfo) if err != nil { return err } err = s.Commit(ctx, &model.CtrContractCommitReq{ Id: req.Id, ContractModel: req.ContractModel, Terms: req.Terms, PayTerms: req.PayTerms, File: fileinfo, }) if err != nil { return err } appendSrv, err := NewCtrContractAppendService(ctx) if err != nil { return err } _, err = appendSrv.Add(ctx, &model.CtrContractAppendAddReq{ ContractId: req.Id, FileName: fileinfo[0].FileName, FileType: fileinfo[0].FileType, FileUrl: strings.Join([]string{"dingtalk", fileinfo[0].SpaceId, fileinfo[0].FileId}, ":"), Remark: "", }) if err != nil { return err } return nil } func (s CtrContractService) DownloadDingtalkFile(ctx context.Context, id int) (string, error) { ent, err := s.AppendDao.Where("id= ?", id).One() if err != nil { return "", err } if ent == nil { return "", myerrors.TipsError("附件不存在") } if !strings.HasPrefix(ent.FileUrl, "dingtalk") { return "", myerrors.TipsError("此附件不是钉钉附件") } fileInfo := strings.Split(ent.FileUrl, ":") if len(fileInfo) != 3 { return "", myerrors.TipsError("钉钉附件地址不合法") } spaceId := fileInfo[1] fileId := fileInfo[2] // res, err := dingtalk.Client.GetStorage().AddPermission(dingtalk.Client.Context.CorpId, spaceId, s.userInfo.DingtalkId, "EDITOR", "USER") // fmt.Println(res, err) // if err != nil { // return "", fmt.Errorf("设置权限异常 %s", err.Error()) // } resp, err := dingtalk.Client.GetStorage().QueryFileDownloadInfo(spaceId, fileId, s.userInfo.DingtalkId) if err != nil { return "", myerrors.TipsError("获取文件下载信息异常") } fmt.Println(resp, err) req, err := http.NewRequest("GET", resp.HeaderSignatureInfo.ResourceUrls[0], nil) if err != nil { return "", fmt.Errorf("构建文件下载请求异常 %s", err.Error()) } for k, v := range resp.HeaderSignatureInfo.Headers { req.Header.Add(k, v) } fileresp, err := http.DefaultClient.Do(req) if err != nil { return "", fmt.Errorf("文件下载异常 %s", err.Error()) } data, err := io.ReadAll(fileresp.Body) if err != nil { return "", fmt.Errorf("读取下载内容异常 %s", err.Error()) } return base64.StdEncoding.EncodeToString(data), nil } func ContractApplyApproval(ctx context.Context, flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error { mtx.Lock() defer mtx.Unlock() tenant, err := micro_srv.GetTenant(ctx) if err != nil { return fmt.Errorf("获取租户码异常:%s", err.Error()) } contractDao := dao.NewCtrContractDao(tenant) contractId, err := strconv.Atoi(flow.BizCode) if err != nil { return fmt.Errorf("创建合同审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id) } contract, err := contractDao.Where("id = ?", contractId).One() if err != nil { return err } if contract == nil { return fmt.Errorf("合同不存在:%s Id: %d", flow.BizCode, flow.Id) } 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) } var status string if msg.ProcessType == "terminate" { status = "50" } else { pass := msg.Result == "agree" if !pass { status = "40" } else { status = "30" } } _, err = contractDao.Where("id = ?", contractId).Data(map[string]interface{}{ "appro_status": status, }).Update() if err != nil { return err } if status != "30" { return nil } return contractDao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { // 交付状态(0发起 10项目立项 15进行中 20 完成 30审批拒绝40关闭) _, err = worksrv.DeliverOrderAdd(tx, contractId, request.UserInfo{}, nil, "10") return err }) } func (s CtrContractService) Update(ctx context.Context, req *model.CtrContractUpdateReq) error { validErr := gvalid.CheckStruct(ctx, req, nil) if validErr != nil { return myerrors.TipsError(validErr.Current().Error()) } ent, err := s.Dao.Where("id = ?", req.Id).One() if err != nil { return err } if ent == nil { return myerrors.TipsError(fmt.Sprintf("合同不存在: %d", req.Id)) } // if req.ContractCode != "" { // exist, err := s.Dao.Where("contract_code = ?", req.ContractCode).One() // if err != nil { // return err // } // if exist != nil && exist.Id != req.Id { // return myerrors.NewMsgError(nil, fmt.Sprintf("合同编号:%s 已存在", req.ContractCode)) // } // } if req.ContractName != "" { exist, err := s.Dao.Where("contract_name = ?", req.ContractName).One() if err != nil { return err } if exist != nil && exist.Id != req.Id { return myerrors.TipsError(fmt.Sprintf("合同名称:%s 已存在", req.ContractName)) } } var nbo *proj.ProjBusiness if req.NboId != 0 { nbo, err = s.ProjBusinessDao.Where("id = ?", req.NboId).One() if err != nil { return err } if nbo == nil { return myerrors.TipsError("项目不存在") } } toupdate := map[string]interface{}{} // if req.ContractCode != "" { // toupdate["contract_code"] = req.ContractCode // } if req.ContractName != "" { toupdate["contract_name"] = req.ContractName } if req.NboId != 0 { toupdate["cust_id"] = nbo.CustId toupdate["cust_name"] = nbo.CustName toupdate["nbo_id"] = nbo.Id toupdate["nbo_name"] = nbo.NboName toupdate["is_big"] = nbo.IsBig toupdate["product_line"] = nbo.ProductLine toupdate["cust_province_id"] = nbo.CustProvinceId toupdate["cust_province"] = nbo.CustProvince toupdate["cust_city_id"] = nbo.CustCityId toupdate["cust_city"] = nbo.CustCity } // if req.ApproStatus != "" { // toupdate["appro_status"] = req.ApproStatus // } if req.ContractType != "" { toupdate["contract_type"] = req.ContractType } // if req.ContractAmount != 0 { // toupdate["contract_amount"] = req.ContractAmount // } // if req.InvoiceAmount != 0 { // toupdate["invoice_amount"] = req.InvoiceAmount // } // if req.CollectedAmount != 0 { // toupdate["collected_amount"] = req.CollectedAmount // } if req.ContractStartTime != nil { toupdate["contract_start_time"] = req.ContractStartTime } if req.ContractEndTime != nil { toupdate["contract_end_time"] = req.ContractEndTime } if req.ContractSignTime != nil { toupdate["contract_sign_time"] = req.ContractSignTime } //if req.InchargeId != 0 { // toupdate["incharge_id"] = req.InchargeId //} //if req.InchargeName != "" { // toupdate["incharge_name"] = req.InchargeName //} if req.SignatoryId != 0 { toupdate["signatory_id"] = req.SignatoryId } if req.SignatoryName != "" { toupdate["signatory_name"] = req.SignatoryName } if req.SignatoryType != "" { toupdate["signatory_type"] = req.SignatoryType } if req.SignatoryUnit != "" { toupdate["signatory_unit"] = req.SignatoryUnit } if req.EarnestMoney != nil { toupdate["earnest_money"] = req.EarnestMoney } if req.CustSignatoryId != 0 { toupdate["cust_signatory_id"] = req.CustSignatoryId } if req.CustSignatoryName != "" { toupdate["cust_signatory_name"] = req.CustSignatoryName } if req.DistributorId != 0 { toupdate["distributor_id"] = req.DistributorId } if req.DistributorName != "" { toupdate["distributor_name"] = req.DistributorName } if req.Remark != nil { toupdate["remark"] = *req.Remark } if req.Product != nil { var contractAmount float64 for _, p := range *req.Product { contractAmount += (p.TranPrice * float64(p.ProdNum)) } toupdate["contract_amount"] = contractAmount } if len(toupdate) != 0 { toupdate["updated_by"] = int(s.userInfo.Id) toupdate["updated_name"] = s.userInfo.NickName toupdate["updated_time"] = gtime.Now() txerr := s.Dao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Update("ctr_contract", toupdate, "id = ?", req.Id) if err != nil { return err } if req.Product != nil { err = s.BindProduct(tx, req.Id, ent.ContractCode, *req.Product) if err != nil { return err } } return nil }) if txerr != nil { return txerr } } return nil } func (s CtrContractService) UpdateProduct(ctx context.Context, req *model.CtrContractUpdateProductReq) error { validErr := gvalid.CheckStruct(ctx, req, nil) if validErr != nil { return myerrors.TipsError(validErr.Current().Error()) } ent, err := s.CtrProductDao.Where("id = ?", req.Id).One() if err != nil { return err } if ent == nil { return myerrors.TipsError(fmt.Sprintf("合同产品记录不存在: %d", req.Id)) } toupdate := map[string]interface{}{} if req.MaintainPeriod != nil { toupdate["maintain_period"] = req.MaintainPeriod } if req.WarrantPeriod != nil { toupdate["warrant_period"] = req.WarrantPeriod } if req.MaintainStartTime != nil { toupdate["maintain_start_time"] = req.MaintainStartTime } if req.MaintainRemark != nil { toupdate["maintain_remark"] = req.MaintainRemark } if req.AcceptTime != nil { toupdate["accept_time"] = req.AcceptTime } if req.PurchaseCost != nil { toupdate["purchase_cost"] = req.PurchaseCost } if req.DevCost != nil { toupdate["dev_cost"] = req.DevCost } if req.MaintainCost != nil { toupdate["maintain_cost"] = req.MaintainCost } if req.DirectCost != nil { toupdate["direct_cost"] = req.DirectCost } if len(toupdate) != 0 { toupdate["updated_by"] = int(s.userInfo.Id) toupdate["updated_name"] = s.userInfo.NickName toupdate["updated_time"] = gtime.Now() txerr := s.Dao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Update("ctr_contract_product", toupdate, "id = ?", req.Id) if err != nil { return err } err = s.AddDynamicsByCurrentUser(tx, ent.ContractId, "更新合同产品信息", toupdate) if err != nil { return err } return nil }) if txerr != nil { return txerr } } return nil } func (s CtrContractService) Transfer(ctx context.Context, req *model.CtrContractTransferReq) error { if len(req.Id) == 0 { return nil } ents := map[int]*model.CtrContract{} for _, i := range req.Id { ent, err := s.Dao.Where("id = ?", i).One() if err != nil { return err } if ent == nil { return myerrors.TipsError(fmt.Sprintf("合同不存在: %d", req.Id)) } ents[ent.Id] = ent } txerr := s.Dao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { toupdate := map[string]interface{}{ "incharge_id": req.InchargeId, "incharge_name": req.InchargeName, } _, err := tx.Update("ctr_contract", toupdate, "id in (?)", req.Id) if err != nil { return err } for _, ent := range ents { err = s.AddDynamicsByCurrentUser(tx, ent.Id, "转移合同", map[string]interface{}{ "toInchargeId": req.InchargeId, "toInchargeName": req.InchargeName, "fromInchargeId": ent.InchargeId, "fromInchargeName": ent.InchargeName, "operatedId": s.userInfo.Id, "operatedName": s.userInfo.NickName, }) if err != nil { return err } } return nil }) if txerr != nil { return txerr } return nil } func (s CtrContractService) UpdateInvoiceAmount(tx *gdb.TX, id int) error { ctr := model.CtrContract{} err := tx.GetStruct(&ctr, "select * from ctr_contract where id = ?", id) if err == sql.ErrNoRows { return myerrors.TipsError(fmt.Sprintf("合同不存在 %d", id)) } if err != nil { return err } v, err := tx.GetValue("select sum(invoice_amount) from ctr_contract_invoice where contract_id=? and appro_status='30' and deleted_time is null", id) if err != nil { return err } amount := v.Float64() _, err = tx.Update("ctr_contract", map[string]interface{}{ "invoice_amount": amount, }, "id = ?", id) if err != nil { return err } return nil } func (s CtrContractService) UpdateCollectedAmount(tx *gdb.TX, id int) error { ctr := model.CtrContract{} err := tx.GetStruct(&ctr, "select * from ctr_contract where id = ?", id) if err == sql.ErrNoRows { return myerrors.TipsError(fmt.Sprintf("合同不存在 %d", id)) } if err != nil { return err } v, err := tx.GetValue("select sum(collection_amount) from ctr_contract_collection where contract_id=? and appro_status='20' and deleted_time is null", id) if err != nil { return err } amount := v.Float64() _, err = tx.Update("ctr_contract", map[string]interface{}{ "collected_amount": amount, }, "id = ?", id) if err != nil { return err } return nil } func (s CtrContractService) Delete(ctx context.Context, id []int) error { if len(id) == 0 { return nil } _, err := s.Dao.Where("Id IN (?)", id).Delete() return err } func init() { tenant := g.Config().GetString("micro_srv.tenant") if tenant == "" { panic("定时任务租户码未设置,请前往配置") } contractDao := dao.NewCtrContractDao(tenant) produceDao := dao.NewCtrContractProductDao(tenant) job := func() { alert := map[int]*[]model.CtrContractProduct{ 180: {}, 90: {}, 30: {}, 10: {}, // 7: {}, } where := `DATE_FORMAT(DATE_ADD(maintain_start_time, INTERVAL ? day), "%Y-%m-%d") = DATE_FORMAT(NOW(), "%Y-%m-%d")` for day, p := range alert { err := produceDao.Where(where, day).Structs(p) if err != nil { glog.Error(err) } glog.Infof("运维期到期 %d 天提醒,产品个数 %d", day, len(*p)) } for day, p := range alert { for _, i := range *p { ctr, err := contractDao.Where("id = ?", i.ContractId).One() if err != nil { glog.Error(err) } text := fmt.Sprintf("合同:%s-%s 中的产品:%s 距离运维到期还有 %d 天", ctr.ContractCode, ctr.ContractName, i.ProdName, day) msg := g.MapStrStr{ "msgTitle": "运维期到期提醒", "msgContent": text, "msgType": "20", "recvUserIds": strconv.Itoa(ctr.InchargeId), "msgStatus": "10", "sendType": "10", } if err := service.CreateSystemMessage(msg); err != nil { glog.Error("消息提醒异常:", err) } glog.Infof("%s", text) } } } // 每天凌晨2点执行 gcron.AddSingleton("0 0 2 * * *", job) // job() }