business.go 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474
  1. package proj
  2. import (
  3. "context"
  4. contractDao "dashoo.cn/micro/app/dao/contract"
  5. custDao "dashoo.cn/micro/app/dao/cust"
  6. projDao "dashoo.cn/micro/app/dao/proj"
  7. contractModel "dashoo.cn/micro/app/model/contract"
  8. model "dashoo.cn/micro/app/model/proj"
  9. workflowModel "dashoo.cn/micro/app/model/workflow"
  10. workflowService "dashoo.cn/micro/app/service/workflow"
  11. "dashoo.cn/opms_libary/plugin/dingtalk"
  12. "dashoo.cn/micro/app/service"
  13. "dashoo.cn/opms_libary/multipart"
  14. "dashoo.cn/opms_libary/myerrors"
  15. "dashoo.cn/opms_libary/plugin/dingtalk/message"
  16. "dashoo.cn/opms_libary/plugin/dingtalk/workflow"
  17. "dashoo.cn/opms_libary/utils"
  18. "fmt"
  19. "github.com/gogf/gf/database/gdb"
  20. "github.com/gogf/gf/frame/g"
  21. "github.com/gogf/gf/os/gtime"
  22. "github.com/gogf/gf/util/gconv"
  23. "github.com/shopspring/decimal"
  24. "strconv"
  25. "strings"
  26. )
  27. type businessService struct {
  28. *service.ContextService
  29. Dao *projDao.ProjBusinessDao
  30. }
  31. func NewBusinessService(ctx context.Context) (svc *businessService, err error) {
  32. svc = new(businessService)
  33. if svc.ContextService, err = svc.Init(ctx); err != nil {
  34. return nil, err
  35. }
  36. svc.Dao = projDao.NewProjBusinessDao(svc.Tenant)
  37. return svc, nil
  38. }
  39. func (p *businessService) GetList(req *model.ProjBusinessSearchReq) (total int, businessList []*model.ProjBusinessRes, err error) {
  40. db := p.Dao.As("proj").DataScope(p.Ctx, "sale_id")
  41. if req.NboName != "" {
  42. db = db.WhereLike("proj."+p.Dao.C.NboName, "%"+req.NboName+"%")
  43. }
  44. if req.CustName != "" {
  45. db = db.WhereLike("proj."+p.Dao.C.CustName, "%"+req.CustName+"%")
  46. }
  47. if req.SaleName != "" {
  48. db = db.WhereLike("proj."+p.Dao.C.SaleName, "%"+req.SaleName+"%")
  49. }
  50. if req.NboType != "" {
  51. db = db.Where("proj."+p.Dao.C.NboType, req.NboType)
  52. }
  53. if req.ProductLine != "" {
  54. db = db.Where("proj."+p.Dao.C.ProductLine, req.ProductLine)
  55. }
  56. if req.NboSource != "" {
  57. db = db.Where("proj."+p.Dao.C.NboSource, req.NboSource)
  58. }
  59. if req.DistributorName != "" {
  60. db = db.Where("proj."+p.Dao.C.DistributorName, "%"+req.DistributorName+"%")
  61. }
  62. if req.BeginTime != "" {
  63. db = db.WhereGTE("proj."+p.Dao.C.FilingTime, req.BeginTime)
  64. }
  65. if req.EndTime != "" {
  66. db = db.WhereLTE("proj."+p.Dao.C.FilingTime, req.EndTime)
  67. }
  68. total, err = db.Count()
  69. if err != nil {
  70. err = myerrors.DbError("获取总行数失败。")
  71. return
  72. }
  73. if req.NboType == StatusDeal {
  74. db = db.Unscoped().WhereNull(`proj.deleted_time`).
  75. LeftJoin(contractDao.CtrContract.Table, "contract", "`proj`.id=`contract`.nbo_id AND `contract`.`deleted_time` IS NULL ").
  76. Fields("`proj`.cust_city_id as cust_city_id,`contract`.contract_amount, `contract`.created_time as proj_closing_time")
  77. }
  78. db = db.Fields("`proj`.*")
  79. err = db.Page(req.GetPage()).OrderDesc("id").Scan(&businessList)
  80. return
  81. }
  82. func (p *businessService) GetEntityById(id int64) (business *model.ProjBusiness, err error) {
  83. err = p.Dao.Where(projDao.ProjBusiness.C.Id, id).Scan(&business)
  84. return
  85. }
  86. func (p *businessService) GetBusinessProduct(id int64) (productList []*model.ProjBusinessProduct, err error) {
  87. productDao := projDao.NewProjBusinessProductDao(p.Tenant)
  88. err = productDao.Where(productDao.ProjBusinessProductDao.C.BusId, id).Scan(&productList)
  89. return
  90. }
  91. func (p *businessService) GetBusinessDynamics(req *model.BusinessReq) (total int, result g.MapStrAny, err error) {
  92. result = make(g.MapStrAny, 0)
  93. dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).ProjBusinessDynamicsDao.Where(projDao.ProjBusinessDynamics.C.BusId, req.BusId)
  94. total, err = dynamicsDao.Count()
  95. if err != nil {
  96. g.Log().Error(err)
  97. return
  98. }
  99. dynamicsList, err := dynamicsDao.Page(req.GetPage()).Order("created_time desc").All()
  100. if err != nil || dynamicsList == nil {
  101. return
  102. }
  103. // 数据树格式转换
  104. opnDateFlag := gtime.New(dynamicsList[0].OpnDate).Format("Y-m-d")
  105. for k, v := range dynamicsList {
  106. opnDate := gtime.New(v.OpnDate).Format("Y-m-d")
  107. if opnDateFlag == opnDate && k != 0 {
  108. result[opnDate] = append(result[opnDate].(g.ListStrAny), g.Map{
  109. "opnPeople": v.OpnPeople,
  110. "opnDate": v.OpnDate,
  111. "opnType": v.OpnType,
  112. "remark": v.Remark,
  113. "opnContent": gconv.Map(v.OpnContent),
  114. })
  115. } else {
  116. temp := make(g.ListStrAny, 0)
  117. temp = append(temp, g.Map{
  118. "opnPeople": v.OpnPeople,
  119. "opnDate": v.OpnDate,
  120. "opnType": v.OpnType,
  121. "remark": v.Remark,
  122. "opnContent": gconv.Map(v.OpnContent),
  123. })
  124. result[opnDate] = temp
  125. opnDateFlag = opnDate
  126. }
  127. }
  128. return
  129. }
  130. func (p *businessService) GetBusinessDynamicsList(req *model.BusinessDynamicsReq) (total int, list []map[string]interface{}, err error) {
  131. dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).Where(projDao.ProjBusinessDynamics.C.BusId, req.BusId)
  132. if req.OpnType != "" {
  133. dynamicsDao = dynamicsDao.Where(projDao.ProjBusinessDynamics.C.OpnType+" = ?", req.OpnType)
  134. }
  135. total, err = dynamicsDao.Count()
  136. if err != nil {
  137. g.Log().Error(err)
  138. return
  139. }
  140. dynamicsList, err := dynamicsDao.Page(req.GetPage()).Order("created_time desc").All()
  141. for _, v := range dynamicsList {
  142. val := gconv.Map(v)
  143. val["opnContent"] = gconv.Map(v.OpnContent)
  144. list = append(list, val)
  145. }
  146. return
  147. }
  148. // 获取项目编号
  149. func (p *businessService) getNboCode(customerCode string) (string, error) {
  150. sequence, err := service.Sequence(p.Dao.DB, "nbo_code")
  151. if err != nil {
  152. return "", err
  153. }
  154. return customerCode + sequence, nil
  155. }
  156. func (p *businessService) Create(req *model.AddProjBusinessReq) (err error) {
  157. // 获取客户信息
  158. customer, err := custDao.NewCustCustomerDao(p.Tenant).WherePri(req.CustId).One()
  159. if err != nil {
  160. return err
  161. }
  162. if customer == nil {
  163. return myerrors.TipsError("客户不存在")
  164. }
  165. // 设置默认联系人
  166. contact := g.Map{
  167. projDao.ProjBusinessContact.C.ContactId: req.ContactId,
  168. }
  169. service.SetCreatedInfo(contact, p.GetCxtUserId(), p.GetCxtUserName())
  170. // 设置产品信息
  171. totalPrice, products, err := p.setProductInfo(0, req.Products)
  172. if err != nil {
  173. return err
  174. }
  175. // 获取项目编号
  176. nboCode, err := p.getNboCode(customer.CustCode)
  177. if err != nil {
  178. return err
  179. }
  180. // 初始化项目信息
  181. business := new(model.ProjBusiness)
  182. if err = gconv.Struct(req, business); err != nil {
  183. return
  184. }
  185. business.NboCode = nboCode
  186. //business.NboStatus = StatusOK
  187. business.NboType = StatusC
  188. business.ApproStatus = ApprovalWaiting
  189. business.EstTransPrice = totalPrice
  190. business.CustProvinceId = customer.CustProvinceId
  191. business.CustProvince = customer.CustProvince
  192. business.CustCityId = customer.CustCityId
  193. business.CustCity = customer.CustCity
  194. business.CustRegionId = customer.CustRegionId
  195. business.CustRegion = customer.CustRegion
  196. business.DeptId = p.GetCxtUserDeptId()
  197. service.SetCreatedInfo(business, p.GetCxtUserId(), p.GetCxtUserName())
  198. business.FilingTime = business.CreatedTime
  199. productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
  200. nboSource, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "proj_nbo_source", business.NboSource)
  201. salesModel, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "proj_sales_model", business.SalesModel)
  202. // 事务
  203. err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
  204. // 添加项目
  205. lastId, err := p.Dao.TX(tx).InsertAndGetId(business)
  206. if err != nil {
  207. return err
  208. }
  209. // 创建了联系人
  210. contact[projDao.ProjBusinessContact.C.BusId] = lastId
  211. _, err = projDao.NewProjBusinessContactDao(p.Tenant).TX(tx).Insert(contact)
  212. if err != nil {
  213. return err
  214. }
  215. // 处理项目产品信息
  216. for _, v := range products {
  217. v.BusId = int(lastId)
  218. }
  219. // 添加项目产品
  220. _, err = projDao.NewProjBusinessProductDao(p.Tenant).TX(tx).Insert(products)
  221. if err != nil {
  222. return err
  223. }
  224. // 添加项目动态
  225. dynamics := model.ProjBusinessDynamics{
  226. BusId: int(lastId),
  227. OpnType: OpnCreate,
  228. Remark: business.Remark,
  229. }
  230. _, err = p.CreateProjBusinessDynamics(tx, dynamics, business)
  231. // 审批流
  232. workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
  233. // OMS项目转移 审批
  234. bizCode := business.NboCode + ":" + gconv.String(lastId)
  235. _, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectCreate, "", &workflow.StartProcessInstanceRequest{
  236. ProcessCode: &BusinessCreateRequestProcessCode,
  237. FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
  238. {
  239. Id: utils.String("TextField-K2AD4O5B"),
  240. Name: utils.String("项目编码"),
  241. Value: utils.String(business.NboCode),
  242. },
  243. {
  244. Id: utils.String("TextField_BDLSECETVSG0"),
  245. Name: utils.String("项目名称"),
  246. Value: utils.String(business.NboName),
  247. },
  248. {
  249. Id: utils.String("DDSelectField_213JKZA1OUO00"),
  250. Name: utils.String("产品线"),
  251. Value: utils.String(productLine),
  252. },
  253. {
  254. Id: utils.String("TextField_1J9BJMOZ18F40"),
  255. Name: utils.String("客户名称"),
  256. Value: utils.String(business.CustName),
  257. },
  258. {
  259. Id: utils.String("TextField_VZ64Y44LXFK0"),
  260. Name: utils.String("主要联系人"),
  261. Value: utils.String(business.ContactName),
  262. },
  263. {
  264. Id: utils.String("DDSelectField_6CQD451D3800"),
  265. Name: utils.String("项目来源"),
  266. Value: utils.String(nboSource),
  267. },
  268. {
  269. Id: utils.String("TextField_AEUWH63LJ0O0"),
  270. Name: utils.String("销售工程师"),
  271. Value: utils.String(business.SaleName),
  272. },
  273. {
  274. Id: utils.String("DDSelectField_34QSUGHO2SO0"),
  275. Name: utils.String("销售模式"),
  276. Value: utils.String(salesModel),
  277. },
  278. {
  279. Id: utils.String("TextField_1PWK6WHMGITC0"),
  280. Name: utils.String("经销商/代理商"),
  281. Value: utils.String(business.DistributorName),
  282. },
  283. {
  284. Id: utils.String("DDSelectField_5R11VVM6GI00"),
  285. Name: utils.String("是否为大项目"),
  286. Value: utils.String(yesOrNoType[business.IsBig]),
  287. },
  288. {
  289. Id: utils.String("TextareaField_1GEL8JJL3H5S0"),
  290. Name: utils.String("备注"),
  291. Value: utils.String(business.Remark),
  292. },
  293. },
  294. })
  295. if err != nil {
  296. g.Log().Error(err)
  297. return err
  298. }
  299. return err
  300. })
  301. return
  302. }
  303. // BusinessCreatedNotify 项目创建 审批结果通知
  304. func (p *businessService) BusinessCreatedNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
  305. business, err := p.checkDingTalkNotify(flow, msg)
  306. if err != nil {
  307. return err
  308. }
  309. var data = g.Map{}
  310. if msg.ProcessType == "terminate" {
  311. data[p.Dao.C.ApproStatus] = ApprovalReturn
  312. }
  313. if msg.ProcessType == "finish" && msg.Result == "refuse" {
  314. data[p.Dao.C.ApproStatus] = ApprovalRejection
  315. }
  316. if msg.ProcessType == "finish" && msg.Result == "agree" {
  317. data[p.Dao.C.ApproStatus] = ApprovalOK
  318. }
  319. // 项目修改
  320. _, err = p.Dao.WherePri(business.Id).FieldsEx(service.UpdateFieldEx...).Data(data).Update()
  321. if err != nil {
  322. return err
  323. }
  324. // 添加项目动态
  325. dynamics := model.ProjBusinessDynamics{
  326. BusId: business.Id,
  327. OpnType: OpnCreatedApproval,
  328. }
  329. _, err = p.CreateProjBusinessDynamics(nil, dynamics, data)
  330. if err != nil {
  331. return err
  332. }
  333. return err
  334. }
  335. // setProductInfo 设置产品信息
  336. func (p *businessService) setProductInfo(busId int, productInfo []model.BusinessProduct) (total float64, products []*model.ProjBusinessProduct, err error) {
  337. products = make([]*model.ProjBusinessProduct, len(productInfo))
  338. if err = gconv.Structs(productInfo, &products); err != nil {
  339. return 0, nil, err
  340. }
  341. var totalPrice decimal.Decimal
  342. for _, v := range products {
  343. v.Id = 0
  344. v.BusId = busId
  345. v.TotalPrice = decimal.NewFromFloat(v.ProdPrice).Mul(decimal.NewFromInt(int64(v.ProdNum))).InexactFloat64()
  346. totalPrice = totalPrice.Add(decimal.NewFromFloat(v.TotalPrice))
  347. service.SetCreatedInfo(v, p.GetCxtUserId(), p.GetCxtUserName())
  348. }
  349. return totalPrice.InexactFloat64(), products, nil
  350. }
  351. func (p *businessService) UpdateById(req *model.UpdateProjBusinessReq) error {
  352. record, err := p.Dao.WherePri(req.Id).Count()
  353. if err != nil {
  354. return err
  355. }
  356. if record == 0 {
  357. return myerrors.TipsError("项目不存在。")
  358. }
  359. // 设置产品信息
  360. totalPrice, products, err := p.setProductInfo(req.Id, req.Products)
  361. if err != nil {
  362. return err
  363. }
  364. // 设置默认联系人
  365. contact := g.Map{
  366. projDao.ProjBusinessContact.C.BusId: req.Id,
  367. projDao.ProjBusinessContact.C.ContactId: req.ContactId,
  368. }
  369. contactFlag, err := projDao.NewProjBusinessContactDao(p.Tenant).Where(contact).Count()
  370. if err != nil {
  371. return err
  372. }
  373. if contactFlag == 0 {
  374. service.SetCreatedInfo(contact, p.GetCxtUserId(), p.GetCxtUserName())
  375. }
  376. // 设置项目信息
  377. req.EstTransPrice = totalPrice
  378. businessData := gconv.Map(req)
  379. service.SetUpdatedInfo(businessData, p.GetCxtUserId(), p.GetCxtUserName())
  380. err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
  381. // 更新项目
  382. updateFieldEx := append(service.UpdateFieldEx, p.Dao.C.SaleId, p.Dao.C.SaleName)
  383. _, err = p.Dao.TX(tx).FieldsEx(updateFieldEx...).WherePri(projDao.ProjBusiness.C.Id, req.Id).Update(businessData)
  384. if err != nil {
  385. return err
  386. }
  387. // 删除项目产品
  388. _, err = projDao.NewProjBusinessProductDao(p.Tenant).TX(tx).Where(projDao.ProjBusinessProduct.C.BusId, req.Id).Delete()
  389. if err != nil {
  390. return err
  391. }
  392. // 添加项目产品
  393. _, err = projDao.NewProjBusinessProductDao(p.Tenant).TX(tx).Insert(products)
  394. if err != nil {
  395. return err
  396. }
  397. // 关联联系人
  398. if contactFlag == 0 {
  399. _, err = projDao.NewProjBusinessContactDao(p.Tenant).TX(tx).Insert(contact)
  400. if err != nil {
  401. return err
  402. }
  403. }
  404. // 添加项目动态
  405. dynamics := model.ProjBusinessDynamics{
  406. BusId: req.Id,
  407. OpnType: OpnUpdate,
  408. Remark: req.Remark,
  409. }
  410. _, err = p.CreateProjBusinessDynamics(tx, dynamics, req)
  411. return err
  412. })
  413. return err
  414. }
  415. func (p *businessService) DeleteByIds(ids []int64) (err error) {
  416. _, err = p.Dao.WhereIn(projDao.ProjBusiness.C.Id, ids).Delete()
  417. return
  418. }
  419. // BusinessTransfer 项目转移
  420. func (p *businessService) BusinessTransfer(req *model.BusinessTransferReq) error {
  421. business, err := p.Dao.WherePri(req.Id).WhereNot(p.Dao.C.ApproStatus, ApprovalWaiting).One()
  422. if err != nil {
  423. return err
  424. }
  425. if business == nil {
  426. return myerrors.TipsError("项目已提交审批任务,无法重复提交。")
  427. }
  428. businessMap := g.Map{
  429. p.Dao.C.ApproStatus: ApprovalWaiting,
  430. }
  431. service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
  432. opnContent := gconv.Map(gconv.String(businessMap))
  433. opnContent["origSaleId"] = business.SaleId
  434. opnContent["origSaleName"] = business.SaleName
  435. opnContent["saleId"] = req.UserId
  436. opnContent["saleName"] = req.UserName
  437. opnContent["remark"] = req.Remark
  438. productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
  439. // 审批流
  440. workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
  441. err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
  442. // 更新项目
  443. _, err = p.Dao.TX(tx).WherePri(projDao.ProjBusiness.C.Id, req.Id).Data(businessMap).Update()
  444. if err != nil {
  445. return err
  446. }
  447. // 添加项目动态
  448. dynamics := model.ProjBusinessDynamics{
  449. BusId: req.Id,
  450. OpnType: OpnTransfer,
  451. Remark: req.Remark,
  452. }
  453. _, err = p.CreateProjBusinessDynamics(tx, dynamics, opnContent)
  454. if err != nil {
  455. g.Log().Error(err)
  456. return err
  457. }
  458. // OMS项目转移 审批
  459. bizCode := business.NboCode + ":" + strconv.Itoa(business.Id)
  460. _, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectTransfer, "", &workflow.StartProcessInstanceRequest{
  461. ProcessCode: &BusinessTransferRequestProcessCode,
  462. FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
  463. {
  464. Id: utils.String("TextField-K2AD4O5B"),
  465. Name: utils.String("项目编码"),
  466. Value: utils.String(business.NboCode),
  467. },
  468. {
  469. Id: utils.String("TextField_7EFHRQ9DDF80"),
  470. Name: utils.String("项目名称"),
  471. Value: utils.String(business.NboName),
  472. },
  473. {
  474. Id: utils.String("TextField_1T3DEY5FWV7K0"),
  475. Name: utils.String("客户名称"),
  476. Value: utils.String(business.CustName),
  477. },
  478. {
  479. Id: utils.String("TextField_QDU06LXYKK00"),
  480. Name: utils.String("所在省"),
  481. Value: utils.String(business.CustProvince),
  482. },
  483. {
  484. Id: utils.String("TextField_MVSOO6EG6YO0"),
  485. Name: utils.String("所在市"),
  486. Value: utils.String(business.CustCity),
  487. },
  488. {
  489. Id: utils.String("DDSelectField_6OMVO1JV0980"),
  490. Name: utils.String("产品线"),
  491. Value: utils.String(productLine),
  492. },
  493. {
  494. Id: utils.String("TextField_1E1WOYGKRTDS0"),
  495. Name: utils.String("项目级别"),
  496. Value: utils.String(nboType[business.NboType]),
  497. },
  498. {
  499. Id: utils.String("TextField_NRQXWLJ17HC0"),
  500. Name: utils.String("申请人"),
  501. Value: utils.String(p.GetCxtUserName()),
  502. },
  503. {
  504. Id: utils.String("TextField_GHSQYDGD13K0"),
  505. Name: utils.String("转移原因"),
  506. Value: utils.String(req.Remark),
  507. },
  508. {
  509. Id: utils.String("TextField_76P8FPHH0UC0"),
  510. Name: utils.String("接收人"),
  511. Value: utils.String(req.UserName),
  512. },
  513. },
  514. })
  515. if err != nil {
  516. g.Log().Error(err)
  517. return err
  518. }
  519. return nil
  520. })
  521. return err
  522. }
  523. // BusinessTransferNotify 项目转移 审批结果通知
  524. func (p *businessService) BusinessTransferNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
  525. business, err := p.checkDingTalkNotify(flow, msg)
  526. if err != nil {
  527. return err
  528. }
  529. var data = g.Map{}
  530. if msg.ProcessType == "terminate" {
  531. data[p.Dao.C.ApproStatus] = ApprovalReturn
  532. }
  533. if msg.ProcessType == "finish" && msg.Result == "refuse" {
  534. data[p.Dao.C.ApproStatus] = ApprovalRejection
  535. }
  536. if msg.ProcessType == "finish" && msg.Result == "agree" {
  537. // 从项目动态内获取变更信息
  538. var transferDynamics model.ProjBusinessDynamics
  539. dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).Where(projDao.ProjBusinessDynamics.C.BusId, business.Id)
  540. err = dynamicsDao.Where(projDao.ProjBusinessDynamics.C.OpnType, OpnTransfer).OrderDesc("created_time").Scan(&transferDynamics)
  541. if err != nil {
  542. return err
  543. }
  544. changeData := gconv.Map(transferDynamics.OpnContent)
  545. data[p.Dao.C.SaleId] = changeData["saleId"]
  546. data[p.Dao.C.SaleName] = changeData["saleName"]
  547. data[p.Dao.C.Remark] = changeData["remark"]
  548. data[p.Dao.C.ApproStatus] = ApprovalOK
  549. }
  550. // 项目修改
  551. _, err = p.Dao.WherePri(business.Id).FieldsEx(service.UpdateFieldEx...).Data(data).Update()
  552. if err != nil {
  553. return err
  554. }
  555. // 添加项目动态
  556. dynamics := model.ProjBusinessDynamics{
  557. BusId: business.Id,
  558. OpnType: OpnTransferApproval,
  559. }
  560. _, err = p.CreateProjBusinessDynamics(nil, dynamics, data)
  561. if err != nil {
  562. return err
  563. }
  564. return err
  565. }
  566. // BusinessGradation 项目调级
  567. func (p *businessService) BusinessGradation(busId int, nboType, busType string) (*model.ProjBusiness, error) {
  568. business, err := p.Dao.WherePri(busId).WhereNot(p.Dao.C.ApproStatus, ApprovalWaiting).One()
  569. if err != nil {
  570. return nil, err
  571. }
  572. if business == nil {
  573. return nil, myerrors.TipsError("项目已提交审批任务,无法重复提交。")
  574. }
  575. if business.NboType == nboType {
  576. return nil, myerrors.TipsError("同级别无法进行调级。")
  577. }
  578. if business.NboType == StatusDeal {
  579. return nil, myerrors.TipsError("成交项目无法进行调级。")
  580. }
  581. if business.NboType == StatusReserve && nboType == StatusDeal {
  582. return nil, myerrors.TipsError("储备项目无法直接转为成交项目。")
  583. }
  584. if busType == "up" && gconv.Int(business.NboType) < gconv.Int(nboType) {
  585. return nil, myerrors.TipsError("项目级别错误。")
  586. }
  587. if busType == "down" && gconv.Int(business.NboType) > gconv.Int(nboType) {
  588. return nil, myerrors.TipsError("项目级别错误。")
  589. }
  590. return business, err
  591. }
  592. // BusinessUpgrade 项目升级
  593. func (p *businessService) BusinessUpgrade(req *model.BusinessUpgradeReq, fileMap map[string]*multipart.FileHeader) error {
  594. business, err := p.BusinessGradation(req.Id, req.NboType, "up")
  595. if err != nil {
  596. return err
  597. }
  598. businessMap := g.Map{
  599. p.Dao.C.ApproStatus: ApprovalWaiting,
  600. }
  601. service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
  602. opnContent := gconv.Map(req)
  603. opnContent["origNboType"] = business.NboType
  604. opnContent["approStatus"] = ApprovalWaiting
  605. service.SetUpdatedInfo(opnContent, p.GetCxtUserId(), p.GetCxtUserName())
  606. err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
  607. // 更新项目调级
  608. _, err = p.Dao.TX(tx).WherePri(req.Id).Data(businessMap).Update()
  609. if err != nil {
  610. return err
  611. }
  612. // 添加项目动态
  613. dynamics := model.ProjBusinessDynamics{
  614. BusId: business.Id,
  615. OpnType: OpnUpgrade,
  616. Remark: req.Remark,
  617. }
  618. _, err = p.CreateProjBusinessDynamics(tx, dynamics, opnContent)
  619. if err != nil {
  620. return err
  621. }
  622. err = p.BusUpgradeDingEvent(business, req, fileMap)
  623. return err
  624. })
  625. return err
  626. }
  627. // 获取项目的钉钉审批的升级类型
  628. func (p *businessService) getBusDingUpgradeType(dbNboType, reqNboType string) string {
  629. var upgradeType string
  630. switch true {
  631. case dbNboType == StatusReserve && reqNboType == StatusC: // 储备转C/option_0
  632. upgradeType = "储备转C"
  633. case dbNboType == StatusReserve && reqNboType == StatusB: // 储备转B/option_1
  634. upgradeType = "储备转B"
  635. case dbNboType == StatusReserve && reqNboType == StatusA: // 储备转A/option_KTAX3Y9K5340
  636. upgradeType = "储备转A"
  637. case dbNboType == StatusC && reqNboType == StatusB: // C转B/option_0
  638. upgradeType = "C转B"
  639. case dbNboType == StatusC && reqNboType == StatusA: // C转A/option_0
  640. upgradeType = "C转A"
  641. case dbNboType == StatusB && reqNboType == StatusA: // B转A/option_1
  642. upgradeType = "B转A"
  643. default:
  644. }
  645. return upgradeType
  646. }
  647. // BusUpgradeDingEvent 项目升级钉钉审批流调用
  648. func (p *businessService) BusUpgradeDingEvent(business *model.ProjBusiness, req *model.BusinessUpgradeReq, fileMap map[string]*multipart.FileHeader) error {
  649. upgradeType := p.getBusDingUpgradeType(business.NboType, req.NboType)
  650. if upgradeType == "" {
  651. return myerrors.TipsError("错误的升级类型")
  652. }
  653. productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
  654. // 审批流
  655. workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
  656. // OMS项目升级 审批
  657. var err error
  658. var dingReq *workflow.StartProcessInstanceRequest
  659. bizCode := business.NboCode + ":" + strconv.Itoa(business.Id)
  660. switch req.NboType {
  661. case StatusC:
  662. dingReq = &workflow.StartProcessInstanceRequest{
  663. ProcessCode: &BusinessUpgradeCRequestProcessCode,
  664. FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
  665. {
  666. Id: utils.String("TextField-K2AD4O5B"),
  667. Name: utils.String("项目编码"),
  668. Value: utils.String(business.NboCode),
  669. },
  670. {
  671. Id: utils.String("TextField_BDLSECETVSG0"),
  672. Name: utils.String("项目名称"),
  673. Value: utils.String(business.NboName),
  674. },
  675. {
  676. Id: utils.String("DDSelectField_1MJU37HGJX4W0"),
  677. Name: utils.String("产品线"),
  678. Value: utils.String(productLine),
  679. },
  680. {
  681. Id: utils.String("DDSelectField_VSA3U380ZK00"),
  682. Name: utils.String("升级类型"),
  683. Value: utils.String(upgradeType),
  684. },
  685. {
  686. Id: utils.String("TextField_1J9BJMOZ18F40"),
  687. Name: utils.String("客户名称"),
  688. Value: utils.String(business.CustName),
  689. },
  690. {
  691. Id: utils.String("TextField_AEUWH63LJ0O0"),
  692. Name: utils.String("销售工程师"),
  693. Value: utils.String(business.SaleName),
  694. },
  695. {
  696. Id: utils.String("TextareaField_1LO81IKHH91C0"),
  697. Name: utils.String("转化原因"),
  698. Value: utils.String(req.ProjConversionReason),
  699. },
  700. },
  701. }
  702. case StatusB:
  703. quotationFile := make([]contractModel.DingFileInfo, 0)
  704. if len(fileMap) > 0 {
  705. for k, files := range fileMap {
  706. // 报价单
  707. if k == "quotationFile" {
  708. if quotationFile, err = p.txCreateBusinessDingTalkFile(business.Id, upgradeType, k, files); err != nil {
  709. return err
  710. }
  711. }
  712. }
  713. }
  714. if len(quotationFile) == 0 {
  715. return myerrors.TipsError("请上传报价单文件")
  716. }
  717. processCode := &BusinessUpgradeBRequestProcessCode
  718. dingReq = &workflow.StartProcessInstanceRequest{
  719. ProcessCode: processCode,
  720. FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
  721. {
  722. Id: utils.String("TextField-K2AD4O5B"),
  723. Name: utils.String("项目编码"),
  724. Value: utils.String(business.NboCode),
  725. },
  726. {
  727. Id: utils.String("TextField_BDLSECETVSG0"),
  728. Name: utils.String("项目名称"),
  729. Value: utils.String(business.NboName),
  730. },
  731. {
  732. Id: utils.String("DDSelectField_213JKZA1OUO00"),
  733. Name: utils.String("产品线"),
  734. Value: utils.String(productLine),
  735. },
  736. {
  737. Id: utils.String("DDSelectField_VSA3U380ZK00"),
  738. Name: utils.String("升级类型"),
  739. Value: utils.String(upgradeType),
  740. },
  741. {
  742. Id: utils.String("TextField_1J9BJMOZ18F40"),
  743. Name: utils.String("客户名称"),
  744. Value: utils.String(business.CustName),
  745. },
  746. {
  747. Id: utils.String("NumberField_1F88MCD0W8KG0"),
  748. Name: utils.String("项目预算"),
  749. Value: utils.String(gconv.String(req.NboBudget)),
  750. },
  751. {
  752. Id: utils.String("TextField_1PWK6WHMGITC0"),
  753. Name: utils.String("经销商/代理商"),
  754. Value: utils.String(req.DistributorName),
  755. },
  756. {
  757. Id: utils.String("TextField_X4D3QGARU7K0"),
  758. Name: utils.String("支持内容"),
  759. Value: utils.String(req.TechnicalSupportContent),
  760. },
  761. {
  762. Id: utils.String("TextField_AEUWH63LJ0O0"),
  763. Name: utils.String("销售工程师"),
  764. Value: utils.String(business.SaleName),
  765. },
  766. {
  767. Id: utils.String("DDDateField_1FW1QZQYBZVK0"),
  768. Name: utils.String("采购时间"),
  769. Value: utils.String(gconv.String(req.PurchasingTime.Format("Y-m-d"))),
  770. },
  771. {
  772. Id: utils.String("DDSelectField_21ASEWDIB3MO0"),
  773. Name: utils.String("采购方式"),
  774. Value: utils.String(gconv.String(purchasingWayType[req.PurchasingWay])),
  775. },
  776. {
  777. Id: utils.String("DDSelectField_5R11VVM6GI00"),
  778. Name: utils.String("是否我司参数"),
  779. Value: utils.String(gconv.String(yesOrNoType[req.IsAdoptDashoo])),
  780. },
  781. {
  782. Id: utils.String("DDAttachment_KZPWZJS9GHO0"),
  783. Name: utils.String("上传报价单"),
  784. Value: utils.String(gconv.String(quotationFile)),
  785. },
  786. {
  787. Id: utils.String("TextareaField_1GEL8JJL3H5S0"),
  788. Name: utils.String("备注"),
  789. Value: utils.String(req.Remark),
  790. },
  791. },
  792. }
  793. case StatusA:
  794. var dashooParamFile []contractModel.DingFileInfo
  795. var quotationFile []contractModel.DingFileInfo
  796. if len(fileMap) > 0 {
  797. for k, files := range fileMap {
  798. // 报价单
  799. if k == "quotationFile" {
  800. if quotationFile, err = p.txCreateBusinessDingTalkFile(business.Id, upgradeType, k, files); err != nil {
  801. return err
  802. }
  803. }
  804. // 大数参数文件
  805. if k == "dashooParamFile" {
  806. if dashooParamFile, err = p.txCreateBusinessDingTalkFile(business.Id, upgradeType, k, files); err != nil {
  807. return err
  808. }
  809. }
  810. }
  811. }
  812. if len(quotationFile) == 0 {
  813. return myerrors.TipsError("请上传报价单文件")
  814. }
  815. processCode := &BusinessUpgradeARequestProcessCode
  816. dingReq = &workflow.StartProcessInstanceRequest{
  817. ProcessCode: processCode,
  818. FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
  819. {
  820. Id: utils.String("TextField-K2AD4O5B"),
  821. Name: utils.String("项目编码"),
  822. Value: utils.String(business.NboCode),
  823. },
  824. {
  825. Id: utils.String("TextField_BDLSECETVSG0"),
  826. Name: utils.String("项目名称"),
  827. Value: utils.String(business.NboName),
  828. },
  829. {
  830. Id: utils.String("DDSelectField_L4CSUVLU1NK"),
  831. Name: utils.String("产品线"),
  832. Value: utils.String(productLine),
  833. },
  834. {
  835. Id: utils.String("DDSelectField_VSA3U380ZK00"),
  836. Name: utils.String("升级类型"),
  837. Value: utils.String(upgradeType),
  838. },
  839. {
  840. Id: utils.String("TextField_1J9BJMOZ18F40"),
  841. Name: utils.String("客户名称"),
  842. Value: utils.String(business.CustName),
  843. },
  844. {
  845. Id: utils.String("NumberField_1F88MCD0W8KG0"),
  846. Name: utils.String("项目预算"),
  847. Value: utils.String(gconv.String(req.NboBudget)),
  848. },
  849. {
  850. Id: utils.String("TextField_1PWK6WHMGITC0"),
  851. Name: utils.String("经销商/代理商"),
  852. Value: utils.String(req.DistributorName),
  853. },
  854. {
  855. Id: utils.String("TextField_X4D3QGARU7K0"),
  856. Name: utils.String("支持内容"),
  857. Value: utils.String(req.TechnicalSupportContent),
  858. },
  859. {
  860. Id: utils.String("TextField_AEUWH63LJ0O0"),
  861. Name: utils.String("销售工程师"),
  862. Value: utils.String(business.SaleName),
  863. },
  864. {
  865. Id: utils.String("DDDateField_1FW1QZQYBZVK0"),
  866. Name: utils.String("采购时间"),
  867. Value: utils.String(gconv.String(req.PurchasingTime.Format("Y-m-d"))),
  868. },
  869. {
  870. Id: utils.String("DDSelectField_21ASEWDIB3MO0"),
  871. Name: utils.String("采购方式"),
  872. Value: utils.String(gconv.String(purchasingWayType[req.PurchasingWay])),
  873. },
  874. {
  875. Id: utils.String("DDSelectField_5R11VVM6GI00"),
  876. Name: utils.String("是否我司参数"),
  877. Value: utils.String(gconv.String(yesOrNoType[req.IsAdoptDashoo])),
  878. },
  879. {
  880. Id: utils.String("DDAttachment_11Q7DBRKE6HC0"),
  881. Name: utils.String("附件"),
  882. Value: utils.String(gconv.String(dashooParamFile)),
  883. },
  884. {
  885. Id: utils.String("DDAttachment_19Y01ZRBFWXS0"),
  886. Name: utils.String("上传报价单"),
  887. Value: utils.String(gconv.String(quotationFile)),
  888. },
  889. {
  890. Id: utils.String("TextareaField_1GEL8JJL3H5S0"),
  891. Name: utils.String("备注"),
  892. Value: utils.String(req.Remark),
  893. },
  894. },
  895. }
  896. default:
  897. return nil
  898. }
  899. _, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectUpGrade, "", dingReq)
  900. if err != nil {
  901. g.Log().Error(err)
  902. return err
  903. }
  904. return nil
  905. }
  906. // 项目上传文件至钉钉
  907. func (p *businessService) txCreateBusinessDingTalkFile(businessId int, upgradeType, fileType string, file *multipart.FileHeader) ([]contractModel.DingFileInfo, error) {
  908. dingTalkFiles := make([]contractModel.DingFileInfo, 0)
  909. //for _, file := range files {
  910. resp, err := dingtalk.Client.GetStorage().UploadFile(service.DingTalkSpaceId, p.GetCxtUserDingtalkId(), file.FileName, file.File.Name())
  911. if err != nil {
  912. g.Log().Error(err)
  913. return nil, myerrors.TipsError("钉钉上传文件异常")
  914. }
  915. typ := "项目" + upgradeType
  916. if fileType == "quotationFile" {
  917. typ += "上传报价单文件"
  918. }
  919. if fileType == "dashooParamFile" {
  920. typ += "上传大数技术参数文件"
  921. }
  922. g.Log().Info(typ, resp)
  923. dingTalkFiles = append(dingTalkFiles, contractModel.DingFileInfo{
  924. SpaceId: resp.Dentry.SpaceId,
  925. FileId: resp.Dentry.Id,
  926. FileName: resp.Dentry.Name,
  927. FileSize: resp.Dentry.Size,
  928. FileType: resp.Dentry.Extension,
  929. })
  930. //}
  931. err = p.txCreateBusinessFile(businessId, typ, dingTalkFiles)
  932. if err != nil {
  933. return nil, err
  934. }
  935. return dingTalkFiles, nil
  936. }
  937. // 采用大数参数文件记录
  938. func (p *businessService) txCreateBusinessFile(busId int, fileSource string, files []contractModel.DingFileInfo) error {
  939. dataList := make([]*model.ProjBusinessFile, 0)
  940. for _, v := range files {
  941. data := new(model.ProjBusinessFile)
  942. data.BusId = busId
  943. data.FileName = v.FileName
  944. data.FileSource = fileSource
  945. data.FileSize = gconv.String(v.FileSize)
  946. data.FileUrl = strings.Join([]string{"dingtalk", v.SpaceId, v.FileId}, ":")
  947. service.SetCreatedInfo(data, p.GetCxtUserId(), p.GetCxtUserName())
  948. dataList = append(dataList, data)
  949. }
  950. _, err := projDao.NewProjBusinessFileDao(p.Tenant).Insert(&dataList)
  951. return err
  952. }
  953. // BusinessUpgradeNotify 项目升级 审批结果通知
  954. func (p *businessService) BusinessUpgradeNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
  955. business, err := p.checkDingTalkNotify(flow, msg)
  956. if err != nil {
  957. return err
  958. }
  959. var data = g.Map{}
  960. var remark string
  961. if msg.ProcessType == "terminate" {
  962. data[p.Dao.C.ApproStatus] = ApprovalReturn
  963. }
  964. if msg.ProcessType == "finish" && msg.Result == "refuse" {
  965. data[p.Dao.C.ApproStatus] = ApprovalRejection
  966. }
  967. if msg.ProcessType == "finish" && msg.Result == "agree" {
  968. // 从项目动态内获取变更信息
  969. dynamics := new(model.ProjBusinessDynamics)
  970. dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).Where(projDao.ProjBusinessDynamics.C.BusId, business.Id)
  971. err = dynamicsDao.Where(projDao.ProjBusinessDynamics.C.OpnType, OpnUpgrade).OrderDesc("created_time").Scan(dynamics)
  972. if err != nil {
  973. return err
  974. }
  975. updateData := new(model.BusinessUpgradeReq)
  976. gconv.Struct(dynamics.OpnContent, updateData)
  977. data = gconv.Map(updateData)
  978. data[p.Dao.C.ApproStatus] = ApprovalOK
  979. remarkMap := gconv.Map(dynamics.OpnContent)
  980. remark = gconv.String(g.Map{"nboType": remarkMap["nboType"], "origNboType": remarkMap["origNboType"]})
  981. }
  982. // 项目修改
  983. _, err = p.Dao.WherePri(business.Id).FieldsEx(service.UpdateFieldEx...).Data(data).Update()
  984. if err != nil {
  985. return err
  986. }
  987. // 添加项目动态
  988. dynamics := model.ProjBusinessDynamics{
  989. BusId: business.Id,
  990. OpnType: OpnUpgradeApproval,
  991. Remark: remark,
  992. }
  993. _, err = p.CreateProjBusinessDynamics(nil, dynamics, data)
  994. if err != nil {
  995. return err
  996. }
  997. return nil
  998. }
  999. // 获取项目的钉钉审批的降级类型
  1000. func (p *businessService) getBusDingDowngradeType(dbNboType, reqNboType string) string {
  1001. var downgradeType string
  1002. switch true {
  1003. case dbNboType == StatusB && reqNboType == StatusC: // B转C/option_0
  1004. downgradeType = "B转C"
  1005. case dbNboType == StatusA && reqNboType == StatusB: // A转B/option_1
  1006. downgradeType = "A转B"
  1007. case dbNboType == StatusA && reqNboType == StatusC: // A转C/option_2
  1008. downgradeType = "A转C"
  1009. case dbNboType == StatusA && reqNboType == StatusReserve: // A转储备/option_YZMFJYQQK6O0
  1010. downgradeType = "A转储备"
  1011. case dbNboType == StatusB && reqNboType == StatusReserve: // B转储备/option_232GR5NMFCSG0
  1012. downgradeType = "B转储备"
  1013. case dbNboType == StatusC && reqNboType == StatusReserve: // C转储备/option_1ZV2GJLDKQOW0
  1014. downgradeType = "C转储备"
  1015. default:
  1016. }
  1017. return downgradeType
  1018. }
  1019. // BusinessDowngrade 项目降级
  1020. func (p *businessService) BusinessDowngrade(req *model.BusinessDowngradeReq) error {
  1021. business, err := p.BusinessGradation(req.Id, req.NboType, "down")
  1022. if err != nil {
  1023. return err
  1024. }
  1025. downgradeType := p.getBusDingDowngradeType(business.NboType, req.NboType)
  1026. if downgradeType == "" {
  1027. return myerrors.TipsError("错误的降级类型")
  1028. }
  1029. businessMap := g.Map{
  1030. p.Dao.C.ApproStatus: ApprovalWaiting,
  1031. }
  1032. service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
  1033. opnContent := gconv.Map(req)
  1034. opnContent["origNboType"] = business.NboType
  1035. opnContent["approStatus"] = ApprovalWaiting
  1036. service.SetUpdatedInfo(opnContent, p.GetCxtUserId(), p.GetCxtUserName())
  1037. productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
  1038. // 审批流
  1039. workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
  1040. err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
  1041. // 更新项目调级
  1042. _, err = p.Dao.TX(tx).WherePri(req.Id).Data(businessMap).Update()
  1043. if err != nil {
  1044. return err
  1045. }
  1046. // 添加项目动态
  1047. dynamics := model.ProjBusinessDynamics{
  1048. BusId: business.Id,
  1049. OpnType: OpnDowngrade,
  1050. Remark: req.Remark,
  1051. }
  1052. _, err = p.CreateProjBusinessDynamics(tx, dynamics, opnContent)
  1053. if err != nil {
  1054. return err
  1055. }
  1056. // OMS项目降级 审批
  1057. bizCode := business.NboCode + ":" + strconv.Itoa(business.Id)
  1058. _, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectDownGrade, "", &workflow.StartProcessInstanceRequest{
  1059. ProcessCode: &BusinessDowngradeRequestProcessCode,
  1060. FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
  1061. {
  1062. Id: utils.String("TextField-K2AD4O5B"),
  1063. Name: utils.String("项目编码"),
  1064. Value: utils.String(business.NboCode),
  1065. },
  1066. {
  1067. Id: utils.String("TextField_BDLSECETVSG0"),
  1068. Name: utils.String("项目名称"),
  1069. Value: utils.String(business.NboName),
  1070. },
  1071. {
  1072. Id: utils.String("TextField_1J9BJMOZ18F40"),
  1073. Name: utils.String("客户名称"),
  1074. Value: utils.String(business.CustName),
  1075. },
  1076. {
  1077. Id: utils.String("TextField_GL7MQUB723K0"),
  1078. Name: utils.String("所在省"),
  1079. Value: utils.String(business.CustProvince),
  1080. },
  1081. {
  1082. Id: utils.String("TextField_CFA88QQQUUO0"),
  1083. Name: utils.String("所在市"),
  1084. Value: utils.String(business.CustCity),
  1085. },
  1086. {
  1087. Id: utils.String("DDSelectField_VSA3U380ZK00"),
  1088. Name: utils.String("降级类型"),
  1089. Value: utils.String(downgradeType),
  1090. },
  1091. {
  1092. Id: utils.String("DDSelectField_1UCNHJ0P8C5C0"),
  1093. Name: utils.String("产品线"),
  1094. Value: utils.String(productLine),
  1095. },
  1096. {
  1097. Id: utils.String("TextField_X4D3QGARU7K0"),
  1098. Name: utils.String("支持内容"),
  1099. Value: utils.String(req.TechnicalSupportContent),
  1100. },
  1101. {
  1102. Id: utils.String("TextField_AEUWH63LJ0O0"),
  1103. Name: utils.String("销售工程师"),
  1104. Value: utils.String(business.SaleName),
  1105. },
  1106. {
  1107. Id: utils.String("TextareaField_PTGJOKD3J7K0"),
  1108. Name: utils.String("降级原因"),
  1109. Value: utils.String(req.Remark),
  1110. },
  1111. },
  1112. })
  1113. if err != nil {
  1114. g.Log().Error(err)
  1115. return err
  1116. }
  1117. return nil
  1118. })
  1119. return err
  1120. }
  1121. // BusinessDowngradeNotify 项目降级 审批结果通知
  1122. func (p *businessService) BusinessDowngradeNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
  1123. business, err := p.checkDingTalkNotify(flow, msg)
  1124. if err != nil {
  1125. return err
  1126. }
  1127. var data = g.Map{}
  1128. var remark string
  1129. if msg.ProcessType == "terminate" {
  1130. data[p.Dao.C.ApproStatus] = ApprovalReturn
  1131. }
  1132. if msg.ProcessType == "finish" && msg.Result == "refuse" {
  1133. data[p.Dao.C.ApproStatus] = ApprovalRejection
  1134. }
  1135. if msg.ProcessType == "finish" && msg.Result == "agree" {
  1136. // 从项目动态内获取变更信息
  1137. dynamics := new(model.ProjBusinessDynamics)
  1138. dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).Where(projDao.ProjBusinessDynamics.C.BusId, business.Id)
  1139. err = dynamicsDao.Where(projDao.ProjBusinessDynamics.C.OpnType, OpnDowngrade).OrderDesc("created_time").Scan(dynamics)
  1140. if err != nil {
  1141. return err
  1142. }
  1143. updateData := new(model.BusinessDowngradeReq)
  1144. gconv.Struct(dynamics.OpnContent, updateData)
  1145. data = gconv.Map(updateData)
  1146. data[p.Dao.C.ApproStatus] = ApprovalOK
  1147. remarkMap := gconv.Map(dynamics.OpnContent)
  1148. remark = gconv.String(g.Map{"nboType": remarkMap["nboType"], "origNboType": remarkMap["origNboType"]})
  1149. }
  1150. // 项目修改
  1151. _, err = p.Dao.WherePri(business.Id).FieldsEx(service.UpdateFieldEx...).Data(data).Update()
  1152. if err != nil {
  1153. return err
  1154. }
  1155. // 添加项目动态
  1156. dynamics := model.ProjBusinessDynamics{
  1157. BusId: business.Id,
  1158. OpnType: OpnDowngradeApproval,
  1159. Remark: remark,
  1160. }
  1161. _, err = p.CreateProjBusinessDynamics(nil, dynamics, data)
  1162. if err != nil {
  1163. return err
  1164. }
  1165. return nil
  1166. }
  1167. // SetPrimacyContact 项目设置首要联系人
  1168. func (p *businessService) SetPrimacyContact(req *model.BusinessPrimacyContactReq) (err error) {
  1169. business, err := p.Dao.Where(projDao.ProjBusiness.C.Id, req.Id).One()
  1170. if err != nil {
  1171. return err
  1172. }
  1173. if business == nil {
  1174. return myerrors.TipsError("项目不存在。")
  1175. }
  1176. businessMap := g.Map{
  1177. p.Dao.C.ContactId: req.ContactId,
  1178. p.Dao.C.ContactName: req.ContactName,
  1179. p.Dao.C.ContactPostion: req.ContactPostion,
  1180. p.Dao.C.ContactTelephone: req.ContactTelephone,
  1181. }
  1182. service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
  1183. opnContent := gconv.Map(gconv.String(businessMap))
  1184. opnContent["origContactId"] = business.ContactId
  1185. opnContent["origContactName"] = business.ContactName
  1186. opnContent["origContactPostion"] = business.ContactPostion
  1187. opnContent["origContactTelephone"] = business.ContactTelephone
  1188. err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
  1189. // 更新项目
  1190. _, err = p.Dao.TX(tx).WherePri(projDao.ProjBusiness.C.Id, req.Id).Data(businessMap).Update()
  1191. if err != nil {
  1192. return err
  1193. }
  1194. // 添加项目动态
  1195. dynamics := model.ProjBusinessDynamics{
  1196. BusId: req.Id,
  1197. OpnType: OpnPrimacyContact,
  1198. Remark: req.Remark,
  1199. }
  1200. _, err = p.CreateProjBusinessDynamics(tx, dynamics, opnContent)
  1201. return err
  1202. })
  1203. return err
  1204. }
  1205. // UpdateBusinessStatus 更新项目状态
  1206. func (p *businessService) UpdateBusinessStatus(req *model.UpdateBusinessStatusReq) error {
  1207. business, err := p.Dao.WherePri(req.Id).One()
  1208. if err != nil {
  1209. return err
  1210. }
  1211. if business == nil {
  1212. return myerrors.TipsError("项目不存在。")
  1213. }
  1214. businessMap := g.Map{
  1215. p.Dao.C.NboStatus: req.NboStatus,
  1216. p.Dao.C.Remark: req.Remark,
  1217. }
  1218. service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
  1219. opnContent := gconv.Map(gconv.String(businessMap))
  1220. opnContent["origNboStatus"] = business.NboStatus
  1221. err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
  1222. // 更新项目
  1223. _, err = p.Dao.TX(tx).WherePri(projDao.ProjBusiness.C.Id, req.Id).Data(businessMap).Update()
  1224. if err != nil {
  1225. return err
  1226. }
  1227. // 添加项目动态
  1228. dynamics := model.ProjBusinessDynamics{
  1229. BusId: req.Id,
  1230. OpnType: OpnStatus,
  1231. Remark: req.Remark,
  1232. }
  1233. _, err = p.CreateProjBusinessDynamics(tx, dynamics, opnContent)
  1234. return err
  1235. })
  1236. return err
  1237. }
  1238. // CreateProjBusinessDynamics 创建项目动态
  1239. func (p *businessService) CreateProjBusinessDynamics(tx *gdb.TX, dynamics model.ProjBusinessDynamics, opnContent interface{}) (int64, error) {
  1240. if v, ok := opnContent.(g.Map); ok {
  1241. opnContent = utils.MapKeySnakeCamelCase(v)
  1242. }
  1243. // 添加项目动态
  1244. dynamics.OpnPeopleId = p.GetCxtUserId()
  1245. dynamics.OpnPeople = p.GetCxtUserName()
  1246. dynamics.OpnDate = gtime.Now()
  1247. dynamics.OpnContent = gconv.String(opnContent)
  1248. service.SetCreatedInfo(&dynamics, p.GetCxtUserId(), p.GetCxtUserName())
  1249. dao := projDao.NewProjBusinessDynamicsDao(p.Tenant).M
  1250. if tx != nil {
  1251. dao = dao.TX(tx)
  1252. }
  1253. lastId, err := dao.InsertAndGetId(&dynamics)
  1254. return lastId, err
  1255. }
  1256. // ConvertToReserve 转为储备项目
  1257. func (p *businessService) ConvertToReserve(req *model.BusinessToReserveReq) error {
  1258. business, err := p.Dao.WherePri(req.Id).WhereNot(p.Dao.C.ApproStatus, ApprovalWaiting).One()
  1259. if err != nil {
  1260. return err
  1261. }
  1262. if business == nil {
  1263. return myerrors.TipsError("项目已提交审批任务,无法重复提交。")
  1264. }
  1265. productLine, _ := service.GetDictLabelByTypeAndValue(p.Ctx, "sys_product_line", business.ProductLine)
  1266. // 审批流
  1267. workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
  1268. err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
  1269. // 更新项目
  1270. businessMap := g.Map{
  1271. p.Dao.C.ApproStatus: ApprovalWaiting,
  1272. p.Dao.C.ProjConversionTime: gtime.Now(),
  1273. p.Dao.C.ProjConversionReason: req.ProjConversionReason,
  1274. }
  1275. service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
  1276. _, err = p.Dao.TX(tx).WherePri(business.Id).Data(businessMap).Update()
  1277. if err != nil {
  1278. return err
  1279. }
  1280. // 添加项目动态
  1281. dynamics := model.ProjBusinessDynamics{
  1282. BusId: business.Id,
  1283. OpnType: OpnToReserve,
  1284. Remark: req.ProjConversionReason,
  1285. }
  1286. _, err = p.CreateProjBusinessDynamics(tx, dynamics, businessMap)
  1287. if err != nil {
  1288. return err
  1289. }
  1290. // OMS项目转储备 审批
  1291. bizCode := business.NboCode + ":" + strconv.Itoa(business.Id)
  1292. _, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectToReserve, "", &workflow.StartProcessInstanceRequest{
  1293. ProcessCode: &ConvertToReserveRequestProcessCode,
  1294. FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
  1295. {
  1296. Id: utils.String("TextField-K2AD4O5B"),
  1297. Name: utils.String("项目编码"),
  1298. Value: utils.String(business.NboCode),
  1299. },
  1300. {
  1301. Id: utils.String("TextField_CMH6TBXYR5S0"),
  1302. Name: utils.String("项目名称"),
  1303. Value: utils.String(business.NboName),
  1304. },
  1305. {
  1306. Id: utils.String("TextField_YQBGGYHQPS00"),
  1307. Name: utils.String("客户名称"),
  1308. Value: utils.String(business.CustName),
  1309. },
  1310. {
  1311. Id: utils.String("DDSelectField_VBY9YAIOK5C0"),
  1312. Name: utils.String("项目级别"),
  1313. Value: utils.String(convertToReserveType[business.NboType]),
  1314. },
  1315. {
  1316. Id: utils.String("DDSelectField_1UVBB1LZHIJK0"),
  1317. Name: utils.String("产品线"),
  1318. Value: utils.String(productLine),
  1319. },
  1320. {
  1321. Id: utils.String("TextField_1NDD3TY8KJB40"),
  1322. Name: utils.String("销售工程师"),
  1323. Value: utils.String(business.SaleName),
  1324. },
  1325. {
  1326. Id: utils.String("TextareaField_15KZFM4YHQ8W0"),
  1327. Name: utils.String("转化原因"),
  1328. Value: utils.String(req.ProjConversionReason),
  1329. },
  1330. },
  1331. })
  1332. if err != nil {
  1333. g.Log().Error(err)
  1334. return err
  1335. }
  1336. return nil
  1337. })
  1338. return err
  1339. }
  1340. // ConvertToReserveNotify 转为储备项目 审批结果通知
  1341. func (p *businessService) ConvertToReserveNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
  1342. business, err := p.checkDingTalkNotify(flow, msg)
  1343. if err != nil {
  1344. return err
  1345. }
  1346. var data = g.Map{}
  1347. if msg.ProcessType == "terminate" {
  1348. data[p.Dao.C.ApproStatus] = ApprovalReturn
  1349. }
  1350. if msg.ProcessType == "finish" && msg.Result == "refuse" {
  1351. data[p.Dao.C.ApproStatus] = ApprovalRejection
  1352. }
  1353. if msg.ProcessType == "finish" && msg.Result == "agree" {
  1354. data[p.Dao.C.NboType] = StatusReserve
  1355. data[p.Dao.C.ApproStatus] = ApprovalOK
  1356. }
  1357. // 项目修改
  1358. _, err = p.Dao.WherePri(business.Id).FieldsEx(service.UpdateFieldEx...).Data(data).Update()
  1359. if err != nil {
  1360. return err
  1361. }
  1362. // 添加项目动态
  1363. dynamics := model.ProjBusinessDynamics{
  1364. BusId: business.Id,
  1365. OpnType: OpnToReserveApproval,
  1366. }
  1367. _, err = p.CreateProjBusinessDynamics(nil, dynamics, data)
  1368. if err != nil {
  1369. return err
  1370. }
  1371. return err
  1372. }
  1373. // 钉钉审批通知检查
  1374. func (p *businessService) checkDingTalkNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) (*model.ProjBusiness, error) {
  1375. bizCode := strings.Split(flow.BizCode, ":")
  1376. if len(bizCode) != 2 {
  1377. return nil, fmt.Errorf("项目审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id)
  1378. }
  1379. nboCode := bizCode[0]
  1380. busId, err := strconv.Atoi(bizCode[1])
  1381. if err != nil {
  1382. return nil, fmt.Errorf("项目审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id)
  1383. }
  1384. if msg.ProcessType != "finish" && msg.ProcessType != "terminate" {
  1385. return nil, fmt.Errorf("无法识别的 ProcessType :%s", msg.ProcessType)
  1386. }
  1387. if msg.Result != "agree" && msg.Result != "refuse" && msg.Result != "" {
  1388. return nil, fmt.Errorf("无法识别的 Result :%s", msg.Result)
  1389. }
  1390. fmt.Println(msg)
  1391. business, err := p.Dao.WherePri(busId).Where(p.Dao.C.NboCode, nboCode).One()
  1392. if err != nil {
  1393. return nil, err
  1394. }
  1395. if business == nil {
  1396. return nil, fmt.Errorf("项目不存在:%s Id: %d", flow.BizCode, flow.Id)
  1397. }
  1398. return business, nil
  1399. }