business.go 55 KB

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