business.go 47 KB

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