neck_ring_estrus.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package crontab
  2. import (
  3. "kpt-pasture/model"
  4. "time"
  5. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  6. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  7. "go.uber.org/zap"
  8. "gitee.com/xuyiping_admin/pkg/xerr"
  9. )
  10. const (
  11. MaxRuminaAdJust = 20
  12. XAdjust21 = 15
  13. XAdjust42 = 10
  14. RumtoHeat = 0.5
  15. MinCalvingAge = 20
  16. MinLact = 0
  17. NormalChangJust = 10
  18. )
  19. func (e *Entry) EntryCowEstrus() (err error) {
  20. activeLowValue := e.GetSystemConfigure(model.ActiveLow).Value
  21. activeMiddleValue := e.GetSystemConfigure(model.ActiveMiddle).Value
  22. activeHighValue := e.GetSystemConfigure(model.ActiveHigh).Value
  23. lastMaxEstrusId := e.GetSystemConfigure(model.MaxEstrus).Value
  24. currentMaxHabit := &model.NeckActiveHabit{}
  25. if err = e.DB.Model(new(model.NeckActiveHabit)).
  26. Order("id desc").
  27. First(currentMaxHabit).Error; err != nil {
  28. return xerr.WithStack(err)
  29. }
  30. defer func() {
  31. if err == nil {
  32. e.DB.Model(new(model.SystemConfigure)).
  33. Where("name = ?", model.MaxEstrus).
  34. Update("value", currentMaxHabit.Id)
  35. }
  36. }()
  37. xToday := &XToday{}
  38. if err = e.DB.Model(new(model.NeckActiveHabit)).
  39. Select(`MIN(h.heat_date) as x_beg_date, MAX(h.heat_date) as x_end_date`).
  40. Where("id BETWEEN ? AND ?", lastMaxEstrusId, currentMaxHabit.Id).
  41. First(xToday).Error; err != nil {
  42. return xerr.WithStack(err)
  43. }
  44. // 当前Id<=上次执行的id,则不执行
  45. if currentMaxHabit.Id <= int64(lastMaxEstrusId) {
  46. return nil
  47. }
  48. xToday.LastMaxHabitId = int64(lastMaxEstrusId)
  49. xToday.CurrMaxHabitId = currentMaxHabit.Id
  50. xToday.ActiveLow = int64(activeLowValue)
  51. xToday.ActiveMiddle = int64(activeMiddleValue)
  52. xToday.ActiveHigh = int64(activeHighValue)
  53. if err = e.CowEstrusWarning(xToday); err != nil {
  54. return xerr.WithStack(err)
  55. }
  56. return nil
  57. }
  58. func (e *Entry) CowEstrusWarning(xToday *XToday) error {
  59. startDate, err := time.Parse(model.LayoutDate2, xToday.XBegDate)
  60. if err != nil {
  61. return xerr.WithStack(err)
  62. }
  63. endDate, err := time.Parse(model.LayoutDate2, xToday.XEndDate)
  64. if err != nil {
  65. return xerr.WithStack(err)
  66. }
  67. for startDate.Format(model.LayoutDate2) <= endDate.Format(model.LayoutDate2) {
  68. neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  69. if err = e.DB.Model(new(model.NeckActiveHabit)).
  70. Select("*,MAX(filter_high) as filter_high").
  71. Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
  72. Where("heat_date = ?", startDate.Format(model.LayoutDate2)).
  73. Where("cow_id > ?", 0).
  74. Where(e.DB.Where("calving_age > ?", MinCalvingAge).Or("lact = ?", MinLact)).
  75. Group("cow_id").
  76. Find(&neckActiveHabitList).
  77. Error; err != nil {
  78. return xerr.WithStack(err)
  79. }
  80. eventEstrusList := make([]*model.EventEstrus, 0)
  81. for _, v := range neckActiveHabitList {
  82. if ok := e.IsAdJustLow(xToday, v); ok {
  83. continue
  84. }
  85. cft := float32(0)
  86. if v.ChangeAdjust > 10 {
  87. cft = float32(v.ChangeFilter) - float32(v.ChangeAdjust) + 3
  88. } else {
  89. value := float32(0)
  90. switch {
  91. case v.RuminaFilter > MaxRuminaAdJust:
  92. value = float32(5)
  93. case v.RuminaFilter > 0:
  94. value = float32(v.RuminaFilter) * 0.25
  95. case v.RuminaFilter < -MaxRuminaAdJust:
  96. value = -MaxRuminaAdJust * RumtoHeat
  97. default:
  98. value = float32(v.RuminaFilter) * RumtoHeat
  99. }
  100. cft = float32(v.ChangeFilter)*float32(v.FilterCorrect)/100 - value
  101. }
  102. // 最近3天最大发情记录,小于该变化趋势的不再插入
  103. eventEstrus := e.GetBeforeThreeDaysCowEstrus(v.CowId, startDate.AddDate(0, 0, -2).Format(model.LayoutTime))
  104. if eventEstrus.CowId != v.CowId {
  105. if int32(cft) <= eventEstrus.PerTwentyFourHigh {
  106. continue
  107. }
  108. }
  109. // 判断最近50天内是否存在发情记录(发情等级>=2),如果18~25天@xadjust21,如果36~50天@xadjust42
  110. cowEstrus := e.GetTwoEstrus(v.CowId, startDate.AddDate(0, 0, -100).Format(model.LayoutTime), startDate.AddDate(0, 0, -2).Format(model.LayoutTime))
  111. if cowEstrus.CowId == v.CowId {
  112. activeDateTime, _ := time.Parse(model.LayoutTime, cowEstrus.ActiveDate)
  113. if activeDateTime.Unix() >= startDate.AddDate(0, 0, -25).Unix() && activeDateTime.Unix() <= startDate.AddDate(0, 0, -18).Unix() {
  114. cowEstrus.HadJust = XAdjust21
  115. }
  116. if activeDateTime.Unix() >= startDate.AddDate(0, 0, -50).Unix() && activeDateTime.Unix() <= startDate.AddDate(0, 0, -36).Unix() {
  117. cowEstrus.HadJust = XAdjust42
  118. }
  119. }
  120. if int32(cft)+cowEstrus.HadJust <= int32(xToday.ActiveLow) {
  121. continue
  122. }
  123. cowInfo, err := e.GetCowById(v.CowId)
  124. if err != nil {
  125. zaplog.Error("CowEstrusWarning", zap.Any("GetCowById", err), zap.Any("cowId", v.CowId))
  126. continue
  127. }
  128. level := pasturePb.EstrusLevel_High
  129. if int32(cft)+cowEstrus.HadJust < int32(xToday.ActiveMiddle) {
  130. level = pasturePb.EstrusLevel_Low
  131. }
  132. if int32(cft)+cowEstrus.HadJust >= int32(xToday.ActiveHigh) {
  133. level = pasturePb.EstrusLevel_Middle
  134. }
  135. result := pasturePb.EstrusResult_Invalid
  136. if eventEstrus.Result == pasturePb.EstrusResult_Fail && eventEstrus.PerTwentyFourHigh > int32(cft)+cowEstrus.HadJust {
  137. result = pasturePb.EstrusResult_Fail
  138. }
  139. // todo 待定
  140. if result == pasturePb.EstrusResult_Invalid {
  141. result = pasturePb.EstrusResult_Correct
  142. }
  143. isShow := pasturePb.IsShow_Ok
  144. if cowInfo.IsPregnant == pasturePb.IsShow_Ok {
  145. isShow = pasturePb.IsShow_No
  146. }
  147. eventEstrusList = append(eventEstrusList, &model.EventEstrus{
  148. CowId: v.CowId,
  149. Lact: cowInfo.Lact,
  150. ExposeEstrusType: pasturePb.ExposeEstrusType_Natural_Estrus,
  151. FilterHigh: v.FilterHigh,
  152. EstrusDate: v.ActiveTime,
  153. ActiveDate: v.ActiveTime,
  154. LastEstrusDate: cowEstrus.ActiveDate,
  155. Level: level,
  156. IsPeak: pasturePb.IsShow_No,
  157. PerTwentyFourHigh: int32(cft) + cowEstrus.HadJust,
  158. Result: result,
  159. IsShow: isShow,
  160. })
  161. }
  162. if len(eventEstrusList) > 0 {
  163. if err = e.DB.Create(eventEstrusList).Error; err != nil {
  164. zaplog.Error("CowEstrusWarning", zap.Any("eventEstrusList", eventEstrusList), zap.Any("err", err))
  165. }
  166. }
  167. startDate.AddDate(0, 0, 1)
  168. }
  169. return nil
  170. }
  171. // IsAdJustLow 是否低于最低活动量
  172. func (e *Entry) IsAdJustLow(xToday *XToday, habit *model.NeckActiveHabit) bool {
  173. ruminaAdJust := float64(0)
  174. switch {
  175. case habit.RuminaFilter > MaxRuminaAdJust:
  176. ruminaAdJust = 5
  177. case habit.RuminaFilter > 0:
  178. ruminaAdJust = float64(habit.RuminaFilter) * 0.25
  179. case habit.RuminaFilter < -MaxRuminaAdJust:
  180. ruminaAdJust = -MaxRuminaAdJust * RumtoHeat
  181. default:
  182. ruminaAdJust = float64(habit.RuminaFilter) * RumtoHeat
  183. }
  184. ruminaAdJustSum := int32(float64(habit.FilterCorrect)/100 - ruminaAdJust)
  185. isContinue := int32(0)
  186. activeLow := xToday.ActiveLow - XAdjust21
  187. if habit.ChangeFilter >= NormalChangJust {
  188. isContinue = habit.ChangeFilter - habit.ChangeAdjust + 3*ruminaAdJustSum
  189. } else {
  190. isContinue = habit.ChangeFilter * ruminaAdJustSum
  191. }
  192. if isContinue < int32(activeLow) {
  193. return true
  194. }
  195. return false
  196. }