Prechádzať zdrojové kódy

event: 批量断奶

Yi 4 mesiacov pred
rodič
commit
dc0ea957bd

+ 6 - 3
README.md

@@ -38,7 +38,10 @@ todo列表:
 - [ ] 后备牛到达主动停配期后的牛只放在哪个模块(配种清单,发情清单)
 - [ ] 发情清单和配种清单更新机制
 - [ ] 前后端部署架构【k8s,docker-compose,docker-swarm】namespace隔离,需要考虑的问题【1.一次性任务,2. 定时任务 3. 数据收集,4. 日志收集 5. 报警介入】
-- [ ] 所有事件录入梳理【批量录入,excel导入,信息人员与操作人员统一规范】
+- [x] 所有事件录入梳理【批量录入,excel导入,信息人员与操作人员统一规范】
 - [ ] 药品优化成药品名称关联生产商
-- [ ] 框架logrus日志优化【未按照指定天数的日志自动删除,待验证】
-- [ ] 犊牛的牛只品种是根据母牛的品种来确定,还是根据公牛来确定?【目前是根据母牛品种来确定】
+- [x] 框架logrus日志优化【未按照指定天数的日志自动删除,待验证】
+- [ ] 犊牛的牛只品种是根据母牛的品种来确定,还是根据公牛来确定?【目前是根据母牛品种来确定】
+
+脖环发情算法梳理:
+- [ ] 处理异常上报数据(frameid > 12)

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20241118130425-0268b6791546
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20241121031639-c1bda72e25b5
 	gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/eclipse/paho.mqtt.golang v1.4.3

+ 4 - 0
go.sum

@@ -38,6 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241118130425-0268b6791546 h1:j6ocvgNQljRKDLvXYoAJKBTqONRedAqvZSJNdzfFrMI=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241118130425-0268b6791546/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241121031639-c1bda72e25b5 h1:8UyjUjPax9gkjWtFnpaA1pzM3Dz9cu6Y4CzoAt9791U=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241121031639-c1bda72e25b5/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b h1:w05MxH7yqveRlaRbxHhbif5YjPrJFodRPfOjYhXn7Zk=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b/go.mod h1:8tF25X6pE9WkFCczlNAC0K2mrjwKvhhp02I7o0HtDxY=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -172,6 +174,7 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
 github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
@@ -609,6 +612,7 @@ go.uber.org/dig v1.15.0/go.mod h1:pKHs0wMynzL6brANhB2hLMro+zalv1osARTviTcqHLM=
 go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
 go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
+go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=

+ 35 - 0
http/handler/event/event_breed.go

@@ -331,3 +331,38 @@ func AbortionList(c *gin.Context) {
 	}
 	ginutil.JSONResp(c, res)
 }
+
+func WeaningCreateBatch(c *gin.Context) {
+	var req pasturePb.EventWeaningBatchRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(req.WeaningAt, valid.Required),
+		valid.Field(req.OperationId, valid.Required),
+		valid.Field(req.PenId, valid.Required),
+		valid.Field(&req.Item, valid.Required, valid.Each(valid.By(func(value interface{}) error {
+			item := value.(pasturePb.WeaningBatch)
+			return valid.ValidateStruct(&item,
+				valid.Field(&item.CowId, valid.Required),
+				valid.Field(&item.Weight, valid.Required),
+			)
+		}))),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.WeaningBatch(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}

+ 3 - 0
http/route/event_api.go

@@ -48,6 +48,9 @@ func EventAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		eventRoute.POST("/abortion/list", event.AbortionList)
 		eventRoute.POST("/abortion/create/batch", event.AbortionCreateBatch)
 
+		// 断奶
+		eventRoute.POST("/weaning/create/batch", event.WeaningCreateBatch)
+
 		// 发病
 		eventRoute.POST("/disease/create", event.CowDiseaseCreate)
 		eventRoute.POST("/disease/list", event.CowDiseaseList)

+ 0 - 1
model/event_weaning.go

@@ -16,7 +16,6 @@ type EventWeaning struct {
 	Status        pasturePb.IsShow_Kind `json:"status"`
 	BeforePenId   int32                 `json:"beforePenId"`
 	AfterPenId    int32                 `json:"afterPenId"`
-	RealityDayAge int32                 `json:"realityDayAge"`
 	Remarks       string                `json:"remarks"`
 	OperationId   int32                 `json:"operationId"`
 	OperationName string                `json:"operationName"`

+ 62 - 0
module/backend/event_breed.go

@@ -493,3 +493,65 @@ func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMatin
 
 	return nil
 }
+
+func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeaningBatchRequest) error {
+	if len(req.Item) <= 0 {
+		return nil
+	}
+	cowIds := make([]int64, 0)
+	cowWeightMap := make(map[int64]float64)
+	for _, item := range req.Item {
+		cowIds = append(cowIds, int64(item.CowId))
+		cowWeightMap[int64(item.CowId)] = float64(item.Weight)
+	}
+
+	eventWeaningList := make([]*model.EventWeaning, 0)
+
+	if err := s.DB.Model(new(model.EventWeaning)).
+		Where("cow_id IN ?", cowIds).
+		Where("status = ?", pasturePb.IsShow_No).
+		Find(&eventWeaningList).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	operation, err := s.GetSystemUserById(ctx, int64(req.OperationId))
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	currentUser, err := s.GetCurrentSystemUser(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		for _, v := range eventWeaningList {
+			if err = tx.Model(new(model.EventWeaning)).Where("id = ?", v.Id).Updates(map[string]interface{}{
+				"status":         pasturePb.IsShow_Ok,
+				"reality_day":    int64(req.WeaningAt),
+				"operation_id":   req.OperationId,
+				"operation_name": operation.Name,
+				"message_id":     currentUser.Id,
+				"message_name":   currentUser.Name,
+				"remarks":        req.Remarks,
+				"after_pen_id":   req.PenId,
+			}).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+			if err = tx.Model(new(model.Cow)).Where("id = ?", v.CowId).Updates(map[string]interface{}{
+				"pen_id":         req.PenId,
+				"current_weight": cowWeightMap[v.CowId],
+				"weaning_at":     req.WeaningAt,
+				"last_weight_at": req.WeaningAt,
+			}).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+		}
+
+		return nil
+	}); err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}

+ 2 - 0
module/backend/interface.go

@@ -173,6 +173,8 @@ type EventService interface {
 	AbortionList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EventAbortionResponse, error)
 	AbortionCreate(ctx context.Context, req *pasturePb.EventAbortionRequest) error
 	AbortionCreateBatch(ctx context.Context, req *pasturePb.EventAbortionBatch) error
+	// WeaningBatch 断奶
+	WeaningBatch(ctx context.Context, req *pasturePb.EventWeaningBatchRequest) error
 	// SameTimeCreate 同期
 	SameTimeCreate(ctx context.Context, req *pasturePb.EventSameTime) error
 	SameTimeList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchSameTimeResponse, error)