milk_original.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. package crontab
  2. import (
  3. "fmt"
  4. "kpt-pasture/model"
  5. "kpt-pasture/util"
  6. "sort"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  11. "go.uber.org/zap"
  12. )
  13. func (e *Entry) UpdateMilkOriginal() error {
  14. pastureList := e.FindPastureList()
  15. if pastureList == nil || len(pastureList) == 0 {
  16. return nil
  17. }
  18. for _, pasture := range pastureList {
  19. e.ProcessMilkOriginal(pasture.Id)
  20. }
  21. return nil
  22. }
  23. func (e *Entry) ProcessMilkOriginal(pastureId int64) {
  24. milkConfigList, err := e.FindMilkConfigure(pastureId)
  25. if err != nil {
  26. zaplog.Error("MilkOriginal", zap.Any("pastureId", pastureId), zap.Any("err", err))
  27. return
  28. }
  29. milkClassConfig := &MilkClassConfig{}
  30. for _, v := range milkConfigList {
  31. switch v.Name {
  32. case model.FirstClassMilkTime:
  33. milkClassConfig.FirstClassMilkTime = v.Value
  34. case model.SecondClassMilkTime:
  35. milkClassConfig.SecondClassMilkTime = v.Value
  36. case model.ThirdClassMilkTime:
  37. milkClassConfig.ThirdClassMilkTime = v.Value
  38. case model.FourthClassMilkTime:
  39. milkClassConfig.FourthClassMilkTime = v.Value
  40. case model.UpdateMilkOriginalMaxId:
  41. maxId, _ := strconv.ParseInt(v.Value, 10, 64)
  42. milkClassConfig.OldUpdateMaxId = maxId
  43. }
  44. }
  45. xDBeg, xBeg1, xBeg2, xBeg3, xBeg4 := parseXBeg(milkClassConfig)
  46. e.UpdateShifts(pastureId, xBeg1, xBeg2, xBeg3, xBeg4)
  47. e.UpdateMilkDate(pastureId, xDBeg)
  48. // 获取当前最大Id
  49. var currentMaxId int64
  50. if err = e.DB.Model(new(model.MilkOriginal)).
  51. Select("MAX(id)").
  52. Where("pasture_id = ?", pastureId).
  53. Where("id > ?", milkClassConfig.OldUpdateMaxId).
  54. Scan(&currentMaxId).Error; err != nil {
  55. zaplog.Error("DeleteRepeatMilkData GetOriWid", zap.Any("pastureId", pastureId), zap.Any("err", err))
  56. return
  57. }
  58. milkClassConfig.CurrentMaxId = currentMaxId
  59. // 获取时间范围和ID范围
  60. deleteModel := &DeleteMilkOriginal{}
  61. selectSql := fmt.Sprintf(`MIN(DATE(TIMESTAMPADD(HOUR, -%d, attach_time))) as x_mind,
  62. MAX(DATE(TIMESTAMPADD(HOUR, -%d, attach_time))) as x_max_d2, MIN(id) as x_min_wid, MAX(id) as x_max_wid`, xDBeg, xDBeg)
  63. if err = e.DB.Model(new(model.MilkOriginal)).
  64. Select(selectSql).
  65. Where("pasture_id = ?", pastureId).
  66. Where("id > ?", milkClassConfig.OldUpdateMaxId).
  67. First(deleteModel).Error; err != nil {
  68. zaplog.Error("DeleteRepeatMilkData", zap.Any("pastureId", pastureId), zap.Any("err", err))
  69. return
  70. }
  71. milkOriginalList := make([]*model.MilkOriginal, 0)
  72. if err = e.DB.Model(new(model.MilkOriginal)).
  73. Where("pasture_id = ?", pastureId).
  74. Where("id BETWEEN ? AND ?", milkClassConfig.OldUpdateMaxId+1, milkClassConfig.CurrentMaxId).
  75. Find(&milkOriginalList).Error; err != nil {
  76. zaplog.Error("DeleteRepeatMilkData", zap.Any("pastureId", pastureId), zap.Any("err", err))
  77. return
  78. }
  79. e.DeleteRepeatMilkData(pastureId, deleteModel, milkClassConfig, milkOriginalList)
  80. e.MilkHallData(pastureId)
  81. e.UpdateRepeatCupSet1(milkOriginalList)
  82. e.UpdateMilkOriginCowInfo(milkOriginalList)
  83. e.UpdateRepeatCupSet2(milkOriginalList)
  84. }
  85. // UpdateShifts 更新班次
  86. func (e *Entry) UpdateShifts(pastureId int64, xBeg1, xBeg2, xBeg3, xBeg4 int) {
  87. milkOriginalList := make([]*model.MilkOriginal, 0)
  88. if err := e.DB.Model(new(model.MilkOriginal)).
  89. Where("pasture_id = ?", pastureId).
  90. Where("shifts = ?", 0).
  91. Find(&milkOriginalList).Error; err != nil {
  92. zaplog.Error("UpdateShifts", zap.Any("pastureId", pastureId), zap.Any("err", err))
  93. }
  94. for _, v := range milkOriginalList {
  95. subDetachTime1 := util.Substr(v.DetacherTime, 11, 2)
  96. subDetachTime2 := util.Substr(v.DetacherTime, 14, 2)
  97. subDetachTime1Int, _ := strconv.ParseInt(subDetachTime1, 10, 64)
  98. subDetachTime2Int, _ := strconv.ParseInt(subDetachTime2, 10, 64)
  99. allDetachTime := int(subDetachTime1Int*100 + subDetachTime2Int)
  100. // 更新第一班
  101. if xBeg2 > xBeg1 {
  102. if allDetachTime >= xBeg1 && allDetachTime <= xBeg2 {
  103. v.Shifts = 1
  104. }
  105. } else {
  106. if allDetachTime >= xBeg1 || allDetachTime <= xBeg2 {
  107. v.Shifts = 1
  108. }
  109. }
  110. // 更新第二班
  111. if xBeg3 > xBeg2 {
  112. if allDetachTime >= xBeg2 && allDetachTime <= xBeg3 {
  113. v.Shifts = 2
  114. }
  115. } else {
  116. if allDetachTime >= xBeg2 || allDetachTime <= xBeg3 {
  117. v.Shifts = 2
  118. }
  119. }
  120. // 更新第四班(如果有)
  121. if xBeg4 > 0 && xBeg4 != xBeg1 {
  122. if xBeg1 > xBeg4 {
  123. if allDetachTime >= xBeg4 && allDetachTime <= xBeg1 {
  124. v.Shifts = 4
  125. }
  126. } else {
  127. if allDetachTime >= xBeg4 || allDetachTime <= xBeg1 {
  128. v.Shifts = 4
  129. }
  130. }
  131. }
  132. // 如果还没有分配班次,则分配到第三班
  133. if v.Shifts == 0 {
  134. v.Shifts = 3
  135. }
  136. // 批量更新数据库
  137. if err := e.DB.Model(new(model.MilkOriginal)).
  138. Select("shifts").
  139. Where("id = ?", v.Id).
  140. Updates(v).Error; err != nil {
  141. zaplog.Error("UpdateShifts Save", zap.Any("pastureId", pastureId), zap.Any("err", err))
  142. }
  143. }
  144. }
  145. // UpdateMilkDate 更换挤奶时间
  146. func (e *Entry) UpdateMilkDate(pastureId int64, xDBeg int) {
  147. milkOriginalList := make([]*model.MilkOriginal, 0)
  148. if err := e.DB.Model(new(model.MilkOriginal)).
  149. Where("pasture_id = ?", pastureId).
  150. Where("milk_date = ?", "").
  151. Find(&milkOriginalList).Error; err != nil {
  152. zaplog.Error("UpdateMilkDate", zap.Any("pastureId", pastureId), zap.Any("err", err))
  153. return
  154. }
  155. for _, v := range milkOriginalList {
  156. // 获取结束时间,如果为空则使用默认时间
  157. var endTime time.Time
  158. if v.EndTime == "" {
  159. endTime = time.Date(1999, 12, 31, 23, 0, 0, 0, time.Local)
  160. }
  161. // 比较挤奶时间和结束时间,取较晚的时间
  162. detacherTime, _ := util.TimeParseLocal(model.LayoutTime, v.DetacherTime)
  163. latestTime := detacherTime
  164. if endTime.After(detacherTime) {
  165. latestTime = endTime
  166. }
  167. // 减去xDBeg小时并获取日期
  168. milkDate := latestTime.Add(time.Duration(-xDBeg) * time.Hour).Format(model.LayoutDate2)
  169. // 更新数据库
  170. if err := e.DB.Model(new(model.MilkOriginal)).
  171. Select("milk_date").
  172. Where("id = ?", v.Id).
  173. Update("milk_date", milkDate).Error; err != nil {
  174. zaplog.Error("UpdateMilkDate", zap.Any("err", err), zap.Any("milkDate", milkDate))
  175. }
  176. }
  177. }
  178. // DeleteRepeatMilkData 删除重复数据
  179. func (e *Entry) DeleteRepeatMilkData(pastureId int64, deleteModel *DeleteMilkOriginal, cfg *MilkClassConfig, milkOriginalList []*model.MilkOriginal) {
  180. // 获取最小日期对应的最小wid
  181. var oriWid int64
  182. if err := e.DB.Model(new(model.MilkOriginal)).
  183. Select("MIN(id)").
  184. Where("pasture_id = ?", pastureId).
  185. Where("milk_date = ?", deleteModel.XMind).
  186. Scan(&oriWid).Error; err != nil {
  187. zaplog.Error("DeleteRepeatMilkData GetOriWid", zap.Any("pastureId", pastureId), zap.Any("err", err))
  188. return
  189. }
  190. for _, v := range milkOriginalList {
  191. e.delete1(v, deleteModel.XMind, cfg)
  192. e.delete2(v, deleteModel.XMind, cfg)
  193. e.delete3(v, deleteModel.XMind, cfg)
  194. e.delete4(v, deleteModel.XMind, cfg)
  195. }
  196. }
  197. func (e *Entry) MilkHallData(pastureId int64) {
  198. milkHallList := e.FindMilkHallList(pastureId)
  199. if len(milkHallList) == 0 {
  200. return
  201. }
  202. for _, v := range milkHallList {
  203. e.UpdateRecognitionTime(pastureId, v)
  204. }
  205. }
  206. // UpdateRecognitionTime 识别时间超过40分钟未套杯牛只,识别改为未识别
  207. func (e *Entry) UpdateRecognitionTime(pastureId int64, hall *model.MilkHall) {
  208. milkOriginalList := make([]*model.MilkOriginal, 0)
  209. if err := e.DB.Model(new(model.MilkOriginal)).
  210. Where("pasture_id = ?", pastureId).
  211. Where("milk_hall_number = ?", hall.Name).
  212. Where("milk_hall_brand = ?", hall.Brand).
  213. Where("load = ?", 0).
  214. Find(&milkOriginalList).Error; err != nil {
  215. zaplog.Error("MilkHallData", zap.Any("err", err))
  216. }
  217. for _, v := range milkOriginalList {
  218. t1, _ := util.TimeParseLocal(model.LayoutTime, v.AttachTime)
  219. t2, _ := util.TimeParseLocal(model.LayoutTime, v.RecognitionTime)
  220. diff := t1.Sub(t2)
  221. minute := int(diff.Minutes())
  222. if util.Substr(v.RecognitionTime, -1, 8) != "00:00:00" && minute > 40 {
  223. if err := e.DB.Model(new(model.MilkOriginal)).
  224. Where("id = ?", v.Id).
  225. Updates(map[string]interface{}{
  226. "cow_id": 0,
  227. "ele_ear_number": "",
  228. "recognition_time": fmt.Sprintf("%s 00:00:00", util.Substr(v.RecognitionTime, 0, 10)),
  229. }).Error; err != nil {
  230. zaplog.Error("MilkHallData", zap.Any("err", err))
  231. }
  232. }
  233. }
  234. }
  235. // UpdateRepeatCupSet1 更新重复套杯1, 识别时间相同,且不为0为重复套杯
  236. func (e *Entry) UpdateRepeatCupSet1(milkOriginalList []*model.MilkOriginal) {
  237. if len(milkOriginalList) == 0 {
  238. return
  239. }
  240. milkOriginalMap := make(map[string][]*model.MilkOriginal)
  241. for _, v := range milkOriginalList {
  242. if strings.HasSuffix(v.RecognitionTime, "00:00:00") {
  243. continue
  244. }
  245. key := fmt.Sprintf("%s_%d_%d_%s", v.MilkDate, v.Shifts, v.DetacherAddress, v.RecognitionTime)
  246. milkOriginalMap[key] = append(milkOriginalMap[key], v)
  247. }
  248. for _, originalList := range milkOriginalMap {
  249. if len(originalList) >= 2 {
  250. // 按照Id升序排序(保留第一条)
  251. sort.Slice(originalList, func(i, j int) bool {
  252. return originalList[i].Id < originalList[j].Id
  253. })
  254. for i, v := range originalList {
  255. if i == 0 {
  256. continue
  257. }
  258. if err := e.DB.Model(new(model.MilkOriginal)).
  259. Select("").Where("id = ?", v.Id).
  260. Update("nattach", 2).Error; err != nil {
  261. zaplog.Error("UpdateRepeatCupSet1", zap.Any("err", err))
  262. }
  263. }
  264. }
  265. }
  266. }
  267. func (e *Entry) UpdateMilkOriginCowInfo(milkOriginalList []*model.MilkOriginal) {
  268. }
  269. // UpdateRepeatCupSet2 非标准重复套杯
  270. func (e *Entry) UpdateRepeatCupSet2(milkOriginalList []*model.MilkOriginal) {
  271. for _, v := range milkOriginalList {
  272. if v.AttachTime == "" || v.InitialTime == "" {
  273. continue
  274. }
  275. attchTime, _ := util.TimeParseLocal(model.LayoutTime, v.AttachTime)
  276. initialTime, _ := util.TimeParseLocal(model.LayoutTime, v.InitialTime)
  277. if util.Substr(v.InitialTime, -1, 5) != "00:00" && v.Nattach == 0 && attchTime.Sub(initialTime).Minutes() <= 1 {
  278. if err := e.DB.Model(new(model.MilkOriginal)).
  279. Select("nattach").
  280. Where("id = ?", v.Id).
  281. Update("nattach", 2).Error; err != nil {
  282. zaplog.Error("UpdateRepeatCupSet2", zap.Any("err", err))
  283. }
  284. }
  285. }
  286. }
  287. func (e *Entry) delete1(data *model.MilkOriginal, xMinD string, cfg *MilkClassConfig) {
  288. // 1. 删除attach_time为00:00:00的记录
  289. acctchStr := util.Substr(data.AttachTime, -1, 8)
  290. if data.MilkDate < xMinD || acctchStr != "00:00:00" {
  291. return
  292. }
  293. // 2. 检查是否存在符合条件的m2记录
  294. var count int64
  295. if err := e.DB.Model(new(model.MilkOriginal)).
  296. Where("wid BETWEEN ? AND ?", cfg.OldUpdateMaxId+1, cfg.CurrentMaxId).
  297. Where("milk_date = ?", data.MilkDate).
  298. Where("detacher_address = ?", data.DetacherAddress).
  299. Where("ABS(TIMESTAMPDIFF(SECOND, detach_time, ?)) < 10", data.DetacherTime).
  300. Where("milk_weight = ?", data.MilkWeight).
  301. Where("pasture_id = ?", data.PastureId).
  302. Where("RIGHT(attach_time, 8) != '00:00:00'").
  303. Count(&count).Error; err != nil {
  304. zaplog.Error("Delete1", zap.Any("err", err))
  305. return
  306. }
  307. if count > 0 {
  308. if err := e.DB.Model(new(model.MilkOriginal)).
  309. Where("id = ?", data.Id).
  310. Delete(data).Error; err != nil {
  311. zaplog.Error("Delete1", zap.Any("err", err), zap.Any("data", data))
  312. }
  313. }
  314. }
  315. func (e *Entry) delete2(data *model.MilkOriginal, xMinD string, cfg *MilkClassConfig) {
  316. // 1. 检查记录是否在时间范围内
  317. if data.MilkDate < xMinD {
  318. return
  319. }
  320. // 2. 检查是否存在重复记录(除第一条外)
  321. var count int64
  322. if err := e.DB.Model(new(model.MilkOriginal)).
  323. Where("id BETWEEN ? AND ?", cfg.OldUpdateMaxId+1, cfg.CurrentMaxId).
  324. Where("milk_date = ?", data.MilkDate).
  325. Where("shifts = ?", data.Shifts).
  326. Where("detacher_address = ?", data.DetacherAddress).
  327. Where("attach_time = ?", data.AttachTime).
  328. Where("milk_weight = ?", data.MilkWeight).
  329. Where("pasture_id = ?", data.PastureId).
  330. Where("id < ?", data.Id). // 只查找比当前记录更早的记录
  331. Count(&count).Error; err != nil {
  332. zaplog.Error("Delete2", zap.Any("err", err))
  333. return
  334. }
  335. // 3. 如果存在重复记录,则删除当前记录
  336. if count > 0 {
  337. if err := e.DB.Model(new(model.MilkOriginal)).
  338. Where("id = ?", data.Id).
  339. Delete(data).Error; err != nil {
  340. zaplog.Error("Delete2", zap.Any("err", err), zap.Any("data", data))
  341. }
  342. }
  343. }
  344. func (e *Entry) delete3(data *model.MilkOriginal, xMinD string, cfg *MilkClassConfig) {
  345. // 1. 检查记录是否在时间范围内
  346. if data.MilkDate < xMinD {
  347. return
  348. }
  349. // 2. 检查是否为班次开始且无奶量记录
  350. var isFirstInShift bool
  351. if err := e.DB.Raw(`
  352. SELECT 1 FROM (
  353. SELECT m.id, m.milk_date, m.shifts, m.milk_weight,
  354. @tot := IF(@tot + m.milk_weight > 100, 100,
  355. IF(m.shifts = @shifts, @tot, 0) + m.milk_weight) m_tot,
  356. @shifts := m.shifts
  357. FROM milk_original m, (SELECT @tot := 0, @shifts := 0) vars
  358. WHERE m.id BETWEEN ? AND ?
  359. AND m.milk_date >= ?
  360. AND m.pasture_id = ?
  361. ORDER BY m.milk_date, m.shifts, m.attach_time
  362. ) t
  363. WHERE t.id = ? AND t.m_tot = 0`,
  364. cfg.OldUpdateMaxId+1, cfg.CurrentMaxId, xMinD, data.PastureId, data.Id).
  365. Scan(&isFirstInShift).Error; err != nil {
  366. zaplog.Error("Delete3", zap.Any("err", err))
  367. return
  368. }
  369. // 3. 如果是班次开始且无奶量记录,则删除
  370. if isFirstInShift {
  371. if err := e.DB.Model(new(model.MilkOriginal)).
  372. Where("id = ?", data.Id).
  373. Delete(data).Error; err != nil {
  374. zaplog.Error("Delete3", zap.Any("err", err), zap.Any("data", data))
  375. }
  376. }
  377. }
  378. func (e *Entry) delete4(data *model.MilkOriginal, xMinD string, cfg *MilkClassConfig) {
  379. // 1. 检查记录是否在时间范围内
  380. if data.MilkDate < "2020-10-01" {
  381. return
  382. }
  383. // 2. 检查是否为时间异常记录
  384. var isAbnormal bool
  385. if err := e.DB.Model(new(model.MilkOriginal)).
  386. Where("id = ?", data.Id).
  387. Where("milk_date >= ?", "2020-10-01").
  388. Where("recognition_time > detacher_time").
  389. Where("attach_time > detacher_time").
  390. Where("SUBSTRING(attach_time, 12, 2) = ?", "23").
  391. Where("pasture_id = ?", data.PastureId).
  392. Select("1").
  393. Scan(&isAbnormal).Error; err != nil {
  394. zaplog.Error("Delete4", zap.Any("err", err))
  395. return
  396. }
  397. // 3. 如果是时间异常记录,则删除
  398. if isAbnormal {
  399. if err := e.DB.Model(new(model.MilkOriginal)).
  400. Where("id = ?", data.Id).
  401. Delete(data).Error; err != nil {
  402. zaplog.Error("Delete4", zap.Any("err", err), zap.Any("data", data))
  403. }
  404. }
  405. }
  406. func parseXBeg(cfg *MilkClassConfig) (xBeg, xBeg1, xBeg2, xBeg3, xBeg4 int) {
  407. xBeg1Parts := strings.Split(cfg.FirstClassMilkTime, ":")
  408. if len(xBeg1Parts) < 2 {
  409. return
  410. }
  411. // 提取最后一部分
  412. xBeg1LastPart, _ := strconv.Atoi(xBeg1Parts[len(xBeg1Parts)-1])
  413. xBeg, _ = strconv.Atoi(xBeg1Parts[0])
  414. xBeg1, _ = strconv.Atoi(xBeg1Parts[1])
  415. xBeg1 = xBeg1*100 + xBeg1LastPart
  416. xBeg2Parts := strings.Split(cfg.SecondClassMilkTime, ":")
  417. if len(xBeg2Parts) < 2 {
  418. return
  419. }
  420. xBeg2LastPart, _ := strconv.Atoi(xBeg2Parts[len(xBeg2Parts)-1])
  421. xBeg2, _ = strconv.Atoi(xBeg2Parts[0])
  422. xBeg2 = xBeg2*100 + xBeg2LastPart
  423. xBeg3Parts := strings.Split(cfg.ThirdClassMilkTime, ":")
  424. if len(xBeg3Parts) < 2 {
  425. return
  426. }
  427. xBeg3LastPart, _ := strconv.Atoi(xBeg3Parts[len(xBeg3Parts)-1])
  428. xBeg3, _ = strconv.Atoi(xBeg3Parts[0])
  429. xBeg3 = xBeg3*100 + xBeg3LastPart
  430. xBeg4Parts := strings.Split(cfg.FourthClassMilkTime, ":")
  431. if len(xBeg4Parts) < 2 {
  432. return
  433. }
  434. xBeg4LastPart, _ := strconv.Atoi(xBeg4Parts[len(xBeg4Parts)-1])
  435. xBeg4, _ = strconv.Atoi(xBeg4Parts[0])
  436. xBeg4 = xBeg4*100 + xBeg4LastPart
  437. return
  438. }