package base import ( "context" "database/sql" "encoding/json" "fmt" "io/ioutil" "net/http" "os" "path" "strconv" "strings" "time" "github.com/gogf/gf/container/garray" "dashoo.cn/opms_libary/micro_srv" "dashoo.cn/opms_libary/myerrors" "dashoo.cn/opms_libary/plugin/dingtalk" "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/gconv" "github.com/gogf/gf/util/gvalid" "dashoo.cn/micro/app/dao/base" contractdao "dashoo.cn/micro/app/dao/contract" projdao "dashoo.cn/micro/app/dao/proj" model "dashoo.cn/micro/app/model/base" contractmodel "dashoo.cn/micro/app/model/contract" projmodel "dashoo.cn/micro/app/model/proj" workflowmodel "dashoo.cn/micro/app/model/workflow" "dashoo.cn/micro/app/service" workflowService "dashoo.cn/micro/app/service/workflow" "dashoo.cn/opms_libary/plugin/dingtalk/message" "dashoo.cn/opms_libary/plugin/dingtalk/workflow" "dashoo.cn/opms_libary/utils" ) type distributorService struct { *service.ContextService Dao *base.BaseDistributorDao DynamicsDao *base.BaseDistributorDynamicsDao TargetDao *base.BaseDistributorTargetDao RecordDao *base.BaseDistributorRecordDao ProjDao *projdao.ProjBusinessDao ContractDao *contractdao.CtrContractDao } func NewDistributorService(ctx context.Context) (svc *distributorService, err error) { svc = new(distributorService) if svc.ContextService, err = svc.Init(ctx); err != nil { return nil, err } svc.Dao = base.NewBaseDistributorDao(svc.Tenant) svc.DynamicsDao = base.NewBaseDistributorDynamicsDao(svc.Tenant) svc.ProjDao = projdao.NewProjBusinessDao(svc.Tenant) svc.ContractDao = contractdao.NewCtrContractDao(svc.Tenant) svc.TargetDao = base.NewBaseDistributorTargetDao(svc.Tenant) svc.RecordDao = base.NewBaseDistributorRecordDao(svc.Tenant) return svc, nil } // GetList 经销商信息列表 func (s *distributorService) GetList(ctx context.Context, req *model.BaseDistributorSearchReq) (total int, distributorList []*model.BaseDistributorListRsp, err error) { distributorModel := s.Dao.FieldsEx(s.Dao.C.DeletedTime) if garray.NewStrArrayFrom(s.CxtUser.Roles, true).Contains("SalesEngineer") { distributorModel = distributorModel.DataScope(s.Ctx, "belong_sale_id") } if req.DistCode != "" { distributorModel = distributorModel.WhereLike(s.Dao.C.DistCode, "%"+req.DistCode+"%") } if req.DistName != "" { distributorModel = distributorModel.WhereLike(s.Dao.C.DistName, "%"+req.DistName+"%") } if req.BelongSale != "" { distributorModel = distributorModel.WhereLike(s.Dao.C.BelongSale, "%"+req.BelongSale+"%") } if len(req.ProvinceId) > 0 { distributorModel = distributorModel.WhereIn(s.Dao.C.ProvinceId, req.ProvinceId) } if req.DistType != "" { distributorModel = distributorModel.WhereIn(s.Dao.C.DistType, req.DistType) } total, err = distributorModel.Count() if err != nil { err = myerrors.DbError("获取总行数失败。") return } err = distributorModel.Page(req.GetPage()).Order("id desc").Scan(&distributorList) if req.WithStatistic { for i, dist := range distributorList { statistic, err := s.statistic(dist.Id) if err != nil { return 0, nil, err } distributorList[i].BaseDistributorStatistic = statistic } } return } func (s *distributorService) statistic(id int) (stat model.BaseDistributorStatistic, err error) { v, err := s.Dao.DB.GetValue("select count(*) from proj_business where distributor_id=? and appro_status ='30' and nbo_type in (10,20,30) and deleted_time is null", id) if err != nil { return stat, err } stat.ProjectNum = v.Int() v, err = s.Dao.DB.GetValue("select sum(est_trans_price) from proj_business where distributor_id=? and appro_status ='30' and nbo_type in (10,20,30) and deleted_time is null", id) if err != nil { return stat, err } stat.AllProductAmount = v.Float64() v, err = s.Dao.DB.GetValue("select count(distinct(b.id)) from ctr_contract a left join proj_business b on a.nbo_id=b.id where a.distributor_id=? and a.appro_status ='30' and b.appro_status ='30' and a.deleted_time is null and b.deleted_time is null", id) if err != nil { return stat, err } stat.SaledProjectNum = v.Int() v, err = s.Dao.DB.GetValue("select sum(contract_amount) from ctr_contract where distributor_id=? and appro_status='30' and deleted_time is null", id) if err != nil { return stat, err } stat.SaledAmount = v.Float64() v, err = s.Dao.DB.GetValue("select sum(contract_amount - collected_amount) from ctr_contract where distributor_id=? and appro_status='30' and deleted_time is null", id) if err != nil { return stat, err } stat.UnpaidAmount = v.Float64() v, err = s.Dao.DB.GetValue("select sum(invoice_amount) from ctr_contract where distributor_id=? and appro_status='30' and deleted_time is null", id) if err != nil { return stat, err } stat.InvoicedAmount = v.Float64() return } // 获取经销商编号 func (s *distributorService) getDistributorCode(distCode string) (string, error) { sequence, err := service.Sequence(s.Dao.DB, "distributor_code") if err != nil { return "", err } return distCode + sequence, nil } // Create 经销商创建 func (s *distributorService) Create(ctx context.Context, req *model.AddDistributor) (int64, error) { if req.DistType == "10" { if req.DistName == "" { return 0, myerrors.TipsError("经销商名称不能为空") } if req.ProvinceId == 0 { return 0, myerrors.TipsError("所属省份Id不能为空") } if req.ProvinceDesc == "" { return 0, myerrors.TipsError("所属省份名称不能为空") } if req.RegisterDistrict == "" { return 0, myerrors.TipsError("注册地不能为空") } if req.BelongSaleId == 0 { return 0, myerrors.TipsError("归属销售ID不能为空") } if req.BelongSale == "" { return 0, myerrors.TipsError("归属销售不能为空") } } else { if err := gvalid.CheckStruct(ctx, req, nil); err != nil { return 0, err } } DistributorData := new(model.BaseDistributor) if err := gconv.Struct(req, DistributorData); err != nil { return 0, err } code, err := s.getDistributorCode("JXS") if err != nil { return 0, err } DistributorData.DistCode = code if DistributorData.DistType == "20" { DistributorData.ApproItem = "创建代理商" DistributorData.ApproStatus = "20" if req.ContractUrl != "" && req.ContractFileName == "" { return 0, myerrors.TipsError("合同文件名不能为空") } } service.SetCreatedInfo(DistributorData, s.GetCxtUserId(), s.GetCxtUserName()) var id int64 txerr := s.Dao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { id, err = tx.InsertAndGetId("base_distributor", DistributorData) if err != nil { return err } DistributorData.Id = int(id) if DistributorData.DistType == "20" { err = s.createDingtalkProcess(ctx, DistributorData, req.ContractFileName) if err != nil { return err } } err = s.AddDynamicsByCurrentUser(tx, int(id), "创建经销商/代理商", map[string]interface{}{}) return err }) if txerr != nil { return 0, txerr } if req.ProvinceId == 0 || req.BelongSaleId == 0 || req.Capital == 0 || req.RegisterDistrict == "" || req.BusinessScope == "" || req.SaleNum == 0 || req.CustomerType == "" || req.ExistedProduct == "" || req.HistoryCustomer == "" { msg := g.MapStrStr{ "msgTitle": "经销商信息完善提醒", "msgContent": fmt.Sprintf("
经销商:%s 的必要信息未填写完整,请及时完善
", distUrl(*DistributorData), req.DistName), "msgType": "20", "recvUserIds": strconv.Itoa(req.BelongSaleId), "msgStatus": "10", "sendType": "10", } if err := service.CreateSystemMessage(msg); err != nil { g.Log().Error("经销商信息完善提醒异常:", err) } } return id, nil } func distUrl(ent model.BaseDistributor) string { if ent.DistType == "20" { return fmt.Sprintf("#/base/agentDetails?id=%d", ent.Id) } return fmt.Sprintf("#/base/info?id=%d", ent.Id) } var ProcessCodeDistProxyCreate = "PROC-9494B87D-DE96-49EE-B676-D3913911BE21" // 创建代理商 func (s *distributorService) createDingtalkProcess(ctx context.Context, ent *model.BaseDistributor, contractFileName string) error { var fileinfoByte []byte if ent.ContractUrl != "" { var err error fileinfoByte, err = UploadDingtalk(s.CxtUser.DingtalkId, ent.ContractUrl, contractFileName) if err != nil { return err } } workflowSrv, err := workflowService.NewFlowService(ctx) if err != nil { return err } bizCode := strconv.Itoa(ent.Id) form := []*workflow.StartProcessInstanceRequestFormComponentValues{ { Id: utils.String("TextField-K2AD4O5B"), Name: utils.String("代理商名称"), Value: utils.String(ent.DistName), }, { Id: utils.String("TextField_DZ2HNXRKHCG"), Name: utils.String("所在省"), Value: utils.String(ent.ProvinceDesc), }, { Id: utils.String("TextField_1M07EV7YVOPS0"), Name: utils.String("业务范围"), Value: utils.String(ent.BusinessScope), }, { Id: utils.String("TextField_UGJ0UKCU5DS0"), Name: utils.String("注册资金(万元)"), Value: utils.String(strconv.FormatFloat(ent.Capital, 'f', 2, 64)), }, { Id: utils.String("TextField_1RC4FO1WUZ4W0"), Name: utils.String("注册地"), Value: utils.String(ent.RegisterDistrict), }, { Id: utils.String("TextField_FKM6LUQYLFS0"), Name: utils.String("现有销售人数"), Value: utils.String(strconv.Itoa(ent.SaleNum)), }, { Id: utils.String("TextField_1L89WCJM3ZMO0"), Name: utils.String("已有代理名牌和产品"), Value: utils.String(ent.ExistedProduct), }, { Id: utils.String("TextField_P5JA5OZ5XKW0"), Name: utils.String("历史合作的终端客户名称"), Value: utils.String(ent.HistoryCustomer), }, } if len(fileinfoByte) != 0 { form = append(form, &workflow.StartProcessInstanceRequestFormComponentValues{ Id: utils.String("DDAttachment_SD6QFFBOSAO0"), Name: utils.String("代理合同"), Value: utils.String(string(fileinfoByte)), }) } _, err = workflowSrv.StartProcessInstance(bizCode, workflowmodel.DistProxyCreate, "", &workflow.StartProcessInstanceRequest{ ProcessCode: &ProcessCodeDistProxyCreate, FormComponentValues: form, }) return err } // GetEntityById 详情 func (s *distributorService) GetEntityById(id int64) (distributorInfo *model.BaseDistributorListRsp, err error) { err = s.Dao.Where(base.BaseProduct.C.Id, id).Scan(&distributorInfo) if err != nil { return nil, err } statistic, err := s.statistic(int(id)) if err != nil { return nil, err } distributorInfo.BaseDistributorStatistic = statistic target, err := s.TargetDao.Where("dist_id = ?", id).Where("year = ?", time.Now().Year()).One() if err != nil { return nil, err } if target != nil { distributorInfo.YearTarget = target.Total } return } // UpdateById 修改数据 func (s *distributorService) UpdateById(req *model.UpdateDistributorReq) (err error) { ent, err := s.Dao.Where("id = ", req.Id).One() if err != nil { g.Log().Error(err) return } if ent == nil { err = myerrors.TipsError("无修改数据") return } if ent.ApproStatus == "20" { err = myerrors.TipsError("不能修改待审核数据") return } distData := new(model.BaseDistributor) if err = gconv.Struct(req, distData); err != nil { return } service.SetUpdatedInfo(distData, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.Dao.FieldsEx(s.Dao.C.DistCode, s.Dao.C.Id, s.Dao.C.CreatedName, s.Dao.C.CreatedBy, s.Dao.C.CreatedTime).WherePri(s.Dao.C.Id, req.Id).Update(distData) if err != nil { g.Log().Error(err) return } err = s.Dao.DB.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { err = s.AddDynamicsByCurrentUser(tx, req.Id, "更新经销商/代理商", map[string]interface{}{}) return err }) return } func (s *distributorService) ToProxy(ctx context.Context, req *model.DistributorToProxyReq) (err error) { validErr := gvalid.CheckStruct(ctx, req, nil) if validErr != nil { return myerrors.TipsError(validErr.Current().Error()) } if req.ContractUrl != "" && req.ContractFileName == "" { 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)) } approvalData := model.ToProxyApproveData{ CustomerType: req.CustomerType, ProxyStartTime: req.ProxyStartTime, ProxyEndTime: req.ProxyEndTime, ProxyDistrict: req.ProxyDistrict, ContractUrl: req.ContractUrl, OperatedId: s.CxtUser.Id, OperatedName: s.CxtUser.NickName, } approvalDataByte, err := json.Marshal(approvalData) if err != nil { return err } txerr := s.Dao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Update("base_distributor", map[string]interface{}{ "appro_status": "20", "appro_data": string(approvalDataByte), "appro_item": "经销商转代理商", }, "id = ?", req.Id) if err != nil { return err } return s.toProxyDingtalkProcess(ctx, ent, req) }) return txerr } var ProcessCodeDistToProxy = "PROC-39C96165-131C-48EC-B8C0-AA528E0C9F3A" // 经销商转代理商 func (s *distributorService) toProxyDingtalkProcess(ctx context.Context, ent *model.BaseDistributor, req *model.DistributorToProxyReq) error { var fileinfoByte []byte if req.ContractUrl != "" { var err error fileinfoByte, err = UploadDingtalk(s.CxtUser.DingtalkId, req.ContractUrl, req.ContractFileName) if err != nil { return err } } cusTypeMap, err := service.GetDictDataByType(ctx, "cust_idy") if err != nil { return err } cusType := []string{} for _, t := range strings.Split(req.CustomerType, ",") { if v := cusTypeMap[t]; v != "" { cusType = append(cusType, v) } } custTypeByte, err := json.Marshal(cusType) if err != nil { return err } proxyTime := req.ProxyStartTime.Time.Format("2006/01/02") + "-" + req.ProxyEndTime.Time.Format("2006/01/02") workflowSrv, err := workflowService.NewFlowService(ctx) if err != nil { return err } form := []*workflow.StartProcessInstanceRequestFormComponentValues{ { Id: utils.String("TextField-K2AD4O5B"), Name: utils.String("代理商名称"), Value: utils.String(ent.DistName), }, { Id: utils.String("DDSelectField_X3ALRAZA4BK0"), Name: utils.String("授权客户类型"), Value: utils.String(string(custTypeByte)), }, { Id: utils.String("TextField_1M07EV7YVOPS0"), Name: utils.String("授权代理区域"), Value: utils.String(req.ProxyDistrict), }, { Id: utils.String("TextField_UGJ0UKCU5DS0"), Name: utils.String("代理签约有效期"), Value: utils.String(proxyTime), }, } if len(fileinfoByte) != 0 { form = append(form, &workflow.StartProcessInstanceRequestFormComponentValues{ Id: utils.String("DDAttachment_SD6QFFBOSAO0"), Name: utils.String("代理合同"), Value: utils.String(string(fileinfoByte)), }) } bizCode := strconv.Itoa(ent.Id) _, err = workflowSrv.StartProcessInstance(bizCode, workflowmodel.DistToProxy, "", &workflow.StartProcessInstanceRequest{ ProcessCode: &ProcessCodeDistToProxy, FormComponentValues: form, }) return err } func (s *distributorService) Renew(ctx context.Context, req *model.DistributorRenewReq) (err error) { validErr := gvalid.CheckStruct(ctx, req, nil) if validErr != nil { return myerrors.TipsError(validErr.Current().Error()) } if req.ContractUrl != "" && req.ContractFileName == "" { 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)) } approvalData := model.RenewApproveData{ CustomerType: req.CustomerType, ProxyStartTime: req.ProxyStartTime, ProxyEndTime: req.ProxyEndTime, ProxyDistrict: req.ProxyDistrict, ContractUrl: req.ContractUrl, OperatedId: s.CxtUser.Id, OperatedName: s.CxtUser.NickName, } approvalDataByte, err := json.Marshal(approvalData) if err != nil { return err } txerr := s.Dao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Update("base_distributor", map[string]interface{}{ "appro_status": "20", "appro_data": string(approvalDataByte), "appro_item": "代理商续签", }, "id = ?", req.Id) if err != nil { return err } return s.renewDingtalkProcess(ctx, ent, req) }) return txerr } var ProcessCodeDistRenew = "PROC-33514974-4E38-430F-A852-D5694944F20B" // 代理商续签 func (s *distributorService) renewDingtalkProcess(ctx context.Context, ent *model.BaseDistributor, req *model.DistributorRenewReq) error { var fileinfoByte []byte if req.ContractUrl != "" { var err error fileinfoByte, err = UploadDingtalk(s.CxtUser.DingtalkId, req.ContractUrl, req.ContractFileName) if err != nil { return err } } cusTypeMap, err := service.GetDictDataByType(ctx, "cust_idy") if err != nil { return err } cusType := []string{} for _, t := range strings.Split(req.CustomerType, ",") { if v := cusTypeMap[t]; v != "" { cusType = append(cusType, v) } } custTypeByte, err := json.Marshal(cusType) if err != nil { return err } proxyTime := req.ProxyStartTime.Time.Format("2006/01/02") + "-" + req.ProxyEndTime.Time.Format("2006/01/02") workflowSrv, err := workflowService.NewFlowService(ctx) if err != nil { return err } form := []*workflow.StartProcessInstanceRequestFormComponentValues{ { Id: utils.String("TextField-K2AD4O5B"), Name: utils.String("代理商名称"), Value: utils.String(ent.DistName), }, { Id: utils.String("DDSelectField_X3ALRAZA4BK0"), Name: utils.String("授权客户类型"), Value: utils.String(string(custTypeByte)), }, { Id: utils.String("TextField_1M07EV7YVOPS0"), Name: utils.String("授权代理区域"), Value: utils.String(req.ProxyDistrict), }, { Id: utils.String("TextField_UGJ0UKCU5DS0"), Name: utils.String("代理签约有效期"), Value: utils.String(proxyTime), }, } if len(fileinfoByte) != 0 { form = append(form, &workflow.StartProcessInstanceRequestFormComponentValues{ Id: utils.String("DDAttachment_SD6QFFBOSAO0"), Name: utils.String("代理合同"), Value: utils.String(string(fileinfoByte)), }) } bizCode := strconv.Itoa(ent.Id) _, err = workflowSrv.StartProcessInstance(bizCode, workflowmodel.DistProxyRenew, "", &workflow.StartProcessInstanceRequest{ ProcessCode: &ProcessCodeDistRenew, FormComponentValues: form, }) return err } func (s *distributorService) ToDist(ctx context.Context, req *model.DistributorToDistReq) (err 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)) } approvalData := model.ToDistApproveData{ ToDistReason: req.ToDistReason, OperatedId: s.CxtUser.Id, OperatedName: s.CxtUser.NickName, } approvalDataByte, err := json.Marshal(approvalData) if err != nil { return err } txerr := s.Dao.DB.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Update("base_distributor", map[string]interface{}{ "appro_status": "20", "appro_data": string(approvalDataByte), "appro_item": "代理商转经销商", }, "id = ?", req.Id) if err != nil { return err } return s.toDistDingtalkProcess(ctx, ent, req) }) return txerr } var ProcessCodeProxyToDist = "PROC-59A0E9F5-8233-41D5-B36D-021F3E8B48D2" // 代理商转经销商 func (s *distributorService) toDistDingtalkProcess(ctx context.Context, ent *model.BaseDistributor, req *model.DistributorToDistReq) error { workflowSrv, err := workflowService.NewFlowService(ctx) if err != nil { return err } form := []*workflow.StartProcessInstanceRequestFormComponentValues{ { Id: utils.String("TextField-K2AD4O5B"), Name: utils.String("代理商名称"), Value: utils.String(ent.DistName), }, { Id: utils.String("TextareaField_5XMN9CGTDAS0"), Name: utils.String("转移原因"), Value: utils.String(req.ToDistReason), }, } bizCode := strconv.Itoa(ent.Id) _, err = workflowSrv.StartProcessInstance(bizCode, workflowmodel.DistToDist, "", &workflow.StartProcessInstanceRequest{ ProcessCode: &ProcessCodeProxyToDist, FormComponentValues: form, }) return err } func (s *distributorService) TransRecord(ctx context.Context, req *model.DistributorTransRecordReq) (int, []*model.BaseDistributorRecord, error) { dao := s.RecordDao.As("a") if req.DistId != 0 { dao = dao.Where("a.dist_id = ?", req.DistId) } total, err := dao.Count() if err != nil { return 0, nil, err } if req.PageNum != 0 { dao = dao.Page(req.GetPage()) } orderby := "a.created_time desc" if req.OrderBy != "" { orderby = req.OrderBy } dao = dao.Order(orderby) ents := []*model.BaseDistributorRecord{} err = dao.Structs(&ents) if err != nil && err != sql.ErrNoRows { return 0, nil, err } return total, ents, nil } func (s *distributorService) SysAdminTransferDistributor(ctx context.Context, req *model.SysAdminTransferDistributorReq) (err error) { // 校验用户是否有修改权限 arr := garray.NewStrArrayFrom(s.CxtUser.Roles, true) if !arr.Contains("SysAdmin") { return myerrors.TipsError("权限不足") } var updateData = g.Map{} updateData[s.Dao.C.BelongSaleId] = req.UserId updateData[s.Dao.C.BelongSale] = req.UserName service.SetUpdatedInfo(updateData, s.GetCxtUserId(), s.GetCxtUserName()) dynamicsList := make([]model.BaseDistributorDynamics, 0) for _, id := range req.Ids { dynamics := model.BaseDistributorDynamics{ DistId: id, OpnPeopleId: s.GetCxtUserId(), OpnPeople: s.GetCxtUserName(), OpnDate: gtime.Now(), OpnType: "转移渠道", OpnContent: gconv.String(g.Map{"toUserId": req.UserId, "toUserNickName": req.UserName, "operName": s.GetCxtUserName()}), Remark: "", CreatedBy: s.GetCxtUserId(), CreatedName: s.GetCxtUserName(), } dynamicsList = append(dynamicsList, dynamics) } err = s.Dao.Transaction(s.Ctx, func(ctx context.Context, tx *gdb.TX) error { // 项目修改 _, err = s.Dao.TX(tx).WherePri(req.Ids).FieldsEx(service.UpdateFieldEx...).Data(updateData).Update() if err != nil { return err } _, err = s.DynamicsDao.TX(tx).InsertAndGetId(dynamicsList) return err }) return err } // DeleteByIds 删除 func (s *distributorService) DeleteByIds(ids []int64) (err error) { _, err = s.Dao.WhereIn(s.Dao.C.Id, ids).Delete() if err != nil { return err } return } func (s *distributorService) AddDynamicsByCurrentUser(tx *gdb.TX, distId int, opnType string, content map[string]interface{}) error { contentByte, err := json.Marshal(content) if err != nil { return err } _, err = tx.InsertAndGetId("base_distributor_dynamics", model.BaseDistributorDynamics{ DistId: distId, OpnPeopleId: s.GetCxtUserId(), OpnPeople: s.GetCxtUserName(), OpnDate: gtime.Now(), OpnType: opnType, OpnContent: string(contentByte), Remark: "", CreatedBy: s.GetCxtUserId(), CreatedName: s.GetCxtUserName(), CreatedTime: gtime.Now(), UpdatedBy: s.GetCxtUserId(), UpdatedName: s.GetCxtUserName(), UpdatedTime: gtime.Now(), }) return err } func (s *distributorService) ContractList(ctx context.Context, req *model.DistributorContractListReq) (int, []*contractmodel.CtrContractListRsp, error) { dao := s.ContractDao.As("a") if req.DistId != 0 { dao = dao.Where("a.distributor_id = ?", req.DistId) } 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.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.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) } total, err := dao.Count() if err != nil { return 0, nil, err } if req.PageNum != 0 { dao = dao.Page(req.GetPage()) } orderby := "a.created_time desc" if req.OrderBy != "" { orderby = req.OrderBy } dao = dao.Order(orderby) ents := []*contractmodel.CtrContractListRsp{} err = dao.Structs(&ents) if err != nil && err != sql.ErrNoRows { return 0, nil, err } return total, ents, nil } func (s *distributorService) ProjectList(ctx context.Context, req *model.DistributorProjectListReq) (int, []*projmodel.ProjBusiness, error) { dao := &s.ProjDao.ProjBusinessDao if req.DistId != 0 { dao = dao.Where("distributor_id = ?", req.DistId) } if req.SearchText != "" { likestr := fmt.Sprintf("%%%s%%", req.SearchText) dao = dao.Where("(cust_name LIKE ? || nbo_name LIKE ?)", likestr, likestr) } if req.NboName != "" { likestr := fmt.Sprintf("%%%s%%", req.NboName) dao = dao.Where("nbo_name like ?", likestr) } if req.CustName != "" { likestr := fmt.Sprintf("%%%s%%", req.CustName) dao = dao.Where("cust_name like ?", likestr) } if req.CreatedTimeStart != nil { dao = dao.Where("created_time > ?", req.CreatedTimeStart) } if req.CreatedTimeEnd != nil { dao = dao.Where("created_time < ?", req.CreatedTimeEnd) } 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 := []*projmodel.ProjBusiness{} err = dao.Structs(&ents) if err != nil && err != sql.ErrNoRows { return 0, nil, err } return total, ents, nil } func (s *distributorService) DynamicsList(ctx context.Context, req *model.DistributorDynamicsListReq) (int, interface{}, error) { dao := &s.DynamicsDao.BaseDistributorDynamicsDao if req.SearchText != "" { likestr := fmt.Sprintf("%%%s%%", req.SearchText) dao = dao.Where("(opn_people LIKE ? || opn_content LIKE ?)", likestr, likestr) } if req.DistId != 0 { dao = dao.Where("dist_id = ?", req.DistId) } 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.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.BaseDistributorDynamics{} err = dao.Structs(&ents) if err != nil && err != sql.ErrNoRows { return 0, nil, err } ret := map[string][]*model.BaseDistributorDynamics{} for _, ent := range ents { date := ent.OpnDate.Format("Y-m-d") ret[date] = append(ret[date], ent) } return total, ret, err } func DownFile(url string) ([]byte, error) { r, err := http.Get(url) if err != nil { return nil, err } if r.StatusCode != http.StatusOK { return nil, fmt.Errorf("DownFile from %s StatusCode %d", url, r.StatusCode) } defer r.Body.Close() return ioutil.ReadAll(r.Body) } // '审核状态 20 待审核 30 审核已同意 40 审核已拒绝 50 审核已撤销' func ApprovalProxyCreate(ctx context.Context, flow *workflowmodel.PlatWorkflow, msg *message.MixMessage) error { tenant, err := micro_srv.GetTenant(ctx) if err != nil { return fmt.Errorf("获取租户码异常:%s", err.Error()) } distdao := base.NewBaseDistributorDao(tenant) entId, err := strconv.Atoi(flow.BizCode) if err != nil { return fmt.Errorf("创建代理商钉钉审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id) } ent, err := distdao.Where("id = ?", entId).One() if err != nil { return err } if ent == 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) } if msg.ProcessType == "terminate" { _, err = distdao.Where("id = ?", entId).Data(map[string]interface{}{ "appro_status": "50", "appro_data": "", }).Update() return err } pass := msg.Result == "agree" if !pass { _, err = distdao.Where("id = ?", entId).Data(map[string]interface{}{ "appro_status": "40", "appro_data": "", }).Update() return err } _, err = distdao.Where("id = ?", entId).Data(map[string]interface{}{ "appro_status": "30", "appro_data": "", }).Update() return err } func ApprovalDistToProxy(ctx context.Context, flow *workflowmodel.PlatWorkflow, msg *message.MixMessage) error { tenant, err := micro_srv.GetTenant(ctx) if err != nil { return fmt.Errorf("获取租户码异常:%s", err.Error()) } distdao := base.NewBaseDistributorDao(tenant) entId, err := strconv.Atoi(flow.BizCode) if err != nil { return fmt.Errorf("经销商转代理商钉钉审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id) } ent, err := distdao.Where("id = ?", entId).One() if err != nil { return err } if ent == 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) } if msg.ProcessType == "terminate" { _, err = distdao.Where("id = ?", entId).Data(map[string]interface{}{ "appro_status": "50", "appro_data": "", }).Update() return err } pass := msg.Result == "agree" if !pass { _, err = distdao.Where("id = ?", entId).Data(map[string]interface{}{ "appro_status": "40", "appro_data": "", }).Update() return err } approData := model.ToProxyApproveData{} err = json.Unmarshal([]byte(ent.ApproData), &approData) if err != nil { return fmt.Errorf("经销商转代理商钉钉审批 ApproData 解析异常:%s Id: %d ApproData:%s", flow.BizCode, flow.Id, ent.ApproData) } txerr := distdao.DB.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Update("base_distributor", map[string]interface{}{ "dist_type": "20", "appro_status": "30", "appro_data": "", "customer_type": approData.CustomerType, "proxy_start_time": approData.ProxyStartTime, "proxy_end_time": approData.ProxyEndTime, "proxy_district": approData.ProxyDistrict, "contract_url": approData.ContractUrl, }, "id = ?", ent.Id) if err != nil { return err } _, err = tx.Insert("base_distributor_record", model.BaseDistributorRecord{ DistId: ent.Id, DistType: "20", BusinessScope: ent.BusinessScope, CustomerType: approData.CustomerType, ProxyDistrict: approData.ProxyDistrict, ProxyStartTime: approData.ProxyStartTime, ProxyEndTime: approData.ProxyEndTime, ContractUrl: approData.ContractUrl, ExistedProduct: ent.ExistedProduct, HistoryCustomer: ent.HistoryCustomer, ToDistReason: "", Remark: "", CreatedBy: approData.OperatedId, CreatedName: approData.OperatedName, CreatedTime: gtime.Now(), UpdatedBy: approData.OperatedId, UpdatedName: approData.OperatedName, UpdatedTime: gtime.Now(), }) if err != nil { return err } err = addDynamicsByCurrentUser(tx, ent.Id, "转为代理商", approData, approData.OperatedId, approData.OperatedName) if err != nil { return err } return nil }) return txerr } func ApprovalDistRenew(ctx context.Context, flow *workflowmodel.PlatWorkflow, msg *message.MixMessage) error { tenant, err := micro_srv.GetTenant(ctx) if err != nil { return fmt.Errorf("获取租户码异常:%s", err.Error()) } distdao := base.NewBaseDistributorDao(tenant) entId, err := strconv.Atoi(flow.BizCode) if err != nil { return fmt.Errorf("代理商续签钉钉审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id) } ent, err := distdao.Where("id = ?", entId).One() if err != nil { return err } if ent == 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) } if msg.ProcessType == "terminate" { _, err = distdao.Where("id = ?", entId).Data(map[string]interface{}{ "appro_status": "50", "appro_data": "", }).Update() return err } pass := msg.Result == "agree" if !pass { _, err = distdao.Where("id = ?", entId).Data(map[string]interface{}{ "appro_status": "40", "appro_data": "", }).Update() return err } approData := model.RenewApproveData{} err = json.Unmarshal([]byte(ent.ApproData), &approData) if err != nil { return fmt.Errorf("代理商续签钉钉审批 ApproData 解析异常:%s Id: %d ApproData:%s", flow.BizCode, flow.Id, ent.ApproData) } txerr := distdao.DB.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Update("base_distributor", map[string]interface{}{ "appro_status": "30", "appro_data": "", "customer_type": approData.CustomerType, "proxy_start_time": approData.ProxyStartTime, "proxy_end_time": approData.ProxyEndTime, "proxy_district": approData.ProxyDistrict, "contract_url": approData.ContractUrl, }, "id = ?", ent.Id) if err != nil { return err } _, err = tx.Insert("base_distributor_record", model.BaseDistributorRecord{ DistId: ent.Id, DistType: "20", BusinessScope: ent.BusinessScope, CustomerType: approData.CustomerType, ProxyDistrict: approData.ProxyDistrict, ProxyStartTime: approData.ProxyStartTime, ProxyEndTime: approData.ProxyEndTime, ContractUrl: approData.ContractUrl, ExistedProduct: ent.ExistedProduct, HistoryCustomer: ent.HistoryCustomer, ToDistReason: "", Remark: "", CreatedBy: approData.OperatedId, CreatedName: approData.OperatedName, CreatedTime: gtime.Now(), UpdatedBy: approData.OperatedId, UpdatedName: approData.OperatedName, UpdatedTime: gtime.Now(), }) if err != nil { return err } err = addDynamicsByCurrentUser(tx, ent.Id, "续签代理商", approData, approData.OperatedId, approData.OperatedName) if err != nil { return err } return nil }) return txerr } func ApprovalDistToDist(ctx context.Context, flow *workflowmodel.PlatWorkflow, msg *message.MixMessage) error { tenant, err := micro_srv.GetTenant(ctx) if err != nil { return fmt.Errorf("获取租户码异常:%s", err.Error()) } distdao := base.NewBaseDistributorDao(tenant) entId, err := strconv.Atoi(flow.BizCode) if err != nil { return fmt.Errorf("代理商转经销商钉钉审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id) } ent, err := distdao.Where("id = ?", entId).One() if err != nil { return err } if ent == 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) } if msg.ProcessType == "terminate" { _, err = distdao.Where("id = ?", entId).Data(map[string]interface{}{ "appro_status": "50", "appro_data": "", }).Update() return err } pass := msg.Result == "agree" if !pass { _, err = distdao.Where("id = ?", entId).Data(map[string]interface{}{ "appro_status": "40", "appro_data": "", }).Update() return err } approData := model.ToDistApproveData{} err = json.Unmarshal([]byte(ent.ApproData), &approData) if err != nil { return fmt.Errorf("代理商转经销商钉钉审批 ApproData 解析异常:%s Id: %d ApproData:%s", flow.BizCode, flow.Id, ent.ApproData) } txerr := distdao.DB.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Update("base_distributor", map[string]interface{}{ "dist_type": "10", "appro_status": "30", "appro_data": "", }, "id = ?", ent.Id) if err != nil { return err } _, err = tx.Insert("base_distributor_record", model.BaseDistributorRecord{ DistId: ent.Id, DistType: "10", BusinessScope: ent.BusinessScope, CustomerType: ent.CustomerType, ProxyDistrict: "", ProxyStartTime: nil, ProxyEndTime: nil, ContractUrl: "", ExistedProduct: ent.ExistedProduct, HistoryCustomer: ent.HistoryCustomer, ToDistReason: approData.ToDistReason, Remark: "", CreatedBy: approData.OperatedId, CreatedName: approData.OperatedName, CreatedTime: gtime.Now(), UpdatedBy: approData.OperatedId, UpdatedName: approData.OperatedName, UpdatedTime: gtime.Now(), }) if err != nil { return err } err = addDynamicsByCurrentUser(tx, ent.Id, "转为经销商", approData, approData.OperatedId, approData.OperatedName) if err != nil { return err } return nil }) return txerr } func addDynamicsByCurrentUser(tx *gdb.TX, distId int, opnType string, content interface{}, operatedId int, opreatedName string) error { contentByte, err := json.Marshal(content) if err != nil { return err } _, err = tx.InsertAndGetId("base_distributor_dynamics", model.BaseDistributorDynamics{ DistId: distId, OpnPeopleId: operatedId, OpnPeople: opreatedName, OpnDate: gtime.Now(), OpnType: opnType, OpnContent: string(contentByte), Remark: "", CreatedBy: operatedId, CreatedName: opreatedName, CreatedTime: gtime.Now(), UpdatedBy: operatedId, UpdatedName: opreatedName, UpdatedTime: gtime.Now(), }) return err } func UploadDingtalk(uid, url, name string) ([]byte, error) { if uid == "" { return nil, fmt.Errorf("该用户钉钉 uid 为空") } filedata, err := DownFile(url) if err != nil { return nil, err } filepath := path.Join(os.TempDir(), name) err = ioutil.WriteFile(filepath, filedata, 0644) if err != nil { return nil, fmt.Errorf("WriteFile %s %s", filepath, err) } defer os.Remove(filepath) resp, err := dingtalk.Client.GetStorage().UploadFile(service.DingTalkSpaceId, uid, name, filepath) if err != nil { return nil, fmt.Errorf("钉钉上传文件异常 %s", err.Error()) } file := []contractmodel.DingFileInfo{ { SpaceId: resp.Dentry.SpaceId, FileId: resp.Dentry.Id, FileName: resp.Dentry.Name, FileSize: resp.Dentry.Size, FileType: resp.Dentry.Extension, }, } return json.Marshal(file) } func init() { c := gcron.New() // 每天凌晨2点执行 c.Add("0 0 2 * * *", notifyToComplete) } func notifyToComplete() { defer func() { if r := recover(); r != nil { glog.Errorf("完善经销商定时提醒异常 %v", r) } }() tenant := g.Config().GetString("micro_srv.tenant") if tenant == "" { glog.Error("定时任务租户码未设置,请前往配置") return } dao := base.NewBaseDistributorDao(tenant) created := gtime.Now().Add(-time.Hour * 24 * 30) dist, err := dao.Where("province_id = 0 or belong_sale_id = 0 or capital = 0 or register_district = '' or business_scope = '' or sale_num = 0 or customer_type = '' or existed_product = '' or history_customer = ''").Where("created_time < ?", created).Where("dist_type = 10").All() if err != nil { glog.Errorf("完善经销商定时提醒异常 %s", err.Error()) return } if len(dist) == 0 { return } extraUserId, err := service.UserIdByRoles(dao.DB, "SalesDirector", "SaleAssociate") if err != nil { glog.Errorf("查询销售助理销售总监异常 %s", err.Error()) return } glog.Infof("销售助理销售总监 %v", extraUserId) for _, d := range dist { recvUserIds := service.SliceIntDeduplication(extraUserId) recvUserIds = append(recvUserIds, d.BelongSaleId) recvUserIdString := []string{} for _, uid := range recvUserIds { recvUserIdString = append(recvUserIdString, strconv.Itoa(uid)) } msg := g.MapStrStr{ "msgTitle": "经销商信息完善提醒", "msgContent": fmt.Sprintf("经销商:%s 的必要信息未填写完整,请及时完善
", distUrl(*d), d.DistName), "msgType": "20", "recvUserIds": strings.Join(recvUserIdString, ","), "msgStatus": "10", "sendType": "10", } if err := service.CreateSystemMessage(msg); err != nil { g.Log().Error("经销商信息完善提醒异常:%s", err) } } }