business.go 59 KB

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