business.go 46 KB

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