cust_customer.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. package cust
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "math"
  7. "strconv"
  8. "dashoo.cn/opms_libary/myerrors"
  9. "github.com/360EntSecGroup-Skylar/excelize"
  10. "github.com/gogf/gf/frame/g"
  11. "github.com/gogf/gf/os/gtime"
  12. "github.com/gogf/gf/util/gconv"
  13. "dashoo.cn/micro/app/dao/cust"
  14. platdao "dashoo.cn/micro/app/dao/plat"
  15. model "dashoo.cn/micro/app/model/cust"
  16. "dashoo.cn/micro/app/service"
  17. )
  18. type CustomerService struct {
  19. *service.ContextService
  20. Dao *cust.CustCustomerDao
  21. BelongDao *cust.CustCustomerBelongDao
  22. DynamicsDao *cust.CustCustomerDynamicsDao
  23. ContactDao *cust.CustCustomerContactDao
  24. FollowDao *platdao.PlatFollowupDao
  25. BelongServer *CustomerbelongService
  26. ContanctServer *CustomercontactService
  27. }
  28. var isPublic, noPublic = "10", "20" // 公海,非公海
  29. var AllocaTion, OperaTion, Receive, Merge = "10", "20", "30", "40" // 10分配20转移30领取40合并
  30. type OpnType struct {
  31. OperaTion string
  32. }
  33. func NewCustomerService(ctx context.Context) (svc *CustomerService, err error) {
  34. svc = new(CustomerService)
  35. if svc.ContextService, err = svc.Init(ctx); err != nil {
  36. return nil, err
  37. }
  38. svc.Dao = cust.NewCustCustomerDao(svc.Tenant)
  39. svc.BelongDao = cust.NewCustCustomerBelongDao(svc.Tenant)
  40. svc.DynamicsDao = cust.NewCustCustomerDynamicsDao(svc.Tenant)
  41. svc.ContactDao = cust.NewCustCustomerContactDao(svc.Tenant)
  42. svc.FollowDao = platdao.NewPlatFollowupDao(svc.Tenant)
  43. svc.BelongServer, _ = NewCustomerBelongService(ctx)
  44. svc.ContanctServer, _ = NewCustomerContactService(ctx)
  45. return svc, nil
  46. }
  47. // GetList 客户列表列表
  48. func (s *CustomerService) GetList(req *model.CustCustomerSearchReq) (total int, customerList []*model.CustList, err error) {
  49. Model := s.Dao.M
  50. if req.TargetType == "" {
  51. if !req.IsPublic {
  52. Model = Model.Where(s.Dao.Columns.SalesId, s.CxtUser.Id).Where(s.Dao.Columns.IsPublic, noPublic)
  53. } else {
  54. Model = Model.Where(s.Dao.Columns.IsPublic, isPublic)
  55. }
  56. }
  57. //客户名称
  58. if req.CustName != "" {
  59. Model = Model.Where(s.Dao.Columns.CustName+" like ?", "%"+req.CustName+"%")
  60. }
  61. //客户编码
  62. if req.CustCode != "" {
  63. Model = Model.Where(s.Dao.Columns.CustCode+" like ?", "%"+req.CustCode+"%")
  64. }
  65. //客户行业
  66. if req.CustIndustry != "" {
  67. Model = Model.Where(s.Dao.Columns.CustIndustry+" like ?", "%"+req.CustIndustry+"%")
  68. }
  69. //客户级别
  70. if req.CustLevel != "" {
  71. Model = Model.Where(s.Dao.Columns.CustLevel, req.CustLevel)
  72. }
  73. //
  74. if req.FollowUpDate != "" {
  75. Model = Model.Where(s.Dao.Columns.FollowUpDate+" like ? ", req.FollowUpDate+"%")
  76. }
  77. total, err = Model.Count()
  78. if err != nil {
  79. g.Log().Error(err)
  80. return
  81. }
  82. if req.IsRemovePage {
  83. Model = Model
  84. } else {
  85. Model = Model.Page(req.GetPage())
  86. }
  87. err = Model.Order("id desc").Scan(&customerList)
  88. if err != nil {
  89. g.Log().Error(err)
  90. return
  91. }
  92. return
  93. }
  94. // Create 创建客户
  95. func (s *CustomerService) Create(req *model.CustomerAddSeq) (insertId int64, err error) {
  96. cusTomer := new(model.CustCustomer)
  97. count, err := s.Dao.Where(s.Dao.Columns.CustName, req.CustName).Count()
  98. if err != nil {
  99. g.Log().Error(err)
  100. return
  101. }
  102. if count > 0 {
  103. return 0, myerrors.NewMsgError(nil, "该客户信息已存在,不可重复添加")
  104. }
  105. if err = gconv.Struct(req, cusTomer); err != nil {
  106. return
  107. }
  108. service.SetCreatedInfo(cusTomer, s.GetCxtUserId(), s.CxtUser.NickName)
  109. cusTomer.CustCode = "CT" + strconv.Itoa(int(gtime.Timestamp()))
  110. cusTomer.CustStatus = "10"
  111. roles := s.GetCxtUserRoles()
  112. isSales := false
  113. for _, v := range roles {
  114. if v == "Sales" { // 销售角色
  115. isSales = true
  116. }
  117. }
  118. // 销售角色
  119. if isSales {
  120. cusTomer.IsPublic = noPublic
  121. cusTomer.SalesId = s.GetCxtUserId()
  122. cusTomer.SalesName = s.CxtUser.NickName
  123. insertId, err = s.Dao.InsertAndGetId(cusTomer)
  124. if err != nil {
  125. g.Log().Error(err)
  126. return 0, err
  127. }
  128. s.CreateBelong(int(insertId))
  129. } else {
  130. cusTomer.IsPublic = isPublic
  131. insertId, err = s.Dao.InsertAndGetId(cusTomer)
  132. if err != nil {
  133. g.Log().Error(err)
  134. return 0, err
  135. }
  136. }
  137. return insertId, err
  138. }
  139. // CreateBelong 创建客户归属信息
  140. func (s *CustomerService) CreateBelong(custId int) (insertId int64, err error) {
  141. belong := new(model.CustomerBelongAddSeq)
  142. belong.CustId = custId
  143. belong.SaleName = s.CxtUser.NickName
  144. belong.OpnType = AllocaTion
  145. belong.OpnPeople = s.CxtUser.NickName
  146. belong.OpnDatetime = gtime.Now()
  147. err = s.BelongServer.Create(belong)
  148. if err != nil {
  149. g.Log().Error(err)
  150. return
  151. }
  152. return
  153. }
  154. // 删除客户
  155. func (s *CustomerService) DeleteByIds(Ids []int64) (err error) {
  156. customerCount, err := s.Dao.Where(" id in (?)", Ids).Count()
  157. if err != nil {
  158. g.Log().Error(err)
  159. return
  160. }
  161. if customerCount == 0 {
  162. err = myerrors.NewMsgError(nil, "客户信息不存在")
  163. return
  164. }
  165. //删除客户表
  166. _, err = s.Dao.Where("id in (?) ", Ids).Delete()
  167. if err == nil {
  168. _, err = s.ContactDao.Where("cust_id in (?)", Ids).Delete()
  169. if err == nil {
  170. _, err = s.BelongDao.Where("cust_id in (?)", Ids).Delete()
  171. if err != nil {
  172. g.Log().Error(err)
  173. return
  174. }
  175. } else {
  176. g.Log().Error(err)
  177. return
  178. }
  179. } else {
  180. g.Log().Error(err)
  181. return
  182. }
  183. return
  184. }
  185. // UpdateById 修改客户
  186. func (s *CustomerService) UpdateById(req *model.UpdateCustomer) (err error) {
  187. //判断数据是否存在
  188. count, err := s.Dao.Where("id = ", req.Id).Count()
  189. if err != nil {
  190. g.Log().Error(err)
  191. return
  192. }
  193. if count == 0 {
  194. return
  195. }
  196. //新的客户名字是否存在
  197. num, err := s.Dao.Where(s.Dao.Columns.CustName, req.CustName).WhereNot(s.Dao.Columns.Id, req.Id).Count()
  198. if err != nil {
  199. g.Log().Error(err)
  200. return err
  201. }
  202. if num > 0 {
  203. return myerrors.NewMsgError(nil, fmt.Sprintf("客户名称[%s]已存在", req.CustName))
  204. }
  205. CustomertData := new(model.CustomerAddSeq)
  206. if err = gconv.Struct(req, CustomertData); err != nil {
  207. return
  208. }
  209. service.SetUpdatedInfo(CustomertData, s.GetCxtUserId(), s.CxtUser.NickName)
  210. _, err = s.Dao.FieldsEx(s.Dao.Columns.CreatedTime, s.Dao.Columns.CreatedBy, s.Dao.Columns.CreatedName, s.Dao.Columns.Id, s.Dao.Columns.CustCode, s.Dao.Columns.SalesName, s.Dao.Columns.SalesId).
  211. WherePri(s.Dao.Columns.Id, req.Id).Update(CustomertData)
  212. if err != nil {
  213. g.Log().Error(err)
  214. return
  215. }
  216. return
  217. }
  218. // MoveToPubic 移入公海
  219. func (s *CustomerService) MoveToPubic(Ids []int64) (err error) {
  220. count, err := s.Dao.WhereIn(s.Dao.Columns.Id, Ids).Count()
  221. if err != nil {
  222. g.Log().Error(err)
  223. return
  224. }
  225. if count == 0 {
  226. err = myerrors.NewMsgError(nil, "没有要移除的数据")
  227. return
  228. }
  229. _, err = s.Dao.Data(g.Map{
  230. "is_public": isPublic,
  231. "sales_id": 0,
  232. "sales_name": "",
  233. "dept_id": 0,
  234. "dept_name": "",
  235. "create_time": gtime.Now(),
  236. "updated_by": s.GetCxtUserId(),
  237. "updated_name": s.GetCxtUserName(),
  238. "updated_time": gtime.Now(),
  239. }).WhereIn(s.ContactDao.Columns.Id, Ids).Update()
  240. if err != nil {
  241. g.Log().Error(err)
  242. return
  243. }
  244. return nil
  245. }
  246. // AssignCustomer 分配客户
  247. func (s *CustomerService) AssignCustomer(req *model.AssignCustomerReq) (err error) {
  248. data, err := s.Dao.Where("id in (?)", req.Ids).LockShared().All()
  249. if err != nil {
  250. g.Log().Error(err)
  251. return
  252. }
  253. if len(data) == 0 {
  254. return myerrors.NewMsgError(nil, "无可分配客户")
  255. }
  256. for _, v := range data {
  257. if v.SalesId != 0 {
  258. return myerrors.NewMsgError(nil, fmt.Sprintf("客户名称[%s]已被领取或分配", v.CustName))
  259. }
  260. }
  261. s.ChangeCustBelong(req.Ids, req.SalesId, req.SalesName)
  262. if req.Receive != "" {
  263. req.Receive = Receive
  264. } else {
  265. req.Receive = AllocaTion
  266. }
  267. s.BatchCreatebelong(data, req)
  268. return
  269. }
  270. // GetEntityById 客户详情
  271. func (s *CustomerService) GetEntityById(Ids []int64) (entityInfo []*model.CustList, err error) {
  272. Model := s.Dao //
  273. err = Model.Where(" id in (?)", Ids).Scan(&entityInfo)
  274. if err != nil {
  275. g.Log().Error(err)
  276. return
  277. }
  278. return
  279. }
  280. // GetCustNameIsExist 获取客户名称
  281. func (s *CustomerService) GetCustNameIsExist(name string) (exist bool, err error) {
  282. count, err := s.Dao.Where(cust.CustCustomer.Columns.CustName, name).Count()
  283. if err != nil {
  284. g.Log().Error(err)
  285. return
  286. }
  287. exist = false
  288. if count > 0 {
  289. exist = true
  290. }
  291. return
  292. }
  293. // CustAbstract 客户摘要
  294. func (s *CustomerService) CustAbstract(Id int64) (followInfo *model.Follow, err error) {
  295. count, err := s.FollowDao.Where(s.FollowDao.Columns.CustId, Id).Count()
  296. if err != nil {
  297. g.Log().Error(err)
  298. return
  299. }
  300. followInfo = new(model.Follow)
  301. followInfo.FollowCount = count
  302. followTime, err := s.Dao.Fields(s.Dao.Columns.FollowUpDate, s.Dao.Columns.CreatedTime).FindOne(Id)
  303. if err != nil {
  304. g.Log().Error(err)
  305. return
  306. }
  307. now := gtime.Now()
  308. var hours float64
  309. if followTime.FollowUpDate == nil {
  310. poor := now.Sub(gtime.New(followTime.CreatedTime))
  311. hours = float64(poor.Hours() / 24)
  312. } else {
  313. poor := now.Sub(gtime.New(followTime.FollowUpDate))
  314. hours = float64(poor.Hours() / 24)
  315. }
  316. if hours < 0 {
  317. followInfo.NotFollowDay = 0
  318. } else {
  319. followInfo.NotFollowDay = int(math.Floor(hours))
  320. }
  321. return
  322. }
  323. // TransCustomer 转移客户
  324. func (s *CustomerService) TransCustomer(req *model.AssignCustomerReq) (err error) {
  325. data, err := s.Dao.Fields("sales_id,sales_name,id").Where("id in (?)", req.Ids).All()
  326. if err != nil {
  327. g.Log().Error(err)
  328. return err
  329. }
  330. if len(data) == 0 {
  331. return myerrors.NewMsgError(nil, "数据不存在")
  332. }
  333. s.ChangeCustBelong(req.Ids, req.SalesId, req.SalesName)
  334. s.BatchCreatebelong(data, req)
  335. return
  336. }
  337. // ChangeCustBelong 变更客户所属关系
  338. func (s *CustomerService) ChangeCustBelong(Ids []int64, salesId int64, salesName string) (err error) {
  339. _, err = s.Dao.Data(g.Map{
  340. "sales_id": salesId,
  341. "is_public": noPublic,
  342. "sales_name": salesName,
  343. "updated_by": s.GetCxtUserId(),
  344. "updated_name": s.GetCxtUserName(),
  345. "updated_time": gtime.Now(),
  346. }).Where("id in (?)", Ids).Update()
  347. if err != nil {
  348. g.Log().Error(err)
  349. return
  350. }
  351. return
  352. }
  353. // OperationLog 客户操作日志
  354. func (s *CustomerService) OperationLog(ctx context.Context, ids []int64, req *model.AddCustomerDynameicsReq) (err error) {
  355. cusDynameics := new(model.CustCustomerDynamics)
  356. if err = gconv.Struct(req, cusDynameics); err != nil {
  357. err = myerrors.NewMsgError(nil, "操作日志验证结构体失败")
  358. return
  359. }
  360. maps := []map[string]interface{}{}
  361. for _, v := range ids {
  362. contact := map[string]interface{}{}
  363. contact["cust_id"] = v
  364. contact["opn_people_id"] = s.GetCxtUserId()
  365. contact["opn_people"] = s.GetCxtUserName()
  366. contact["opn_date"] = req.OpnDate
  367. contact["opn_type"] = req.OpnType
  368. contact["remark"] = ""
  369. contact["created_by"] = s.GetCxtUserId()
  370. contact["created_name"] = s.CxtUser.NickName
  371. contact["created_by"] = s.GetCxtUserId()
  372. contact["created_time"] = gtime.Now()
  373. contact["opn_content"] = req.OpnContent
  374. maps = append(maps, contact)
  375. }
  376. _, err = s.DynamicsDao.Insert(maps)
  377. if err != nil {
  378. g.Log().Error(err)
  379. return
  380. }
  381. return
  382. }
  383. // GetDynamicsList 客户动态
  384. func (s *CustomerService) GetDynamicsList(req *model.CustomerDynameicsReq) (total int, result []interface{}, err error) {
  385. total, err = s.DynamicsDao.Where("cust_id = ", req.CustId).Count()
  386. if err != nil {
  387. g.Log().Error(err)
  388. return
  389. }
  390. dynamics := []*model.CustomerDynameicsRep{}
  391. err = s.DynamicsDao.Where("cust_id = ?", req.CustId).Order("created_time desc").Scan(&dynamics)
  392. if err != nil {
  393. g.Log().Error(err)
  394. return
  395. }
  396. dynamicsList := make(map[string][]*model.CustomerDynameicsRep)
  397. for _, v := range dynamics {
  398. opnDate := gtime.New(v.OpnDate).Format("Y-m-d")
  399. dynamicsList[opnDate] = append(dynamicsList[opnDate], &model.CustomerDynameicsRep{
  400. OpnPeople: v.OpnPeople,
  401. OpnDate: v.OpnDate,
  402. OpnType: v.OpnType,
  403. OpnContent: v.OpnContent,
  404. })
  405. }
  406. result = append(result, dynamicsList)
  407. return
  408. }
  409. // MergeCustomer 合并客户
  410. func (s *CustomerService) MergeCustomer(req *model.MergecustomerRep) (err error) {
  411. //当前目标客户是否存在
  412. customerCount, err := s.Dao.FindCount(req.Id)
  413. if err != nil {
  414. g.Log().Error(err)
  415. return
  416. }
  417. if customerCount == 0 {
  418. return myerrors.NewMsgError(nil, "该客户不存在")
  419. }
  420. _, err = s.ContactDao.Where(" cust_id in (?)", req.ChooseId).Delete()
  421. if err != nil {
  422. g.Log().Error(err)
  423. return
  424. }
  425. CustomertData := new(model.CustomerAddSeq)
  426. if err = gconv.Struct(req, CustomertData); err != nil {
  427. g.Log().Error(err)
  428. return
  429. }
  430. service.SetUpdatedInfo(CustomertData, s.GetCxtUserId(), s.GetCxtUserName())
  431. _, err = s.Dao.FieldsEx(s.Dao.Columns.CreatedTime, s.Dao.Columns.CreatedBy,
  432. s.Dao.Columns.CreatedName, s.Dao.Columns.Id,
  433. s.Dao.Columns.CustCode).WherePri(s.Dao.Columns.Id, req.Id).Update(CustomertData)
  434. if err != nil {
  435. g.Log().Error(err)
  436. return
  437. }
  438. //删除被合并的客户信息
  439. _, err = s.Dao.Where(" id in (?)", req.ChooseId).Delete()
  440. if err != nil {
  441. g.Log().Error(err)
  442. return
  443. }
  444. //删除 所选客户销售联系人
  445. _, err = s.BelongDao.Where(" cust_id in (?)", req.ChooseId).WhereOr(" cust_id = ", req.Id).Delete()
  446. if err != nil {
  447. g.Log().Error(err)
  448. return
  449. }
  450. //插入一条合并成功的归属记录
  451. req.CustomerBelongAddSeq.CustId = req.Id
  452. req.CustomerBelongAddSeq.OpnType = Merge
  453. req.CustomerBelongAddSeq.OpnPeople = s.GetCxtUserName()
  454. req.CustomerBelongAddSeq.OpnDatetime = gtime.Now()
  455. req.CustomerBelongAddSeq.SaleName = req.SalesName
  456. s.BelongServer.Create(req.CustomerBelongAddSeq)
  457. return
  458. }
  459. // Createcontact 联系人(合并)预留
  460. func (s *CustomerService) Createcontact(Ids []int64, req *model.CustCustomerContactSeq) (err error) {
  461. _, err = s.ContactDao.Where(" cust_id in (?)", Ids).Delete()
  462. if err != nil {
  463. g.Log().Error(err)
  464. return
  465. }
  466. s.ContanctServer.Create(req)
  467. return
  468. }
  469. // BatchCreatebelong 批量插入客户归属记录表
  470. func (s *CustomerService) BatchCreatebelong(rep []*model.CustCustomer, req *model.AssignCustomerReq, n ...interface{}) (err error) {
  471. var belongData []*model.CustCustomerBelong
  472. userName := s.GetCxtUserName()
  473. for _, v := range rep {
  474. orig_sale_name := v.SalesName
  475. belong := new(model.CustCustomerBelong)
  476. belong.CustId = v.Id
  477. belong.SaleName = req.SalesName
  478. belong.OrigSaleName = orig_sale_name
  479. belong.OpnType = req.Receive
  480. belong.OpnPeople = userName
  481. belong.CreatedName = userName
  482. belong.OpnDatetime = gtime.Now()
  483. belong.Remark = req.Remark
  484. belong.CreatedBy = s.GetCxtUserId()
  485. belongData = append(belongData, belong)
  486. }
  487. _, err = s.BelongDao.Insert(belongData)
  488. if err != nil {
  489. g.Log().Error(err)
  490. return
  491. }
  492. return
  493. }
  494. // 导出数据
  495. func (s *CustomerService) Export(req *model.CustCustomerExport) (content *model.CustExport, err error) {
  496. var con model.CustExport
  497. req.IsRemovePage = true // 去掉分页标识
  498. total, data, err := s.GetList(&req.CustCustomerSearchReq)
  499. if err != nil {
  500. return
  501. }
  502. f := excelize.NewFile()
  503. index := f.NewSheet("Sheet1")
  504. for index, item := range req.Columns {
  505. sheetPosition := service.Div(index+1) + "1"
  506. f.SetCellValue("Sheet1", sheetPosition, item)
  507. }
  508. if total > 0 {
  509. for ck, item := range data {
  510. for index, v := range req.Columns {
  511. if v == "客户编码" {
  512. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), item.CustCode)
  513. }
  514. if v == "客户名称" {
  515. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), item.CustName)
  516. }
  517. if v == "助记名" {
  518. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), item.AbbrName)
  519. }
  520. if v == "助记名" {
  521. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), item.AbbrName)
  522. }
  523. if v == "所在地区" {
  524. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), item.CustLocation)
  525. }
  526. if v == "客户行业" {
  527. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), item.CustIndustry)
  528. }
  529. if v == "客户级别" {
  530. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), item.CustLevel)
  531. }
  532. if v == "客户状态" {
  533. var CustStatus string
  534. CustStatus = "正常"
  535. if item.CustStatus != "10" {
  536. CustStatus = "异常"
  537. }
  538. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), CustStatus)
  539. }
  540. if v == "最后跟进时间" {
  541. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), item.FollowUpDate)
  542. }
  543. if v == "创建时间" {
  544. f.SetCellValue("Sheet1", service.Div(index+1)+strconv.Itoa(ck+2), item.CreatedTime)
  545. }
  546. }
  547. }
  548. }
  549. f.SetActiveSheet(index)
  550. var buffer *bytes.Buffer
  551. buffer, _ = f.WriteToBuffer()
  552. con.Content = buffer.Bytes()
  553. return &con, err
  554. }