milk_original.go 14 KB

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