business.go 59 KB

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