feed_service.go 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  1. package backend
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "kpt-tmr-group/model"
  10. "kpt-tmr-group/pkg/logger/zaplog"
  11. "kpt-tmr-group/pkg/xerr"
  12. operationPb "kpt-tmr-group/proto/go/backend/operation"
  13. "net/http"
  14. "strconv"
  15. "sync"
  16. "time"
  17. "go.uber.org/multierr"
  18. "github.com/xuri/excelize/v2"
  19. "go.uber.org/zap"
  20. "gorm.io/gorm"
  21. )
  22. const EncodeNumberPrefix = "encode_number"
  23. var PastureDataLogType = map[string]int32{
  24. "FeedFormula_Distribute": 1,
  25. "FeedFormula_IsModify": 2,
  26. "FeedFormula_Cancel_Distribute": 3,
  27. }
  28. var EditRecodeMap = map[string]string{
  29. "forage_name": "饲料名称",
  30. "weight": "重量",
  31. "stir_delay": "搅拌延迟",
  32. "allow_error": "允许误差",
  33. "sort": "排序",
  34. }
  35. // CreateFeedFormula 添加数据
  36. func (s *StoreEntry) CreateFeedFormula(ctx context.Context, req *operationPb.AddFeedFormulaRequest) error {
  37. forage := model.NewFeedFormula(req)
  38. if err := s.DB.Create(forage).Error; err != nil {
  39. return xerr.WithStack(err)
  40. }
  41. return nil
  42. }
  43. // EditFeedFormula 编辑数据
  44. func (s *StoreEntry) EditFeedFormula(ctx context.Context, req *operationPb.AddFeedFormulaRequest) error {
  45. forage := model.FeedFormula{Id: int64(req.Id)}
  46. if err := s.DB.Where("is_delete = ?", operationPb.IsShow_OK).First(&forage).Error; err != nil {
  47. if errors.Is(err, gorm.ErrRecordNotFound) {
  48. return xerr.Custom("该数据不存在")
  49. }
  50. return xerr.WithStack(err)
  51. }
  52. updateData := &model.FeedFormula{
  53. Name: req.Name,
  54. Colour: req.Colour,
  55. CattleCategoryId: req.CattleCategoryId,
  56. CattleCategoryName: req.CattleCategoryName,
  57. FormulaTypeId: req.FormulaTypeId,
  58. FormulaTypeName: req.FormulaTypeName,
  59. DataSourceId: req.DataSourceId,
  60. DataSourceName: req.DataSourceName,
  61. Remarks: req.Remarks,
  62. IsShow: req.IsShow,
  63. }
  64. if err := s.DB.Model(new(model.FeedFormula)).
  65. Omit("is_show", "is_delete", "encode_number", "formula_type_id", "formula_type_name", "data_source", "version", "is_modify").
  66. Where("id = ?", req.Id).
  67. Updates(updateData).Error; err != nil {
  68. return xerr.WithStack(err)
  69. }
  70. return nil
  71. }
  72. // AddFeedByFeedFormula 配方添加饲料
  73. func (s *StoreEntry) AddFeedByFeedFormula(ctx context.Context, req *operationPb.GroupAddFeedFormulaDetail) error {
  74. feedFormulaData := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  75. if err := s.DB.Model(new(model.FeedFormula)).First(feedFormulaData).Error; err != nil {
  76. return xerr.WithStack(err)
  77. }
  78. defer s.addFeedFormulaDetailAddRecode(ctx, req)
  79. insertData := make([]*model.FeedFormulaDetail, 0)
  80. for _, v := range req.List {
  81. feedData := &model.Forage{Id: int64(v.ForageId)}
  82. if err := s.DB.Model(new(model.Forage)).First(feedData).Error; err != nil {
  83. return xerr.WithStack(err)
  84. }
  85. if v.AllowError > v.StirDelay {
  86. return xerr.Customf("允许误差不能大于搅拌延迟")
  87. }
  88. insertData = append(insertData, &model.FeedFormulaDetail{
  89. PastureName: "集团",
  90. FeedFormulaId: int64(req.FeedFormulaId),
  91. ForageId: int64(v.ForageId),
  92. ForageName: v.ForageName,
  93. ForageGroupName: v.ForageGroupName,
  94. Weight: int32(v.Weight * 100),
  95. StirDelay: v.StirDelay,
  96. AllowError: v.AllowError,
  97. IsShow: operationPb.IsShow_OK,
  98. IsModify: v.IsModify,
  99. Sort: v.Sort,
  100. })
  101. }
  102. if err := s.DB.Model(new(model.FeedFormulaDetail)).Save(insertData).Error; err != nil {
  103. return xerr.WithStack(err)
  104. }
  105. return nil
  106. }
  107. // addFeedFormulaDetailAddRecode 添加配方记录
  108. func (s *StoreEntry) addFeedFormulaDetailAddRecode(ctx context.Context, req *operationPb.GroupAddFeedFormulaDetail) {
  109. editRecordList := make([]*model.FeedFormulaEditRecord, 0)
  110. for _, v := range req.List {
  111. editRecordList = append(editRecordList, &model.FeedFormulaEditRecord{
  112. FeedFormulaId: int64(req.FeedFormulaId),
  113. PastureName: "集团",
  114. ForageName: v.ForageName,
  115. Status: operationPb.FeedFormulaEditRecordType_INSERT,
  116. })
  117. }
  118. if err := s.CreateFeedFormulaEditRecord(ctx, editRecordList); err != nil {
  119. zaplog.Error("deleteFeedFormulaDetailAddRecode", zap.Any("CreateFeedFormulaEditRecord", err))
  120. }
  121. }
  122. // EditFeedByFeedFormula 配方饲料编辑
  123. func (s *StoreEntry) EditFeedByFeedFormula(ctx context.Context, req *operationPb.AddFeedFormulaDetail) error {
  124. feedFormulaData := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  125. if err := s.DB.Model(new(model.FeedFormula)).First(feedFormulaData).Error; err != nil {
  126. return xerr.WithStack(err)
  127. }
  128. feedFormulaDetail := &model.FeedFormulaDetail{Id: int64(req.Id)}
  129. if err := s.DB.Model(new(model.FeedFormulaDetail)).
  130. Where("is_show = ?", operationPb.IsShow_OK).
  131. First(feedFormulaDetail).Error; err != nil {
  132. return xerr.WithStack(err)
  133. }
  134. // 添加修改记录
  135. defer s.editFeedFormulaDetailAddRecode(ctx, req, feedFormulaDetail)
  136. // 更新数据
  137. updateData := &model.FeedFormulaDetail{
  138. ForageId: int64(req.ForageId),
  139. ForageName: req.ForageName,
  140. ForageGroupName: req.ForageGroupName,
  141. Weight: int32(req.Weight * 100),
  142. StirDelay: req.StirDelay,
  143. AllowError: req.AllowError,
  144. Sort: req.Sort,
  145. }
  146. if err := s.DB.Model(new(model.FeedFormulaDetail)).Where("id = ?", req.Id).Updates(updateData).Error; err != nil {
  147. return xerr.WithStack(err)
  148. }
  149. return nil
  150. }
  151. // EditFeedFormulaDetailAddRecode 更新饲料配方修改记录
  152. func (s *StoreEntry) editFeedFormulaDetailAddRecode(ctx context.Context, req *operationPb.AddFeedFormulaDetail, feedFormulaDetail *model.FeedFormulaDetail) {
  153. editRecordList := make([]*model.FeedFormulaEditRecord, 0)
  154. editRecordData := &model.FeedFormulaEditRecord{
  155. FeedFormulaId: int64(req.FeedFormulaId),
  156. PastureName: "集团",
  157. ForageName: req.ForageName,
  158. Status: operationPb.FeedFormulaEditRecordType_UPDATE,
  159. }
  160. if operationName, err := s.GetCurrentUserName(ctx); err != nil {
  161. zaplog.Error("EditFeedByFeedFormula", zap.Any("GetCurrentUserName", err))
  162. } else {
  163. editRecordData.OperationName = operationName
  164. }
  165. lastGroupIdData := &model.FeedFormulaEditRecord{}
  166. if err := s.DB.Model(new(model.FeedFormulaEditRecord)).
  167. Where("is_show = ?", operationPb.IsShow_OK).
  168. Order("group_id desc").
  169. First(&lastGroupIdData).Error; err != nil {
  170. zaplog.Error("EditFeedByFeedFormula", zap.Any("lastGroupIdData", err))
  171. } else {
  172. editRecordData.GroupId = lastGroupIdData.GroupId + 1
  173. editRecordData.BeforeValue = lastGroupIdData.BeforeValue
  174. }
  175. if feedFormulaDetail.ForageName != req.ForageName {
  176. editRecordData.FieldName = EditRecodeMap["forage_name"]
  177. editRecordData.BeforeValue = lastGroupIdData.ForageName
  178. editRecordData.AfterValue = req.ForageName
  179. editRecordList = append(editRecordList, editRecordData)
  180. }
  181. if feedFormulaDetail.Weight != int32(req.Weight*100) {
  182. editRecordData.FieldName = EditRecodeMap["weight"]
  183. editRecordData.AfterValue = fmt.Sprintf("%d", int32(req.Weight*100))
  184. editRecordList = append(editRecordList, editRecordData)
  185. }
  186. if feedFormulaDetail.AllowError != req.AllowError {
  187. editRecordData.FieldName = EditRecodeMap["allow_error"]
  188. editRecordData.AfterValue = fmt.Sprintf("%d", req.AllowError)
  189. editRecordList = append(editRecordList, editRecordData)
  190. }
  191. if feedFormulaDetail.StirDelay != req.StirDelay {
  192. editRecordData.FieldName = EditRecodeMap["stir_delay"]
  193. editRecordData.AfterValue = fmt.Sprintf("%d", req.StirDelay)
  194. editRecordList = append(editRecordList, editRecordData)
  195. }
  196. if feedFormulaDetail.Sort != req.Sort {
  197. editRecordData.FieldName = EditRecodeMap["sort"]
  198. editRecordData.AfterValue = fmt.Sprintf("%d", req.Sort)
  199. editRecordList = append(editRecordList, editRecordData)
  200. }
  201. if err := s.CreateFeedFormulaEditRecord(ctx, editRecordList); err != nil {
  202. zaplog.Error("EditFeedByFeedFormula", zap.Any("CreateFeedFormulaEditRecord", err))
  203. }
  204. }
  205. // CreateFeedFormulaEditRecord 创建配方修改记录
  206. func (s *StoreEntry) CreateFeedFormulaEditRecord(ctx context.Context, req []*model.FeedFormulaEditRecord) error {
  207. if req == nil {
  208. return nil
  209. }
  210. if err := s.DB.Model(new(model.FeedFormulaEditRecord)).Save(req).Error; err != nil {
  211. return xerr.WithStack(err)
  212. }
  213. return nil
  214. }
  215. // FeedFormulaDetailBySort 配方饲料排序
  216. func (s *StoreEntry) FeedFormulaDetailBySort(ctx context.Context, req *operationPb.GroupAddFeedFormulaDetail) error {
  217. feedFormulaData := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  218. if err := s.DB.Model(new(model.FeedFormula)).First(feedFormulaData).Error; err != nil {
  219. return xerr.WithStack(err)
  220. }
  221. tx := s.DB.Transaction(func(tx *gorm.DB) error {
  222. for _, v := range req.List {
  223. if err := tx.Model(new(model.FeedFormulaDetail)).
  224. Where("id = ?", v.Id).
  225. Updates(map[string]interface{}{
  226. "sort": v.Sort,
  227. }).Error; err != nil {
  228. return xerr.WithStack(err)
  229. }
  230. }
  231. return nil
  232. })
  233. return tx
  234. }
  235. // FeedFormulaDetailIsModify 配方饲料是否可修改
  236. func (s *StoreEntry) FeedFormulaDetailIsModify(ctx context.Context, req *operationPb.AddFeedFormulaDetail) error {
  237. feedFormulaData := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  238. if err := s.DB.Model(new(model.FeedFormula)).First(feedFormulaData).Error; err != nil {
  239. return xerr.WithStack(err)
  240. }
  241. return s.DB.Model(new(model.FeedFormulaDetail)).
  242. Where("id = ?", req.Id).
  243. Where("feed_formula_id = ?", req.FeedFormulaId).
  244. Updates(map[string]interface{}{
  245. "is_modify": req.IsModify,
  246. }).Error
  247. }
  248. // DeleteFeedFormulaDetail 配方删除饲料
  249. func (s *StoreEntry) DeleteFeedFormulaDetail(ctx context.Context, req *operationPb.GroupAddFeedFormulaDetail) error {
  250. feedFormulaData := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  251. if err := s.DB.Model(new(model.FeedFormula)).First(feedFormulaData).Error; err != nil {
  252. return xerr.WithStack(err)
  253. }
  254. // 增加配方记录
  255. defer s.deleteFeedFormulaDetailAddRecode(ctx, req)
  256. tr := s.DB.Transaction(func(tx *gorm.DB) error {
  257. for _, v := range req.List {
  258. if err := tx.Model(new(model.FeedFormulaDetail)).
  259. Where("id = ?", v.Id).
  260. Updates(map[string]interface{}{
  261. "is_show": operationPb.IsShow_NO,
  262. }).Error; err != nil {
  263. return xerr.WithStack(err)
  264. }
  265. }
  266. return nil
  267. })
  268. return tr
  269. }
  270. // deleteFeedFormulaDetailAddRecode 删除配方增加修改记录
  271. func (s *StoreEntry) deleteFeedFormulaDetailAddRecode(ctx context.Context, req *operationPb.GroupAddFeedFormulaDetail) {
  272. editRecordList := make([]*model.FeedFormulaEditRecord, 0)
  273. for _, v := range req.List {
  274. editRecordList = append(editRecordList, &model.FeedFormulaEditRecord{
  275. FeedFormulaId: int64(req.FeedFormulaId),
  276. PastureName: "集团",
  277. ForageName: v.ForageName,
  278. Status: operationPb.FeedFormulaEditRecordType_DELETE,
  279. })
  280. }
  281. if err := s.CreateFeedFormulaEditRecord(ctx, editRecordList); err != nil {
  282. zaplog.Error("deleteFeedFormulaDetailAddRecode", zap.Any("CreateFeedFormulaEditRecord", err))
  283. }
  284. }
  285. // SearchFeedFormulaDetail 查询配方饲料详情
  286. func (s *StoreEntry) SearchFeedFormulaDetail(ctx context.Context, req *operationPb.AddFeedFormulaDetail) (*operationPb.FeedFormulaDetailResponse, error) {
  287. feedFormulaData := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  288. if err := s.DB.Model(new(model.FeedFormula)).First(feedFormulaData).Debug().Error; err != nil {
  289. return nil, xerr.WithStack(err)
  290. }
  291. var count int64
  292. feedFormulaDetailList := make([]*model.FeedFormulaDetail, 0)
  293. pref := s.DB.Model(new(model.FeedFormulaDetail)).
  294. Where("is_show = ?", operationPb.IsShow_OK).
  295. Where("feed_formula_id = ?", req.FeedFormulaId)
  296. if req.ForageName != "" {
  297. pref.Where("forage_name = ?", req.ForageName)
  298. }
  299. if req.ForageGroupName != "" {
  300. pref.Where("forage_group_name = ?", req.ForageGroupName)
  301. }
  302. if req.Weight > 0 {
  303. pref.Where("weight = ?", int64(req.Weight*100))
  304. }
  305. if req.IsLockCowCountRatio > 0 {
  306. pref.Where("is_lock_cow_count_ratio = ?", req.IsLockCowCountRatio)
  307. }
  308. if req.StirDelay > 0 {
  309. pref.Where("stir_delay = ?", req.StirDelay)
  310. }
  311. if req.Sort > 0 {
  312. pref.Where("sort = ?", req.Sort)
  313. }
  314. if err := pref.Order("sort").Count(&count).Limit(int(req.Pagination.PageSize)).
  315. Offset(int(req.Pagination.PageOffset)).Find(&feedFormulaDetailList).Debug().Error; err != nil {
  316. return nil, xerr.WithStack(err)
  317. }
  318. return &operationPb.FeedFormulaDetailResponse{
  319. Code: http.StatusOK,
  320. Msg: "ok",
  321. Data: model.FeedFormulaDetailSlice(feedFormulaDetailList).ToPB(),
  322. }, nil
  323. }
  324. // MixedFeedFormula 合成预混料
  325. func (s *StoreEntry) MixedFeedFormula(ctx context.Context, req *operationPb.MixedFeedFormulaRequest) error {
  326. tr := s.DB.Transaction(func(tx *gorm.DB) error {
  327. feedFormulaData := &model.FeedFormula{
  328. Name: req.Name,
  329. Colour: req.Colour,
  330. EncodeNumber: s.EncodeNumber(ctx),
  331. CattleCategoryId: operationPb.CattleCategoryParent_Kind(req.CattleCategoryId),
  332. CattleCategoryName: req.CattleCategoryName,
  333. FormulaTypeId: req.FormulaTypeId,
  334. FormulaTypeName: req.FormulaTypeName,
  335. DataSourceId: operationPb.DataSource_Kind(req.DataSourceId),
  336. DataSourceName: operationPb.DataSource_Kind_name[req.DataSourceId],
  337. Remarks: req.Remarks,
  338. PastureName: "集团",
  339. IsShow: operationPb.IsShow_OK,
  340. IsModify: operationPb.IsShow_OK,
  341. IsDelete: operationPb.IsShow_OK,
  342. }
  343. if err := s.DB.Model(new(model.FeedFormula)).Create(feedFormulaData).Error; err != nil {
  344. return xerr.WithStack(err)
  345. }
  346. feedFormulaDetailList := make([]*model.FeedFormulaDetail, 0)
  347. for _, v := range req.FeedList {
  348. feedFormulaDetailList = append(feedFormulaDetailList, &model.FeedFormulaDetail{
  349. PastureName: "集团",
  350. FeedFormulaId: feedFormulaData.Id,
  351. ForageId: int64(v.ForageId),
  352. ForageName: v.ForageName,
  353. ForageGroupName: v.ForageGroupName,
  354. Weight: int32(v.Weight * 100),
  355. StirDelay: v.StirDelay,
  356. AllowError: v.AllowError,
  357. IsShow: operationPb.IsShow_OK,
  358. Sort: v.Sort,
  359. })
  360. }
  361. if err := s.DB.Model(new(model.FeedFormulaDetail)).Save(feedFormulaDetailList).Error; err != nil {
  362. return xerr.WithStack(err)
  363. }
  364. return nil
  365. })
  366. return tr
  367. }
  368. // SearchFeedFormulaList 查询数据列表
  369. func (s *StoreEntry) SearchFeedFormulaList(ctx context.Context, req *operationPb.SearchFeedFormulaRequest) (*operationPb.SearchFeedFormulaListResponse, error) {
  370. feedFormula := make([]*model.FeedFormula, 0)
  371. var count int64 = 0
  372. pref := s.DB.Model(new(model.FeedFormula)).Where("is_delete = ?", operationPb.IsShow_OK)
  373. if req.Name != "" {
  374. pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%"))
  375. }
  376. if req.CattleCategoryId > 0 {
  377. pref.Where("cattle_category_id = ?", req.CattleCategoryId)
  378. }
  379. if req.FormulaTypeId > 0 {
  380. pref.Where("formula_type_id = ?", req.FormulaTypeId)
  381. }
  382. if req.IsShow > 0 {
  383. pref.Where("is_show = ?", req.IsShow)
  384. }
  385. if req.DataSource > 0 {
  386. pref.Where("data_source = ?", req.DataSource)
  387. }
  388. if req.Remarks != "" {
  389. pref.Where("remarks = ?", req.Remarks)
  390. }
  391. if err := pref.Order("id desc").Count(&count).Limit(int(req.Pagination.PageSize)).Offset(int(req.Pagination.PageOffset)).
  392. Find(&feedFormula).Error; err != nil {
  393. return nil, xerr.WithStack(err)
  394. }
  395. return &operationPb.SearchFeedFormulaListResponse{
  396. Code: http.StatusOK,
  397. Msg: "ok",
  398. Data: &operationPb.SearchFeedFormulaListData{
  399. Page: req.Pagination.Page,
  400. PageSize: req.Pagination.PageSize,
  401. Total: int32(count),
  402. List: model.FeedFormulaSlice(feedFormula).ToPB(),
  403. },
  404. }, nil
  405. }
  406. // SearchFeedFormulaById 查询指定数据
  407. func (s *StoreEntry) SearchFeedFormulaById(ctx context.Context, foodFormulaId int64) (*model.FeedFormula, error) {
  408. feedFormula := &model.FeedFormula{}
  409. if err := s.DB.Model(new(model.FeedFormula)).
  410. Where("is_delete = ?", operationPb.IsShow_OK).
  411. Where("id = ?", foodFormulaId).
  412. First(feedFormula).Error; err != nil {
  413. return nil, xerr.WithStack(err)
  414. }
  415. return feedFormula, nil
  416. }
  417. // IsShowFeedFormula 是否启用和是否可修改
  418. func (s *StoreEntry) IsShowFeedFormula(ctx context.Context, req *operationPb.IsShowModifyFeedFormula) error {
  419. feedFormula := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  420. if err := s.DB.First(feedFormula).Error; err != nil {
  421. if errors.Is(err, gorm.ErrRecordNotFound) {
  422. return xerr.Custom("该数据不存在")
  423. }
  424. return xerr.WithStack(err)
  425. }
  426. if req.EditType == 1 {
  427. if err := s.DB.Model(new(model.FeedFormula)).Where("id = ?", req.FeedFormulaId).Update("is_show", req.IsShow).Error; err != nil {
  428. return xerr.WithStack(err)
  429. }
  430. }
  431. if req.EditType == 2 {
  432. if err := s.DB.Model(new(model.FeedFormula)).Where("id = ?", req.FeedFormulaId).Update("is_modify", req.IsShow).Error; err != nil {
  433. return xerr.WithStack(err)
  434. } else {
  435. s.PastureFeedFormulaIsModify(ctx, req.FeedFormulaId, req.IsShow)
  436. }
  437. }
  438. return nil
  439. }
  440. // DeleteFeedFormula 是否删除
  441. func (s *StoreEntry) DeleteFeedFormula(ctx context.Context, feedFormulaId int64) error {
  442. feedFormula := &model.FeedFormula{Id: feedFormulaId}
  443. if err := s.DB.First(feedFormula).Error; err != nil {
  444. if errors.Is(err, gorm.ErrRecordNotFound) {
  445. return xerr.Custom("该数据不存在")
  446. }
  447. return xerr.WithStack(err)
  448. }
  449. if err := s.DB.Model(new(model.FeedFormula)).Where("id = ?", feedFormula.Id).Update("is_delete", operationPb.IsShow_NO).Error; err != nil {
  450. return xerr.WithStack(err)
  451. }
  452. return nil
  453. }
  454. // ExcelImportFeedFormula 导入excel
  455. func (s *StoreEntry) ExcelImportFeedFormula(ctx context.Context, req io.Reader) error {
  456. xlsx, err := excelize.OpenReader(req)
  457. if err != nil {
  458. return xerr.WithStack(err)
  459. }
  460. defer xlsx.Close()
  461. rows, err := xlsx.GetRows(xlsx.GetSheetName(xlsx.GetActiveSheetIndex()))
  462. if err != nil {
  463. return xerr.WithStack(err)
  464. }
  465. if len(rows) > 10000 {
  466. rows = rows[:10000]
  467. }
  468. feedFormulaList := make([]*model.FeedFormula, 0)
  469. for i, row := range rows {
  470. if i == 0 {
  471. continue
  472. }
  473. var (
  474. name, encodeNumber, cattleCategoryName, formulaTypeName, dataSourceName, remarks, isShowStr string
  475. isShow operationPb.IsShow_Kind
  476. )
  477. for k, v := range row {
  478. if k == 0 {
  479. name = v
  480. }
  481. if k == 1 {
  482. encodeNumber = v
  483. }
  484. if k == 2 {
  485. cattleCategoryName = v
  486. }
  487. if k == 3 {
  488. formulaTypeName = v
  489. }
  490. if k == 4 {
  491. dataSourceName = v
  492. }
  493. if k == 5 {
  494. remarks = v
  495. }
  496. if k == 6 {
  497. isShowStr = v
  498. }
  499. }
  500. if isShowStr == "是" {
  501. isShow = operationPb.IsShow_OK
  502. } else {
  503. isShow = operationPb.IsShow_NO
  504. }
  505. feedFormulaItem := &model.FeedFormula{
  506. Name: name,
  507. EncodeNumber: encodeNumber,
  508. CattleCategoryName: cattleCategoryName,
  509. FormulaTypeName: formulaTypeName,
  510. Remarks: remarks,
  511. IsShow: isShow,
  512. IsDelete: operationPb.IsShow_OK,
  513. DataSourceId: operationPb.DataSource_EXCEL_IMPORT,
  514. DataSourceName: dataSourceName,
  515. }
  516. feedFormulaList = append(feedFormulaList, feedFormulaItem)
  517. }
  518. if len(feedFormulaList) > 0 {
  519. if err = s.DB.Create(feedFormulaList).Error; err != nil {
  520. return xerr.WithStack(err)
  521. }
  522. }
  523. return nil
  524. }
  525. // ExcelExportFeedFormula 流式导出excel
  526. func (s *StoreEntry) ExcelExportFeedFormula(ctx context.Context, req *operationPb.SearchFeedFormulaRequest) (*bytes.Buffer, error) {
  527. res, err := s.SearchFeedFormulaList(ctx, req)
  528. if err != nil {
  529. return nil, xerr.WithStack(err)
  530. }
  531. if len(res.Data.List) <= 0 {
  532. return nil, xerr.Custom("数据为空")
  533. }
  534. file := excelize.NewFile()
  535. defer file.Close()
  536. streamWriter, err := file.NewStreamWriter("Sheet1")
  537. if err != nil {
  538. return nil, xerr.WithStack(err)
  539. }
  540. titles := []interface{}{"配方名称", "配方编码", "畜牧类别", "配方类别", "来源", "备注", "是否启用",
  541. "饲料组", "饲料名称", "重量(kg)", "搅拌延迟(min)", "是否锁定牛头数比例", "顺序"}
  542. if err = streamWriter.SetRow("A1", titles); err != nil {
  543. return nil, xerr.WithStack(err)
  544. }
  545. for i, item := range res.Data.List {
  546. cell, err := excelize.CoordinatesToCellName(1, i+2)
  547. if err != nil {
  548. zaplog.Error("exclude CoordinatesToCellName", zap.Any("Err", err))
  549. continue
  550. }
  551. row := make([]interface{}, 0)
  552. row = append(row, item.Name, item.EncodeNumber, item.CattleCategoryName, item.FormulaTypeName, item.DataSourceName,
  553. item.Remarks, item.IsShow)
  554. if err = streamWriter.SetRow(cell, row); err != nil {
  555. return nil, xerr.WithStack(err)
  556. }
  557. }
  558. if err = streamWriter.Flush(); err != nil {
  559. return nil, xerr.WithStack(err)
  560. }
  561. return file.WriteToBuffer()
  562. }
  563. // ExcelTemplateFeedFormula 导出模板
  564. func (s *StoreEntry) ExcelTemplateFeedFormula(ctx context.Context) (*bytes.Buffer, error) {
  565. file := excelize.NewFile()
  566. defer file.Close()
  567. streamWriter, err := file.NewStreamWriter("Sheet1")
  568. if err != nil {
  569. return nil, xerr.WithStack(err)
  570. }
  571. titles := []interface{}{"配方名称", "配方编码", "畜牧类别", "配方类别", "来源", "备注", "是否启用",
  572. "饲料组", "饲料名称", "重量(kg)", "搅拌延迟(min)", "是否锁定牛头数比例", "顺序"}
  573. if err = streamWriter.SetRow("A1", titles); err != nil {
  574. return nil, xerr.WithStack(err)
  575. }
  576. if err = streamWriter.Flush(); err != nil {
  577. return nil, xerr.WithStack(err)
  578. }
  579. return file.WriteToBuffer()
  580. }
  581. // EncodeNumber 配方编码
  582. func (s *StoreEntry) EncodeNumber(ctx context.Context) string {
  583. currTime := time.Now().Format(model.LayoutDate)
  584. prefix := fmt.Sprintf("%s_%s", EncodeNumberPrefix, currTime)
  585. data := &model.UniqueData{}
  586. if err := s.DB.Order("id desc").Where("prefix = ?", prefix).First(data).Error; err != nil {
  587. if !errors.Is(err, gorm.ErrRecordNotFound) {
  588. return ""
  589. }
  590. ud, _ := strconv.Atoi(currTime)
  591. result := ud*100 + 1
  592. newData := &model.UniqueData{
  593. Prefix: prefix,
  594. Data: int64(result),
  595. }
  596. if err = s.DB.Create(newData).Error; err != nil {
  597. zaplog.Error("EncodeNumber Create", zap.Any("data", newData), zap.Any("Err", err))
  598. return ""
  599. }
  600. return fmt.Sprintf("%d", newData.Data)
  601. }
  602. data.Data += 1
  603. if err := s.DB.Model(new(model.UniqueData)).Where("prefix = ?", prefix).Update("data", data.Data).Error; err != nil {
  604. return ""
  605. } else {
  606. return fmt.Sprintf("%d", data.Data)
  607. }
  608. }
  609. // DistributeFeedFormula 配方下发牧场
  610. func (s *StoreEntry) DistributeFeedFormula(ctx context.Context, req *operationPb.DistributeFeedFormulaRequest) error {
  611. distributeData, err := s.checkoutDistributeData(ctx, req)
  612. if err != nil {
  613. return xerr.WithStack(err)
  614. }
  615. wg := sync.WaitGroup{}
  616. wg.Add(len(distributeData.PastureList))
  617. var muError error
  618. for _, pasture := range distributeData.PastureList {
  619. go func(p *model.GroupPasture) {
  620. defer wg.Done()
  621. request := &model.DistributeFeedFormulaRequest{
  622. PastureId: p.Id,
  623. FeedFormula: distributeData.FeedFormulaList,
  624. FeedFormulaDetail: distributeData.FeedFormulaDetail,
  625. }
  626. response := &model.PastureResponse{}
  627. defer func() {
  628. if response.Code == http.StatusOK {
  629. s.DB.Create(model.NewFeedFormulaDistributeLogList(distributeData.FeedFormulaList, p.Id, p.Name, operationPb.IsShow_OK))
  630. } else {
  631. muError = multierr.Append(muError, xerr.Custom(response.Msg))
  632. }
  633. }()
  634. if _, err = s.PastureHttpClient(ctx, model.FeedFormulaDistributeUrl, p.Id, request, response); err != nil {
  635. muError = multierr.Append(muError, err)
  636. zaplog.Error("DistributeFeedFormula", zap.Any("pasture", p), zap.Any("body", distributeData.FeedFormulaList), zap.Any("err", err), zap.Any("response", response))
  637. b, _ := json.Marshal(request)
  638. res, _ := json.Marshal(response)
  639. pastureDataLog := model.NewPastureDataLog(p.Id, PastureDataLogType["FeedFormula_Distribute"], model.FeedFormulaDistributeUrl, string(b), string(res))
  640. s.DB.Create(pastureDataLog)
  641. }
  642. }(pasture)
  643. }
  644. wg.Wait()
  645. return muError
  646. }
  647. // CancelDistributeFeedFormula 取消配方下发牧场
  648. func (s *StoreEntry) CancelDistributeFeedFormula(ctx context.Context, req *operationPb.DistributeFeedFormulaRequest) error {
  649. distributeData, err := s.checkoutDistributeData(ctx, req)
  650. if err != nil {
  651. return xerr.WithStack(err)
  652. }
  653. wg := sync.WaitGroup{}
  654. wg.Add(len(distributeData.PastureList))
  655. var muError error
  656. for _, pasture := range distributeData.PastureList {
  657. go func(p *model.GroupPasture) {
  658. defer wg.Done()
  659. pastureDataId := make([]int64, 0)
  660. for _, v := range distributeData.FeedFormulaList {
  661. if v.PastureId == p.Id {
  662. pastureDataId = append(pastureDataId, v.PastureDataId)
  663. }
  664. }
  665. if len(pastureDataId) <= 0 {
  666. return
  667. }
  668. request := &model.CancelDistributeFeedFormulaRequest{
  669. PastureId: p.Id,
  670. PastureDataId: pastureDataId,
  671. }
  672. response := &model.PastureResponse{}
  673. if _, err = s.PastureHttpClient(ctx, model.FeedFormulaCancelDistributeUrl, p.Id, request, response); err != nil {
  674. zaplog.Error("DistributeFeedFormula", zap.Any("pasture", p), zap.Any("body", distributeData.FeedFormulaList), zap.Any("err", err), zap.Any("response", response))
  675. b, _ := json.Marshal(request)
  676. res, _ := json.Marshal(response)
  677. pastureDataLog := model.NewPastureDataLog(p.Id, PastureDataLogType["FeedFormula_Cancel_Distribute"], model.FeedFormulaCancelDistributeUrl, string(b), string(res))
  678. s.DB.Create(pastureDataLog)
  679. }
  680. }(pasture)
  681. }
  682. wg.Wait()
  683. return muError
  684. }
  685. // EditRecodeFeedFormula 配方修改记录
  686. func (s *StoreEntry) EditRecodeFeedFormula(ctx context.Context, req *operationPb.EditRecodeFeedFormulaRequest) (*operationPb.EditRecodeFeedFormulaResponse, error) {
  687. feedFormulaData := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  688. if err := s.DB.Model(new(model.FeedFormula)).First(feedFormulaData).Error; err != nil {
  689. return nil, xerr.WithStack(err)
  690. }
  691. res := &operationPb.EditRecodeFeedFormulaResponse{
  692. Code: http.StatusOK,
  693. Msg: "ok",
  694. Data: make([]*operationPb.EditRecodeFeedFormulaData, 0),
  695. }
  696. feedFormulaEditRecordList := make([]*model.FeedFormulaEditRecord, 0)
  697. pref := s.DB.Model(new(model.FeedFormulaEditRecord)).Where("status > 0").Where("feed_formula_id = ?", req.FeedFormulaId)
  698. if req.PastureId > 0 {
  699. pref.Where("pasture_id = ?", req.PastureId)
  700. }
  701. if req.StartTime > 0 && req.EndTime > 0 && req.EndTime >= req.StartTime {
  702. pref.Where("created_at >= ?", req.StartTime).Where("created_at <= ?", req.EndTime)
  703. }
  704. if err := pref.Order("group_id").Find(&feedFormulaEditRecordList).Error; err != nil {
  705. return res, xerr.WithStack(err)
  706. }
  707. groupByFeedFormulaEditRecordList := make(map[int64][]*model.FeedFormulaEditRecord)
  708. for _, v := range feedFormulaEditRecordList {
  709. if groupByFeedFormulaEditRecordList[v.GroupId] == nil {
  710. groupByFeedFormulaEditRecordList[v.GroupId] = make([]*model.FeedFormulaEditRecord, 0)
  711. }
  712. groupByFeedFormulaEditRecordList[v.GroupId] = append(groupByFeedFormulaEditRecordList[v.GroupId], v)
  713. }
  714. editRecodeFeedFormulaDataList := make([]*operationPb.EditRecodeFeedFormulaData, 0)
  715. for _, data := range groupByFeedFormulaEditRecordList {
  716. var modifyDetail = ""
  717. var pastureId int32 = 0
  718. var pastureName = ""
  719. var createTime int64 = 0
  720. for i, v := range data {
  721. if i == 0 {
  722. modifyDetail += fmt.Sprintf("%s\n ", v.PastureName)
  723. pastureId = int32(v.PastureId)
  724. pastureName = v.PastureName
  725. createTime = v.CreatedAt
  726. }
  727. switch v.Status {
  728. case operationPb.FeedFormulaEditRecordType_INSERT:
  729. modifyDetail += fmt.Sprintf(`%s新增了饲料%s\n `, v.OperationName, v.ForageName)
  730. case operationPb.FeedFormulaEditRecordType_UPDATE:
  731. modifyDetail += fmt.Sprintf(`%s将%s的%s"%s"更新为"%s"\n `, v.OperationName, v.ForageName, v.FieldName, v.BeforeValue, v.AfterValue)
  732. case operationPb.FeedFormulaEditRecordType_DELETE:
  733. modifyDetail += fmt.Sprintf(`%s删除了%s\n `, v.OperationName, v.ForageName)
  734. }
  735. }
  736. editRecodeFeedFormulaDataList = append(editRecodeFeedFormulaDataList, &operationPb.EditRecodeFeedFormulaData{
  737. PastureId: pastureId,
  738. PastureName: pastureName,
  739. ModifyTime: time.Unix(createTime, 0).Format(model.LayoutTime),
  740. ModifyDetail: modifyDetail,
  741. })
  742. }
  743. res.Data = editRecodeFeedFormulaDataList
  744. return res, nil
  745. }
  746. func (s *StoreEntry) FeedFormulaDetailList(ctx context.Context, req *operationPb.FeedFormulaDetailRequest) (*operationPb.FeedFormulaDetailResponse, error) {
  747. res := &operationPb.FeedFormulaDetailResponse{
  748. Code: http.StatusOK,
  749. Msg: "ok",
  750. Data: make([]*operationPb.AddFeedFormulaDetail, 0),
  751. }
  752. feedFormula, err := s.SearchFeedFormulaById(ctx, int64(req.FeedFormulaId))
  753. if err != nil {
  754. return nil, xerr.WithStack(err)
  755. }
  756. feedFormulaId := feedFormula.Id
  757. if feedFormula.PastureDataId > 0 {
  758. feedFormulaId = feedFormula.PastureDataId
  759. }
  760. list, err := s.SearchFeedFormalDetailById(ctx, feedFormulaId, feedFormula.PastureId)
  761. if err != nil {
  762. return nil, xerr.WithStack(err)
  763. }
  764. if len(list) <= 0 {
  765. list, err = s.SearchFeedFormalDetailById(ctx, feedFormula.Id, 0)
  766. if err != nil {
  767. return nil, xerr.WithStack(err)
  768. }
  769. }
  770. res.Data = model.FeedFormulaDetailSlice(list).ToPB()
  771. return res, nil
  772. }
  773. // FeedFormulaUsage 配方使用概况
  774. func (s *StoreEntry) FeedFormulaUsage(ctx context.Context, req *operationPb.FeedFormulaUsageRequest) (*operationPb.FeedFormulaUsageResponse, error) {
  775. feedFormulaDistributeLogList := make([]*model.FeedFormulaDistributeLog, 0)
  776. if err := s.DB.Model(new(model.FeedFormulaDistributeLog)).
  777. Where("feed_formula_id = ?", req.FeedFormulaId).
  778. Where("is_show = ?", operationPb.IsShow_OK).Group("pasture_id").
  779. Find(&feedFormulaDistributeLogList).Error; err != nil {
  780. return nil, xerr.WithStack(err)
  781. }
  782. res := &operationPb.FeedFormulaUsageResponse{
  783. Code: http.StatusOK,
  784. Msg: "ok",
  785. Data: make([]*operationPb.FeedFormulaUsageList, 0),
  786. }
  787. wg := sync.WaitGroup{}
  788. wg.Add(len(feedFormulaDistributeLogList))
  789. for _, list := range feedFormulaDistributeLogList {
  790. go func(l *model.FeedFormulaDistributeLog) {
  791. defer wg.Done()
  792. groupDetail, err := s.PastureDetailById(ctx, l.PastureId)
  793. if err != nil {
  794. zaplog.Error("FeedFormulaUsage", zap.Any("PastureDetailById", err))
  795. return
  796. }
  797. req.PastureId = int32(groupDetail.PastureId)
  798. response := &operationPb.PastureFeedFormulaUsageResponse{}
  799. if _, err = s.PastureHttpClient(ctx, model.FeedUsageURl, groupDetail.Id, req, response); err != nil {
  800. zaplog.Error("FeedFormulaUsage", zap.Any("PastureDetailById", err))
  801. return
  802. }
  803. if response.Code == http.StatusOK {
  804. data := &operationPb.FeedFormulaUsageList{
  805. PastureId: int32(groupDetail.Id),
  806. PastureName: groupDetail.Name,
  807. MixedFodderAccurateRatio: response.Data.MixedFodderAccurateRatio,
  808. MixedFodderCorrectRatio: response.Data.MixedFodderCorrectRatio,
  809. SprinkleFodderAccurateRatio: response.Data.SprinkleFodderAccurateRatio,
  810. SprinkleFodderCorrectRatio: response.Data.SprinkleFodderCorrectRatio,
  811. AddFeedTime: response.Data.AddFeedTime,
  812. SprinkleTime: response.Data.SprinkleTime,
  813. StirTime: response.Data.StirTime,
  814. LastEditTime: response.Data.LastEditTime,
  815. }
  816. res.Data = append(res.Data, data)
  817. } else {
  818. zaplog.Error("FeedFormulaUsage-http", zap.Any("response", response))
  819. return
  820. }
  821. }(list)
  822. }
  823. wg.Wait()
  824. return res, nil
  825. }
  826. func (s *StoreEntry) PastureFeedFormulaIsModify(ctx context.Context, feedFormulaId int32, isModify operationPb.IsShow_Kind) {
  827. feedFormulaDistributeLogList := make([]*model.FeedFormulaDistributeLog, 0)
  828. if err := s.DB.Where("is_show = ?", operationPb.IsShow_OK).
  829. Where("feed_formula_id = ?", feedFormulaId).
  830. Group("pasture_id").Find(&feedFormulaDistributeLogList).Error; err != nil {
  831. zaplog.Error("PastureFeedFormulaIsModify", zap.Any("err", err), zap.Any("feed_formula_id", feedFormulaId))
  832. return
  833. }
  834. for _, v := range feedFormulaDistributeLogList {
  835. response := &model.PastureResponse{}
  836. request := &model.FeedFormulaIsModifyRequest{
  837. PastureId: v.PastureId,
  838. FeedFormulaId: v.FeedFormulaId,
  839. IsModify: int32(isModify),
  840. }
  841. if _, err := s.PastureHttpClient(ctx, model.FeedFormulaIsModifyUrl, v.Id, request, response); err != nil {
  842. zaplog.Error("PastureFeedFormulaIsModify", zap.Any("request", request), zap.Any("err", err), zap.Any("response", response))
  843. b, _ := json.Marshal(request)
  844. res, _ := json.Marshal(response)
  845. pastureDataLog := model.NewPastureDataLog(v.PastureId, PastureDataLogType["FeedFormula_IsModify"], model.FeedFormulaIsModifyUrl, string(b), string(res))
  846. s.DB.Create(pastureDataLog)
  847. }
  848. }
  849. }
  850. func (s *StoreEntry) checkoutDistributeData(ctx context.Context, req *operationPb.DistributeFeedFormulaRequest) (*model.DistributeData, error) {
  851. result := &model.DistributeData{
  852. PastureList: make([]*model.GroupPasture, 0),
  853. FeedFormulaList: make([]*model.FeedFormula, 0),
  854. FeedFormulaDetail: make([]*model.FeedFormulaDetail, 0),
  855. }
  856. if err := s.DB.Where("id IN ?", req.PastureIds).Where("is_delete = ?", operationPb.IsShow_OK).Find(&result.PastureList).Error; err != nil {
  857. return result, xerr.WithStack(err)
  858. }
  859. if err := s.DB.Where("id IN ?", req.FeedFormulaIds).Find(&result.FeedFormulaList).Error; err != nil {
  860. return result, xerr.WithStack(err)
  861. }
  862. feedFormulaDetailList := make([]*model.FeedFormulaDetail, 0)
  863. for _, v := range req.FeedFormulaIds {
  864. feedFormulaDetail := make([]*model.FeedFormulaDetail, 0)
  865. if err := s.DB.Model(new(model.FeedFormulaDetail)).Where("feed_formula_id = ?", v).Find(&feedFormulaDetail).Error; err != nil {
  866. if errors.Is(err, gorm.ErrRecordNotFound) {
  867. return result, xerr.Customf("该配方没有添加相关饲料:%d", v)
  868. }
  869. return result, xerr.WithStack(err)
  870. } else {
  871. feedFormulaDetailList = append(feedFormulaDetailList, feedFormulaDetail...)
  872. }
  873. }
  874. result.FeedFormulaDetail = feedFormulaDetailList
  875. if len(result.PastureList) <= 0 || len(result.FeedFormulaList) <= 0 {
  876. return result, xerr.Customf("数据错误")
  877. }
  878. return result, nil
  879. }
  880. func (s *StoreEntry) checkoutDistributeLog(ctx context.Context, pastureId, feedFormulaId int64) bool {
  881. res := &model.FeedFormulaDistributeLog{}
  882. if err := s.DB.Model(new(model.FeedFormulaDistributeLog)).Where("feed_formula_id = ?", feedFormulaId).
  883. Where("pasture_id = ?", pastureId).Where("is_show = ?", operationPb.IsShow_OK).First(res).Error; err != nil {
  884. return false
  885. }
  886. if res.IsShow == operationPb.IsShow_OK {
  887. return true
  888. }
  889. return false
  890. }
  891. func (s *StoreEntry) SearchFeedFormalDetailById(ctx context.Context, feedFormulaId, pastureId int64) ([]*model.FeedFormulaDetail, error) {
  892. res := make([]*model.FeedFormulaDetail, 0)
  893. if err := s.DB.Model(new(model.FeedFormulaDetail)).Where("pasture_id = ?", pastureId).
  894. Where("feed_formula_id = ?", feedFormulaId).
  895. Where("is_show = ?", operationPb.IsShow_OK).
  896. Order("id desc").Find(&res).Error; err != nil {
  897. return nil, xerr.WithStack(err)
  898. }
  899. return res, nil
  900. }