business.go 66 KB

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