Преглед изворни кода

outbound: 出库单编辑和删除

Yi пре 3 месеци
родитељ
комит
6431f3a48d

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20241218092251-fc63330bc909
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20241219080808-6a83c815206e
 	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

@@ -64,6 +64,10 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20241218075304-cbb87679a2f1/go.mod h1:B
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241218075333-5e665935b341/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241218092251-fc63330bc909 h1:vxUvJnVW0fMgbWwLBTHLU0cNYyl3nBm/8RO86TmulIs=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241218092251-fc63330bc909/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241219074512-9ad3e0b600fb h1:2Acmom7XCrhgocmXewDMqNSrQtTUgq/aNsW6uyUEzkw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241219074512-9ad3e0b600fb/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241219080808-6a83c815206e h1:lSDWnqRTfBokXgiH6bGdnDwFFfewIp1fbgpkA8iadDY=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241219080808-6a83c815206e/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=

+ 20 - 0
http/handler/goods/outbound.go

@@ -105,6 +105,26 @@ func OutboundDetail(c *gin.Context) {
 	ginutil.JSONResp(c, res)
 }
 
+func OutboundDelete(c *gin.Context) {
+	idStr := c.Param("id")
+	id, _ := strconv.ParseInt(idStr, 10, 64)
+	if err := valid.Validate(id, valid.Required); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.OutboundDelete(c, id); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
+
 func FrozenSemeList(c *gin.Context) {
 	var req pasturePb.FrozenSemenRequest
 	if err := ginutil.BindProto(c, &req); err != nil {

+ 1 - 0
http/route/goods_api.go

@@ -28,6 +28,7 @@ func GoodsManageAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		goodsRoute.POST("/outbound/audit", goods.OutboundAudit)
 		goodsRoute.POST("/outbound/cancel", goods.OutboundAudit)
 		goodsRoute.GET("/outbound/detail/:id", goods.OutboundDetail)
+		goodsRoute.DELETE("/outbound/:id", goods.OutboundDelete)
 
 		// 冻精
 		goodsRoute.POST("/frozen/seme/list", goods.FrozenSemeList)

+ 31 - 23
model/event_cow_log.go

@@ -2,6 +2,7 @@ package model
 
 import (
 	"fmt"
+	"time"
 
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 )
@@ -9,23 +10,23 @@ import (
 const ShardTableNumber = 6
 
 type EventCowLog struct {
-	Id               int64                  `json:"id"`
-	CowId            int64                  `json:"cowId"`
-	DayAge           int32                  `json:"dayAge"`
-	Lact             int32                  `json:"lact"`
-	PenId            int32                  `json:"penId"`
-	PenName          string                 `json:"penName"`
-	CowType          pasturePb.CowType_Kind `json:"cowType"`
-	CowTypeName      string                 `json:"cowTypeName"`
-	EventType        int64                  `json:"eventType"`
-	EventTypeName    string                 `json:"eventTypeName"`
-	EventDescription string                 `json:"eventDescription"`
-	OperationId      int64                  `json:"operationId"`
-	OperationName    string                 `json:"operationName"`
-	EventAt          string                 `json:"eventAt"`
-	Remarks          string                 `json:"remarks"`
-	CreatedAt        int64                  `json:"createdAt"`
-	UpdatedAt        int64                  `json:"updatedAt"`
+	Id               int64                    `json:"id"`
+	CowId            int64                    `json:"cowId"`
+	DayAge           int32                    `json:"dayAge"`
+	Lact             int32                    `json:"lact"`
+	PenId            int32                    `json:"penId"`
+	PenName          string                   `json:"penName"`
+	CowType          pasturePb.CowType_Kind   `json:"cowType"`
+	CowTypeName      string                   `json:"cowTypeName"`
+	EventType        pasturePb.EventType_Kind `json:"eventType"`
+	EventTypeName    string                   `json:"eventTypeName"`
+	EventDescription string                   `json:"eventDescription"`
+	OperationId      int64                    `json:"operationId"`
+	OperationName    string                   `json:"operationName"`
+	EventAt          int64                    `json:"eventAt"`
+	Remarks          string                   `json:"remarks"`
+	CreatedAt        int64                    `json:"createdAt"`
+	UpdatedAt        int64                    `json:"updatedAt"`
 }
 
 func (e *EventCowLog) UnShardTableName() string {
@@ -37,7 +38,15 @@ func (e *EventCowLog) TableName() string {
 	return fmt.Sprintf("%s_%04d", e.UnShardTableName(), e.CowId%ShardTableNumber)
 }
 
-func NewCowEventLog(cow *Cow, penMap map[int32]*Pen, cowType map[pasturePb.CowType_Kind]string, operation *SystemUser) *EventCowLog {
+func NewCowEventLog(
+	cow *Cow,
+	penMap map[int32]*Pen,
+	cowType map[pasturePb.CowType_Kind]string,
+	eventType pasturePb.EventType_Kind,
+	eventTypeMap map[pasturePb.EventType_Kind]string,
+	operation *SystemUser,
+	description string,
+) *EventCowLog {
 	penName := ""
 	if pen, ok := penMap[cow.PenId]; ok {
 		penName = pen.Name
@@ -50,12 +59,11 @@ func NewCowEventLog(cow *Cow, penMap map[int32]*Pen, cowType map[pasturePb.CowTy
 		PenName:          penName,
 		CowType:          cow.CowType,
 		CowTypeName:      cowType[cow.CowType],
-		EventType:        0,
-		EventTypeName:    "",
-		EventDescription: "",
+		EventType:        eventType,
+		EventTypeName:    eventTypeMap[eventType],
+		EventDescription: description,
 		OperationId:      operation.Id,
 		OperationName:    operation.Name,
-		EventAt:          "",
-		Remarks:          "",
+		EventAt:          time.Now().Unix(),
 	}
 }

+ 4 - 0
model/outbound.go

@@ -29,6 +29,10 @@ func (o *Outbound) TableName() string {
 	return "outbound"
 }
 
+func (o *Outbound) Delete() {
+	o.AuditStatus = pasturePb.AuditStatus_Delete
+}
+
 func NewOutbound(req *pasturePb.OutboundApplyItem, currentUser *SystemUser) *Outbound {
 	return &Outbound{
 		Number:           fmt.Sprintf("%s%s", util.GenerateRandomNumberString(8), time.Now().Format(LayoutDate)),

+ 67 - 0
model/outbound_detail.go

@@ -0,0 +1,67 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type OutboundDetail struct {
+	Id          int64                 `json:"id"`
+	OutboundId  int64                 `json:"outboundId"`
+	GoodsId     int64                 `json:"goodsId"`
+	GoodsName   string                `json:"goodsName"`
+	Specs       string                `json:"specs"`
+	Producer    string                `json:"producer"`
+	BatchNumber string                `json:"batchNumber"`
+	Price       int32                 `json:"price"`
+	Unit        pasturePb.Unit_Kind   `json:"unit"`
+	UnitName    string                `json:"unitName"`
+	Quantity    int32                 `json:"quantity"`
+	IsDelete    pasturePb.IsShow_Kind `json:"isDelete"`
+	CreatedAt   int64                 `json:"createdAt"`
+	UpdatedAt   int64                 `json:"updatedAt"`
+}
+
+func (o *OutboundDetail) TableName() string {
+	return "outbound_detail"
+}
+
+func NewOutboundDetailList(outboundId int64, req []*pasturePb.OutboundApplyGoodsItem, unitMap map[pasturePb.Unit_Kind]string) []*OutboundDetail {
+	res := make([]*OutboundDetail, 0)
+	for _, v := range req {
+		unitName := ""
+		if unit, ok := unitMap[v.Unit]; ok {
+			unitName = unit
+		}
+		res = append(res, &OutboundDetail{
+			OutboundId:  outboundId,
+			GoodsId:     int64(v.GoodsId),
+			GoodsName:   v.GoodsName,
+			Specs:       v.Specs,
+			Producer:    v.Producer,
+			BatchNumber: v.BatchNumber,
+			Price:       int32(v.Price * 100),
+			Unit:        v.Unit,
+			UnitName:    unitName,
+			Quantity:    int32(v.Quantity),
+			IsDelete:    pasturePb.IsShow_Ok,
+		})
+	}
+	return res
+}
+
+type OutboundDetailSlice []*OutboundDetail
+
+func (o OutboundDetailSlice) ToPB() []*pasturePb.OutboundApplyGoodsItem {
+	res := make([]*pasturePb.OutboundApplyGoodsItem, len(o))
+	for i, v := range o {
+		res[i] = &pasturePb.OutboundApplyGoodsItem{
+			GoodsId:     int32(v.GoodsId),
+			GoodsName:   v.GoodsName,
+			Specs:       v.Specs,
+			Producer:    v.Producer,
+			BatchNumber: v.BatchNumber,
+			Price:       float32(v.Price) / 100,
+			Unit:        v.Unit,
+			Quantity:    uint32(v.Quantity),
+		}
+	}
+	return res
+}

+ 0 - 65
model/outbound_log.go

@@ -1,65 +0,0 @@
-package model
-
-import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
-
-type OutboundLog struct {
-	Id          int64               `json:"id"`
-	OutboundId  int64               `json:"outboundId"`
-	GoodsId     int64               `json:"goodsId"`
-	GoodsName   string              `json:"goodsName"`
-	Specs       string              `json:"specs"`
-	Producer    string              `json:"producer"`
-	BatchNumber string              `json:"batchNumber"`
-	Price       int32               `json:"price"`
-	Unit        pasturePb.Unit_Kind `json:"unit"`
-	UnitName    string              `json:"unitName"`
-	Quantity    int32               `json:"quantity"`
-	CreatedAt   int64               `json:"createdAt"`
-	UpdatedAt   int64               `json:"updatedAt"`
-}
-
-func (o *OutboundLog) TableName() string {
-	return "outbound_log"
-}
-
-func NewOutboundLogList(outboundId int64, req []*pasturePb.OutboundApplyGoodsItem, unitMap map[pasturePb.Unit_Kind]string) []*OutboundLog {
-	res := make([]*OutboundLog, 0)
-	for _, v := range req {
-		unitName := ""
-		if unit, ok := unitMap[v.Unit]; ok {
-			unitName = unit
-		}
-		res = append(res, &OutboundLog{
-			OutboundId:  outboundId,
-			GoodsId:     int64(v.GoodsId),
-			GoodsName:   v.GoodsName,
-			Specs:       v.Specs,
-			Producer:    v.Producer,
-			BatchNumber: v.BatchNumber,
-			Price:       int32(v.Price * 100),
-			Unit:        v.Unit,
-			UnitName:    unitName,
-			Quantity:    int32(v.Quantity),
-		})
-	}
-	return res
-}
-
-type OutboundLogSlice []*OutboundLog
-
-func (o OutboundLogSlice) ToPB() []*pasturePb.OutboundApplyGoodsItem {
-	res := make([]*pasturePb.OutboundApplyGoodsItem, len(o))
-	for i, v := range o {
-		res[i] = &pasturePb.OutboundApplyGoodsItem{
-			GoodsId:     int32(v.GoodsId),
-			GoodsName:   v.GoodsName,
-			Specs:       v.Specs,
-			Producer:    v.Producer,
-			BatchNumber: v.BatchNumber,
-			Price:       float32(v.Price) / 100,
-			Unit:        v.Unit,
-			Quantity:    uint32(v.Quantity),
-		}
-	}
-	return res
-}

+ 46 - 0
module/backend/config_data_other.go

@@ -374,6 +374,10 @@ func (s *StoreEntry) AuditStatusEnumList(isAll string) []*pasturePb.ConfigOption
 		Value:    int32(pasturePb.AuditStatus_Cancel),
 		Label:    "已取消",
 		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.AuditStatus_Delete),
+		Label:    "已删除",
+		Disabled: true,
 	})
 	return configOptions
 }
@@ -433,3 +437,45 @@ func (s *StoreEntry) UnMatingReasonsEnumList(isAll string) []*pasturePb.ConfigOp
 	})
 	return configOptions
 }
+
+func (s *StoreEntry) EventTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(0),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Enter),
+		Label:    "入场",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Transfer_Ben),
+		Label:    "转栏",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Body_Score),
+		Label:    "体况评分",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Pregnancy_Check),
+		Label:    "孕检",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Estrus),
+		Label:    "发情",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Seme_Time),
+		Label:    "同情",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Mating),
+		Label:    "配种",
+		Disabled: true,
+	})
+	return configOptions
+}

+ 72 - 10
module/backend/goods.go

@@ -261,6 +261,23 @@ func (s *StoreEntry) OutboundApply(ctx context.Context, req *pasturePb.OutboundA
 	if len(req.Goods) <= 0 {
 		return xerr.Custom("请选择要出库商品")
 	}
+	var outbound *model.Outbound
+	if req.Id > 0 {
+		outbound, err = s.GetOutboundById(ctx, int64(req.Id))
+		if err != nil || outbound == nil || outbound.Id <= 0 {
+			return xerr.Customf("该出库单不存在")
+		}
+		if currentUser.Id != int64(outbound.ApplicantId) {
+			return xerr.Custom("非申请人,无权修改该出库单")
+		}
+
+		if outbound.AuditStatus != pasturePb.AuditStatus_Pending {
+			return xerr.Custom("该出库单不能修改")
+		}
+	} else {
+		// 创建出库申请
+		outbound = model.NewOutbound(req, currentUser)
+	}
 	goodsItems := make([]*pasturePb.OutboundApplyGoodsItem, 0)
 	switch req.OutType {
 	case pasturePb.OutType_Drugs:
@@ -321,13 +338,26 @@ func (s *StoreEntry) OutboundApply(ctx context.Context, req *pasturePb.OutboundA
 		return xerr.Custom("未知的出库类型")
 	}
 	unitMap := s.UnitMap()
+
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		// 创建出库申请
-		outbound := model.NewOutbound(req, currentUser)
-		if err = tx.Create(outbound).Error; err != nil {
-			return xerr.WithStack(err)
+		if req.Id > 0 {
+			if err = tx.Model(new(model.Outbound)).
+				Where("id = ?", req.Id).
+				Update("applicant_remarks", req.ApplicantRemarks).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+			if err = tx.Model(new(model.OutboundDetail)).
+				Where("outbound_id = ?", req.Id).
+				Update("is_delete = ?", pasturePb.IsShow_No).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+		} else {
+			if err = tx.Create(outbound).Error; err != nil {
+				return xerr.WithStack(err)
+			}
 		}
-		outboundLog := model.NewOutboundLogList(outbound.Id, goodsItems, unitMap)
+		outboundLog := model.NewOutboundDetailList(outbound.Id, goodsItems, unitMap)
 		if err = tx.Create(outboundLog).Error; err != nil {
 			return xerr.WithStack(err)
 		}
@@ -415,12 +445,12 @@ func (s *StoreEntry) OutboundAudit(ctx context.Context, req *pasturePb.OutboundA
 		return xerr.Custom("登录人信息失效")
 	}
 
-	outboundLogs, err := s.GetOutboundLogsByOutboundId(ctx, outbound.Id)
+	outboundDetails, err := s.GetOutboundDetailByOutboundId(ctx, outbound.Id)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
 
-	if len(outboundLogs) <= 0 {
+	if len(outboundDetails) <= 0 {
 		return xerr.Custom("出库单商品不存在")
 	}
 
@@ -451,7 +481,7 @@ func (s *StoreEntry) OutboundAudit(ctx context.Context, req *pasturePb.OutboundA
 			return nil
 		}
 
-		for _, v := range outboundLogs {
+		for _, v := range outboundDetails {
 			if err = tx.Table(tableName).
 				Where("id = ?", v.GoodsId).
 				Updates(map[string]interface{}{
@@ -473,7 +503,7 @@ func (s *StoreEntry) OutboundDetail(ctx context.Context, id int64) (*pasturePb.O
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
-	outboundLogs, err := s.GetOutboundLogsByOutboundId(ctx, id)
+	outboundLogs, err := s.GetOutboundDetailByOutboundId(ctx, id)
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
@@ -504,13 +534,45 @@ func (s *StoreEntry) OutboundDetail(ctx context.Context, id int64) (*pasturePb.O
 			ExamineAtFormat:   examineAtFormat,
 			GoodsItem: &pasturePb.OutboundApplyItem{
 				OutType:          outbound.OutType,
-				Goods:            model.OutboundLogSlice(outboundLogs).ToPB(),
+				Goods:            model.OutboundDetailSlice(outboundLogs).ToPB(),
 				ApplicantRemarks: outbound.ApplicantRemarks,
 			},
 		},
 	}, nil
 }
 
+func (s *StoreEntry) OutboundDelete(ctx context.Context, id int64) error {
+	outbound, err := s.GetOutboundById(ctx, id)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if outbound == nil {
+		return xerr.Custom("出库单不存在")
+	}
+
+	currUser, err := s.GetCurrentSystemUser(ctx)
+	if err != nil {
+		return xerr.Custom("登录信息失效")
+	}
+
+	if !(outbound.AuditStatus == pasturePb.AuditStatus_Pending || outbound.AuditStatus == pasturePb.AuditStatus_Cancel) {
+		return xerr.Custom("出库单无法删除")
+	}
+
+	if currUser.Id != int64(outbound.ApplicantId) {
+		return xerr.Custom("非申请人,无权删除出库单")
+	}
+
+	outbound.Delete()
+	if err = s.DB.Model(new(model.Outbound)).
+		Select("audit_status").
+		Updates(outbound).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
 func (s *StoreEntry) FrozenSemenList(ctx context.Context, req *pasturePb.FrozenSemenRequest, pagination *pasturePb.PaginationModel) (*pasturePb.FrozenSemenResponse, error) {
 	frozenSemenList := make([]*model.FrozenSemen, 0)
 	var count int64 = 0

+ 1 - 0
module/backend/interface.go

@@ -223,6 +223,7 @@ type GoodsService interface {
 	OutboundList(ctx context.Context, req *pasturePb.SearchOutboundApplyRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchOutboundApplyResponse, error)
 	OutboundAudit(ctx context.Context, req *pasturePb.OutboundApplyAuditRequest) error
 	OutboundDetail(ctx context.Context, id int64) (*pasturePb.OutboundDetailResponse, error)
+	OutboundDelete(ctx context.Context, id int64) error
 }
 
 //go:generate mockgen -destination mock/AnalyseService.go -package kptservicemock kpt-pasture/module/backend AnalyseService

+ 8 - 4
module/backend/sql.go

@@ -303,15 +303,19 @@ func (s *StoreEntry) GetLastEventMating(ctx context.Context, cowId int64) (*mode
 
 func (s *StoreEntry) GetOutboundById(ctx context.Context, id int64) (*model.Outbound, error) {
 	res := &model.Outbound{}
-	if err := s.DB.Model(new(model.Outbound)).Where("id = ?", id).First(res).Error; err != nil {
+	if err := s.DB.Model(new(model.Outbound)).
+		Where("id = ?", id).First(res).Error; err != nil {
 		return nil, xerr.WithStack(err)
 	}
 	return res, nil
 }
 
-func (s *StoreEntry) GetOutboundLogsByOutboundId(ctx context.Context, id int64) ([]*model.OutboundLog, error) {
-	list := make([]*model.OutboundLog, 0)
-	if err := s.DB.Model(new(model.OutboundLog)).Where("outbound_id = ?", id).Find(&list).Error; err != nil {
+func (s *StoreEntry) GetOutboundDetailByOutboundId(ctx context.Context, id int64) ([]*model.OutboundDetail, error) {
+	list := make([]*model.OutboundDetail, 0)
+	if err := s.DB.Model(new(model.OutboundDetail)).
+		Where("outbound_id = ?", id).
+		Where("is_delete = ?", pasturePb.IsShow_Ok).
+		Find(&list).Error; err != nil {
 		return nil, xerr.WithStack(err)
 	}
 	return list, nil

+ 18 - 10
module/crontab/cow_cron.go

@@ -69,16 +69,21 @@ func (e *Entry) UpdateCowInfo() error {
 		e.CreateCrontabLog(UpdateCowInfo)
 	}()
 	for _, cow := range cowList {
+		updates := map[string]interface{}{
+			"day_age":       cow.GetDayAge(),
+			"calving_at":    cow.GetCalvingAge(),
+			"pregnancy_age": cow.GetDaysPregnant(),
+			"admission_age": cow.GetAdmissionAge(),
+			"abortion_age":  cow.GetAbortionAge(),
+		}
+
+		if cow.GetDayAge() == 60 {
+			updates["cow_type"] = pasturePb.CowType_Weaned_Calf
+		}
+
 		if err := e.DB.Model(new(model.Cow)).
 			Where("id = ?", cow.Id).
-			Updates(map[string]interface{}{
-				"day_age":       cow.GetDayAge(),
-				"calving_at":    cow.GetCalvingAge(),
-				"pregnancy_age": cow.GetDaysPregnant(),
-				"admission_age": cow.GetAdmissionAge(),
-				"abortion_age":  cow.GetAbortionAge(),
-				// todo 牛只类型待完善
-			}).Error; err != nil {
+			Updates(updates).Error; err != nil {
 			zaplog.Error("Crontab", zap.Any("UpdateCowDayAge", err))
 		}
 	}
@@ -108,12 +113,13 @@ func (e *Entry) ImmunizationPlan() error {
 		}
 		e.CreateCrontabLog(ImmunizationPlan)
 	}()
-
+	nowTime := time.Now().Unix()
 	for _, plan := range planList {
 		cowList := make([]*model.Cow, 0)
 		pref := e.DB.Table(fmt.Sprintf("%s as a", new(model.Cow).TableName())).
 			Select("a.*").
-			Where("a.admission_status = ?", pasturePb.AdmissionStatus_Admission)
+			Where("a.admission_status = ?", pasturePb.AdmissionStatus_Admission).
+			Where("NOT EXIST ( select 1 from event_immunization_plan b where b.pen_id = a.id and b.status = ? and b.plan_day > ?)", plan.Id, pasturePb.IsShow_No, nowTime)
 		if plan.CowType > 0 {
 			pref.Where("a.cow_type = ?", plan.CowType)
 		}
@@ -150,6 +156,7 @@ func (e *Entry) ImmunizationPlan() error {
 		penList, _ := e.GetPenMapList()
 		newImmunizationPlanCowList := model.NewCowImmunizationPlanList(cowList, penList, plan)
 		newEventItemList := model.NewEventItemList(cowList, pasturePb.CalendarType_Immunisation)
+
 		if err := e.DB.Transaction(func(tx *gorm.DB) error {
 			if err := tx.Create(newImmunizationPlanCowList).Error; err != nil {
 				return xerr.WithStack(err)
@@ -163,6 +170,7 @@ func (e *Entry) ImmunizationPlan() error {
 			zaplog.Error("ImmunizationPlan", zap.Any("newImmunizationPlanCowList", err), zap.Any("plan", plan), zap.Any("cowList", cowList))
 		}
 	}
+
 	zaplog.Info("ImmunizationPlan", zap.Any("todayCount", todayCount))
 	return nil
 }

+ 5 - 8
module/crontab/neck_ring.go

@@ -308,12 +308,7 @@ func (e *Entry) WeeklyActiveAvgUpdate(xToday *XToday) error {
 			Select("IF(COUNT(1)>6, ROUND(AVG( h2.active)*12,0), 0) as sum_active").
 			Select("MAX(h2.change_filter) as sum_max_high").
 			Select("MIN(IF(change_filter > ?, change_filter, 0)) as sum_min_high", MinChangeFilter).
-			Select("MIN( "+
-				"CASE WHEN filter_chew > ? "+
-				"THEN filter_chew "+
-				"WHEN filter_rumina >= ? "+
-				"THEN filter_rumina "+
-				"ELSE 0 END) as sum_min_chew", MinChangeFilter, MinRuminaFilter).
+			Select("MIN( CASE WHEN filter_chew > ? THEN filter_chew WHEN filter_rumina >= ? THEN filter_rumina ELSE 0 END) as sum_min_chew", MinChangeFilter, MinRuminaFilter).
 			Where("id BETWEEN ? AND ?", xToday.XMin2Id, xToday.CurrMaxHabitId).
 			Where("heat_date BETWEEN ? AND ?", xStartDate.AddDate(0, 0, -1).Format(model.LayoutDate2), xStartDate.Format(model.LayoutDate2)).
 			Where("created_at BETWEEN ? AND ?", xStartDate.Add(-23*time.Hour).Unix(), xStartDate.Unix()).
@@ -357,7 +352,7 @@ func (e *Entry) WeeklyActiveAvgUpdate(xToday *XToday) error {
 
 			v.ChangeRumina = v.RuminaFilter - v.AvgRuminaHabit/v.AvgHighHabit*100
 			v.ChangeChew = v.FilterChew - v.AvgChewHabit/v.AvgHighHabit*100
-			if err := e.DB.Model(new(model.NeckActiveHabit)).
+			if err = e.DB.Model(new(model.NeckActiveHabit)).
 				Select("change_high", "change_rumina", "change_chew").
 				Where("id = ?", v.Id).
 				Updates(v).Error; err != nil {
@@ -474,7 +469,9 @@ func (e *Entry) ActivityVolumeChanges(xToday *XToday) error {
 		if dayTimes == 1 {
 			if err = e.DB.Model(new(model.NeckActiveHabit)).
 				Select("cow_id").
-				Select("").
+				Select("AVG(IF(change_filter>=60, 60, change_filter)) as avg_filter").
+				Select("ROUND(STD(IF(change_filter>=60, 60, change_filter))) as std_filter").
+				Select("COUNT(1) as nb").
 				Where("id BETWEEN ? AND ?", xToday.XMin7Id, xToday.CurrMaxHabitId).
 				Where("heat_date BETWEEN ? AND ?", currDate.AddDate(0, 0, -7).Format(model.LayoutDate2), currDate.AddDate(0, 0, -1).Format(model.LayoutDate2)).
 				Where("frameid = ?", xframeId).