package backend import ( "context" "fmt" "kpt-pasture/model" "kpt-pasture/util" "net/http" "strings" "time" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" "gitee.com/xuyiping_admin/pkg/xerr" "gorm.io/gorm" ) func (s *StoreEntry) CalvingList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchLavingEventResponse, error) { lavingList := make([]*model.EventCalvingList, 0) var count int64 = 0 pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventCalving).TableName())). Select(`a.*,b.name as pen_name,c.name as staff_member_name`). Joins(fmt.Sprintf("JOIN %s AS b on a.pen_id = b.id", new(model.Pen).TableName())). Joins(fmt.Sprintf("JOIN %s AS c on a.staff_member_id = c.id", new(model.SystemUser).TableName())) if len(req.CowId) > 0 { cowIds := strings.Split(req.CowId, ",") pref.Where("a.cow_id IN ?", cowIds) } if err := pref.Order("a.id desc"). Count(&count).Limit(int(pagination.PageSize)). Offset(int(pagination.PageOffset)). Find(&lavingList).Error; err != nil { return nil, xerr.WithStack(err) } calvingIds := make([]int64, 0) for _, v := range lavingList { calvingIds = append(calvingIds, v.Id) } calvingCalfList := make([]*model.CalvingCalf, 0) if err := s.DB.Model(new(model.CalvingCalf)). Where("calving_id IN ?", calvingIds). Find(&calvingCalfList).Error; err != nil { return nil, xerr.WithStack(err) } return &pasturePb.SearchLavingEventResponse{ Code: http.StatusOK, Message: "ok", Data: &pasturePb.SearchLavingData{ List: model.EventCalvingListSlice(lavingList).ToPB(calvingCalfList), Total: int32(count), PageSize: pagination.PageSize, Page: pagination.Page, }, }, nil } func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalving) error { if len(req.CowId) <= 0 { return xerr.Custom("请选择相关牛只") } cowList, err := s.ParseCowIds(ctx, req.CowId) if err != nil { return xerr.WithStack(err) } if len(cowList) <= 0 { return xerr.Custom("请选择相关牛只") } cow := cowList[0] newEventCalving := &model.EventCalving{} if err = s.DB.Model(new(model.EventCalving)).Where("cow_id = ?", cow.Id).Where("lact = ?", cow.Lact).First(newEventCalving).Error; err != nil { return xerr.Custom("该母牛信息不存在") } if err = s.DB.Transaction(func(tx *gorm.DB) error { // 母牛信息 if err = tx.Model(new(model.EventCalving)). Where("id = ?", newEventCalving.Id). Updates(map[string]interface{}{ "reality_day": time.Unix(int64(req.CalvingAt), 0).Format(model.LayoutTime), "day_age": cow.DayAge, "lact": cow.Lact + 1, "pregnancy_age": cow.PregnancyAge, "calving_level": req.CalvingLevel, "bull_number": cow.LastBullNumber, "child_number": len(req.CalfItemList), }). Error; err != nil { return xerr.WithStack(err) } // 犊牛信息 newCalvingCalfList := model.NewEventCalvingCalf(cow.Id, newEventCalving.Id, req) for _, v := range newCalvingCalfList { if v.IsLive == pasturePb.IsShow_No || v.IsAdoption == pasturePb.IsShow_No { continue } // 留养犊牛 newCow := model.NewCalfCow(cow.Id, cow.LastBullNumber, v) if err = tx.Create(newCow).Error; err != nil { return xerr.WithStack(err) } v.CowId = newCow.Id } if err = tx.Create(newCalvingCalfList).Error; err != nil { return xerr.WithStack(err) } if err = tx.Model(new(model.Cow)).Where("id = ?", cow.Id).Updates(map[string]interface{}{ "calving_age": 0, "lact": cow.Lact + 1, "breed_status": pasturePb.BreedStatus_Calving, "is_pregnant": pasturePb.IsShow_No, "calving_at": 0, "last_calving_at": time.Now().Unix(), }).Error; err != nil { return xerr.WithStack(err) } return nil }); err != nil { return xerr.WithStack(err) } return nil } func (s *StoreEntry) PregnantCheckList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.PregnantCheckEventResponse, error) { pregnantCheckList := make([]*model.EventPregnantCheck, 0) var count int64 = 0 pref := s.DB.Table(new(model.EventPregnantCheck).TableName()) if len(req.CowId) > 0 { cowIds := strings.Split(req.CowId, ",") pref.Where("cow_id IN ?", cowIds) } if err := pref.Order("id desc"). Count(&count).Limit(int(pagination.PageSize)). Offset(int(pagination.PageOffset)). Find(&pregnantCheckList).Error; err != nil { return nil, xerr.WithStack(err) } pregnantCheckResultMap := s.PregnantCheckResultMap() pregnantCheckMethodMap := s.PregnantCheckMethodMap() return &pasturePb.PregnantCheckEventResponse{ Code: http.StatusOK, Message: "ok", Data: &pasturePb.SearchPregnantCheckData{ List: model.EventPregnantCheckSlice(pregnantCheckList).ToPB(pregnantCheckResultMap, pregnantCheckMethodMap), Total: int32(count), PageSize: pagination.PageSize, Page: pagination.Page, }, }, nil } func (s *StoreEntry) PregnantCheckCreate(ctx context.Context, req *pasturePb.EventPregnantCheck) error { if len(req.CowId) <= 0 { return xerr.Custom("请选择相关牛只") } cowList, err := s.ParseCowIds(ctx, req.CowId) if err != nil { return xerr.WithStack(err) } systemUser, _ := s.GetSystemUserById(ctx, int64(req.StaffMemberId)) pregnantCheckDay := time.Unix(int64(req.PregnantCheckAt), 0).Format(model.LayoutTime) // 更新怀孕牛只 updatePregnantCowIds := make([]int64, 0) // 更新流产牛只 updateAbortCowIds := make([]int64, 0) // 更新空怀牛只 updateEmptyCowIds := make([]int64, 0) cowIds := make([]int64, 0) for _, cow := range cowList { // 过滤掉没有配种状态的牛只 if cow.BreedStatus != pasturePb.BreedStatus_Breeding { continue } itemEventPregnantCheck := &model.EventPregnantCheck{} if err = s.DB.Model(new(model.EventPregnantCheck)). Where("lact = ?", cow.Lact). Where("cow_id = ?", cow.Id). Order("id desc").First(itemEventPregnantCheck).Error; err != nil { return xerr.WithStack(err) } if req.PregnantCheckResult == pasturePb.PregnantCheckResult_Pregnant { updatePregnantCowIds = append(updatePregnantCowIds, cow.Id) } if req.PregnantCheckResult == pasturePb.PregnantCheckResult_UnPregnant { if itemEventPregnantCheck.PregnantCheckName == model.PregnantCheckForFirst { updateAbortCowIds = append(updateAbortCowIds, cow.Id) } if itemEventPregnantCheck.PregnantCheckName == model.PregnantCheckForSecond { updateEmptyCowIds = append(updateEmptyCowIds, cow.Id) } } cowIds = append(cowIds, cow.Id) } if err = s.DB.Transaction(func(tx *gorm.DB) error { // 更新孕检事件表 if err = tx.Model(new(model.EventPregnantCheck)). Where("id IN ?", cowIds). Updates(map[string]interface{}{ "reality_day": pregnantCheckDay, "pregnant_check_result": req.PregnantCheckResult, "pregnant_check_method": req.PregnantCheckMethod, "operation_id": systemUser.Id, "operation_name": systemUser.Name, "remarks": req.Remarks, "is_pregnant": req.PregnantCheckResult, }).Error; err != nil { return xerr.WithStack(err) } // 更新牛只信息和配种事件表怀孕状态 if len(updatePregnantCowIds) > 0 { if err = tx.Model(&model.Cow{}).Where("cow_id IN ?", updatePregnantCowIds). Updates(map[string]interface{}{ "breed_status": pasturePb.BreedStatus_Pregnant, "last_pregnant_check_at": pregnantCheckDay, "is_pregnant": pasturePb.IsShow_Ok, }).Error; err != nil { return xerr.WithStack(err) } if err = tx.Model(&model.EventMating{}).Where("cow_id IN ?", updatePregnantCowIds). Group("cow_id").Select("MAX(id) as id"). Updates(map[string]interface{}{"mating_result": pasturePb.MatingResult_Pregnant}).Error; err != nil { return xerr.WithStack(err) } } // 更新牛只信息和配种事件表流产状态 if len(updateAbortCowIds) > 0 { if err = tx.Model(&model.Cow{}).Where("cow_id IN ?", updateAbortCowIds). Updates(map[string]interface{}{ "breed_status": pasturePb.BreedStatus_Abort, "last_pregnant_check_at": pregnantCheckDay, "is_pregnant": pasturePb.IsShow_Ok, }).Error; err != nil { return xerr.WithStack(err) } if err = tx.Model(&model.EventMating{}).Where("cow_id IN ?", updateAbortCowIds). Group("cow_id").Select("MAX(id) as id"). Updates(map[string]interface{}{"mating_result": pasturePb.MatingResult_Abort}).Error; err != nil { return xerr.WithStack(err) } } // 更新牛只信息和配种事件表空怀状态 if len(updateEmptyCowIds) > 0 { if err = tx.Model(&model.Cow{}).Where("cow_id IN ?", updateEmptyCowIds). Updates(map[string]interface{}{ "breed_status": pasturePb.BreedStatus_Empty, "last_pregnant_check_at": pregnantCheckDay, "is_pregnant": pasturePb.IsShow_Ok, }).Error; err != nil { return xerr.WithStack(err) } if err = tx.Model(&model.EventMating{}).Where("cow_id IN ?", updateEmptyCowIds). Group("cow_id").Select("MAX(id) as id"). Updates(map[string]interface{}{"mating_result": pasturePb.MatingResult_Empty}).Error; err != nil { return xerr.WithStack(err) } } return nil }); err != nil { return xerr.WithStack(err) } return nil } func (s *StoreEntry) MatingList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.MatingEventResponse, error) { matingList := make([]*model.EventMating, 0) var count int64 = 0 pref := s.DB.Model(new(model.EventMating)). Where("mating_result > ?", pasturePb.MatingResult_Invalid). Where("status = ?", pasturePb.IsShow_No) if len(req.CowId) > 0 { cowIds := strings.Split(req.CowId, ",") pref.Where("cow_id IN ?", cowIds) } if err := pref.Order("id desc"). Count(&count).Limit(int(pagination.PageSize)). Offset(int(pagination.PageOffset)). Find(&matingList).Error; err != nil { return nil, xerr.WithStack(err) } exposeEstrusTypeMap := s.ExposeEstrusTypeMap() return &pasturePb.MatingEventResponse{ Code: http.StatusOK, Message: "ok", Data: &pasturePb.SearchMatingData{ List: model.EventMatingSlice(matingList).ToPB(exposeEstrusTypeMap), Total: int32(count), PageSize: pagination.PageSize, Page: pagination.Page, }, }, nil } func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMating) error { if len(req.CowId) <= 0 { return xerr.Custom("请选择相关牛只") } cowList, err := s.ParseCowIds(ctx, req.CowId) if err != nil { return xerr.WithStack(err) } systemUser, _ := s.GetSystemUserById(ctx, int64(req.StaffMemberId)) eventFrozenSemenLogList := make([]*model.FrozenSemenLog, 0) frozenSemen := &model.FrozenSemen{} if err = s.DB.Where("bull_id = ?", req.FrozenSemenNumber).First(frozenSemen).Error; err != nil { return xerr.WithStack(err) } matingUpdateIds := make([]int64, 0) cowIds := make([]int64, 0) nowTime := time.Now() for _, cow := range cowList { var count int64 = 0 itemEventMating := &model.EventMating{} if err = s.DB.Where("lact = ?", cow.Lact). Where("cow_id = ?", cow.Id). Order("id desc"). First(itemEventMating).Count(&count).Error; err != nil { return xerr.WithStack(err) } // 判断当前输精时间距离上次输精时间是否超过2天,如果超过则更新为复配状态 itemBeforeTwoDays := nowTime.Sub(time.Unix(util.TimeParseLocalUnix(itemEventMating.RealityDay), 0)).Hours() if count > 0 && itemBeforeTwoDays > 48 { matingUpdateIds = append(matingUpdateIds, itemEventMating.Id) } eventFrozenSemenLogList = append( eventFrozenSemenLogList, model.NewEventFrozenSemenLog(req.FrozenSemenNumber, cow, int64(req.StaffMemberId)), ) cowIds = append(cowIds, cow.Id) } if err = s.DB.Transaction(func(tx *gorm.DB) error { if len(cowIds) > 0 { // 如果有同期牛只,则修改为已结束状态 if err = tx.Table(new(model.CowSameTime).TableName()). Where("cow_id IN ?", cowIds). UpdateColumn("status", pasturePb.SameTimeStatus_End).Error; err != nil { } // 创建配种事件数据 if err = tx.Model(new(model.EventMating)). Where("cow_id IN ?", cowIds). Updates(map[string]interface{}{ "mating_result": pasturePb.MatingResult_Unknown, "status": pasturePb.IsShow_Ok, "reality_day": time.Unix(int64(req.MatingAt), 0).Format(model.LayoutTime), "mating_number": 1, "frozen_semen_number": req.FrozenSemenCount, "operation_id": req.StaffMemberId, "operation_name": systemUser.Name, }). Error; err != nil { return xerr.WithStack(err) } } // 更新已配种的牛只为复配状态 if len(matingUpdateIds) > 0 { if err = tx.Model(new(model.EventMating)). Where("id IN ?", matingUpdateIds). Where("mating_result = ?", pasturePb.MatingResult_Unknown). Updates(map[string]interface{}{ "mating_result": pasturePb.MatingResult_ReMatch, "mating_number": 2, "frozen_semen_number": req.FrozenSemenCount, }). Error; err != nil { return xerr.WithStack(err) } } // 创建冻精使用记录日志 if err = tx.Create(eventFrozenSemenLogList).Error; err != nil { return xerr.WithStack(err) } // 减去精液的数量 if err = tx.Model(new(model.FrozenSemen)). Where("id = ?", frozenSemen.Id). Where("quantity > 0"). UpdateColumn("quantity", gorm.Expr("quantity - ?", len(matingUpdateIds)), ).Error; err != nil { return xerr.WithStack(err) } if err = tx.Table(new(model.Cow).TableName()). Where("id IN ?", cowIds). Updates(map[string]interface{}{ "breed_status": pasturePb.BreedStatus_Breeding, "last_bull_number": req.FrozenSemenNumber, "last_mating_at": int64(req.MatingAt), }).Error; err != nil { return xerr.WithStack(err) } return nil }); err != nil { return xerr.WithStack(err) } return nil } func (s *StoreEntry) EstrusList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EstrusEventResponse, error) { estrusList := make([]*model.EventEstrus, 0) var count int64 = 0 pref := s.DB.Table(new(model.EventEstrus).TableName()) if len(req.CowId) > 0 { cowIds := strings.Split(req.CowId, ",") pref.Where("cow_id IN ?", cowIds) } if err := pref.Order("id desc"). Count(&count).Limit(int(pagination.PageSize)). Offset(int(pagination.PageOffset)). Find(&estrusList).Error; err != nil { return nil, xerr.WithStack(err) } systemUserList, _ := s.SystemUserList(ctx) return &pasturePb.EstrusEventResponse{ Code: http.StatusOK, Message: "ok", Data: &pasturePb.SearchEstrusData{ List: model.EstrusSlice(estrusList).ToPB(systemUserList), Total: int32(count), PageSize: pagination.PageSize, Page: pagination.Page, }, }, nil } func (s *StoreEntry) EstrusCreate(ctx context.Context, req *pasturePb.EventEstrus) error { if len(req.CowId) <= 0 { return xerr.Custom("请选择相关牛只") } cowList, err := s.ParseCowIds(ctx, req.CowId) if err != nil { return xerr.WithStack(err) } estrusList := make([]*model.EventEstrus, 0) currentUser, _ := s.GetCurrentSystemUser(ctx) for _, cow := range cowList { estrusList = append(estrusList, model.NewEventEstrus(cow, currentUser, req)) } if err := s.DB.Create(estrusList).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 pref := s.DB.Table(new(model.FrozenSemen).TableName()) if req.BullId != "" { pref.Where("bull_id = ?", req.BullId) } if req.Producer != "" { pref.Where("producer = ?", req.Producer) } if err := pref.Order("id desc"). Count(&count).Limit(int(pagination.PageSize)). Offset(int(pagination.PageOffset)). Find(&frozenSemenList).Error; err != nil { return nil, xerr.WithStack(err) } frozenSemenTypeMap := s.FrozenSemenTypeMap() unitMap := s.UnitMap() return &pasturePb.FrozenSemenResponse{ Code: http.StatusOK, Message: "ok", Data: &pasturePb.SearchFrozenSemenData{ List: model.FrozenSemenSlice(frozenSemenList).ToPB(frozenSemenTypeMap, unitMap), Total: int32(count), PageSize: pagination.PageSize, Page: pagination.Page, }, }, nil } func (s *StoreEntry) FrozenSemenCreate(ctx context.Context, req *pasturePb.SearchFrozenSemenList) error { currentUser, _ := s.GetCurrentSystemUser(ctx) req.CowKindName = s.CowKindMap()[req.CowKind] newFrozenSemen := model.NewFrozenSemen(req, currentUser) if err := s.DB.Create(newFrozenSemen).Error; err != nil { return xerr.WithStack(err) } return nil } func (s *StoreEntry) SameTimeCreate(ctx context.Context, req *pasturePb.EventSameTime) error { if _, err := s.GetSameTimeById(ctx, int64(req.SameTimeId)); err != nil { return xerr.WithStack(err) } cowList, err := s.ParseCowIds(ctx, req.CowId) if err != nil { return xerr.WithStack(err) } cowIds := make([]int64, 0) for _, v := range cowList { cowIds = append(cowIds, v.Id) } drugs := &model.Drugs{} if req.DrugsId > 0 { if drugs, err = s.GetDrugsById(ctx, int64(req.DrugsId)); err != nil { return xerr.WithStack(err) } } systemUser, _ := s.GetSystemUserById(ctx, int64(req.StaffMemberId)) if err = s.DB.Transaction(func(tx *gorm.DB) error { if err = tx.Model(new(model.CowSameTime)). Where("cow_id IN ?", cowIds). Where("same_time_id = ?", req.SameTimeId). Update("same_time_status", pasturePb.SameTimeStatus_In_Progress).Error; err != nil { return xerr.WithStack(err) } if err = tx.Model(new(model.EventCowSameTime)). Where("cow_id IN ?", cowIds). Where("same_time_id = ?", req.SameTimeId). Where("same_time_type = ?", req.SameTimeType). Updates(map[string]interface{}{ "status": pasturePb.IsShow_Ok, "drug_id": drugs.Id, "unit": drugs.Unit, "usage": req.Usage, "remarks": req.Remarks, "operation_id": req.StaffMemberId, "operation_name": systemUser.Name, }).Error; err != nil { return xerr.WithStack(err) } return nil }); err != nil { return xerr.WithStack(err) } return nil } func (s *StoreEntry) AbortionCreate(ctx context.Context, req *pasturePb.EventAbortionRequest) error { cow, err := s.GetCowInfoByCowId(ctx, int64(req.CowId)) if err != nil { return xerr.WithStack(err) } systemUser, err := s.GetSystemUserById(ctx, int64(req.OperationId)) if err != nil { return xerr.WithStack(err) } req.OperationName = systemUser.Name abortionReasonsMap := s.AbortionReasonsMap() newEventAbortion := model.NewEventAbortion(cow, req, abortionReasonsMap) lastCowMating := &model.EventMating{} if err = s.DB.Where("cow_id = ?", cow.Id).Order("id desc").First(lastCowMating).Error; err != nil { return xerr.WithStack(err) } if err = s.DB.Transaction(func(tx *gorm.DB) error { // 创建牛只流产事件数据 if err = tx.Create(newEventAbortion).Error; err != nil { return xerr.WithStack(err) } // 更新牛只状态 if err = tx.Model(new(model.Cow)).Where("id = ?", req.CowId). Updates(map[string]interface{}{ "is_pregnant": pasturePb.IsShow_No, "last_abortion_at": req.AbortionAt, "breed_status": pasturePb.BreedStatus_Abort, }).Error; err != nil { return xerr.WithStack(err) } // 更新最近一次配种结果为流产 if err = tx.Model(new(model.EventMating)).Where("id = ?", lastCowMating.Id). Updates(map[string]interface{}{ "mating_result": pasturePb.MatingResult_Abort, }).Error; err != nil { } return nil }); err != nil { return xerr.WithStack(err) } return nil } func (s *StoreEntry) AbortionList( ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel, ) (*pasturePb.EventAbortionResponse, error) { abortionList := make([]*model.EventAbortion, 0) var count int64 = 0 pref := s.DB.Model(new(model.EventAbortion)) if len(req.CowId) > 0 { cowIds := strings.Split(req.CowId, ",") pref.Where("cow_id IN ?", cowIds) } if err := pref.Order("id desc"). Count(&count).Limit(int(pagination.PageSize)). Offset(int(pagination.PageOffset)). Find(&abortionList).Error; err != nil { return nil, xerr.WithStack(err) } return &pasturePb.EventAbortionResponse{ Code: http.StatusOK, Message: "ok", Data: &pasturePb.EventAbortionData{ List: model.AbortionSlice(abortionList).ToPB(), Total: int32(count), PageSize: pagination.PageSize, Page: pagination.Page, }, }, nil }