feed_service.go 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  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. feedFormulaData := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  327. if err := s.DB.Model(new(model.FeedFormula)).First(feedFormulaData).Error; err != nil {
  328. return xerr.WithStack(err)
  329. }
  330. if feedFormulaData.FormulaTypeId == operationPb.FormulaType_PREMIXED_FORMULA {
  331. return xerr.Customf("预混料配方不能合成预混料")
  332. }
  333. tr := s.DB.Transaction(func(tx *gorm.DB) error {
  334. newFeedFormulaData := &model.FeedFormula{
  335. Name: req.Name,
  336. Colour: req.Colour,
  337. EncodeNumber: s.EncodeNumber(ctx),
  338. CattleCategoryId: operationPb.CattleCategoryParent_Kind(req.CattleCategoryId),
  339. CattleCategoryName: req.CattleCategoryName,
  340. FormulaTypeId: req.FormulaTypeId,
  341. FormulaTypeName: req.FormulaTypeName,
  342. DataSourceId: operationPb.DataSource_Kind(req.DataSourceId),
  343. DataSourceName: operationPb.DataSource_Kind_name[req.DataSourceId],
  344. Remarks: req.Remarks,
  345. PastureName: "集团",
  346. IsShow: operationPb.IsShow_OK,
  347. IsModify: operationPb.IsShow_OK,
  348. IsDelete: operationPb.IsShow_OK,
  349. }
  350. if err := s.DB.Model(new(model.FeedFormula)).Create(newFeedFormulaData).Error; err != nil {
  351. return xerr.WithStack(err)
  352. }
  353. feedFormulaDetailList := make([]*model.FeedFormulaDetail, 0)
  354. for _, v := range req.FeedList {
  355. feedFormulaDetailList = append(feedFormulaDetailList, &model.FeedFormulaDetail{
  356. PastureName: "集团",
  357. FeedFormulaId: newFeedFormulaData.Id,
  358. ForageId: int64(v.ForageId),
  359. ForageName: v.ForageName,
  360. ForageGroupName: v.ForageGroupName,
  361. Weight: int32(v.Weight * 100),
  362. StirDelay: v.StirDelay,
  363. AllowError: v.AllowError,
  364. IsShow: operationPb.IsShow_OK,
  365. Sort: v.Sort,
  366. })
  367. }
  368. if err := s.DB.Model(new(model.FeedFormulaDetail)).Save(feedFormulaDetailList).Error; err != nil {
  369. return xerr.WithStack(err)
  370. }
  371. return nil
  372. })
  373. return tr
  374. }
  375. // SearchFeedFormulaList 查询数据列表
  376. func (s *StoreEntry) SearchFeedFormulaList(ctx context.Context, req *operationPb.SearchFeedFormulaRequest) (*operationPb.SearchFeedFormulaListResponse, error) {
  377. feedFormula := make([]*model.FeedFormula, 0)
  378. var count int64 = 0
  379. pref := s.DB.Model(new(model.FeedFormula)).Where("is_delete = ?", operationPb.IsShow_OK)
  380. if req.Name != "" {
  381. pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%"))
  382. }
  383. if req.CattleCategoryId > 0 {
  384. pref.Where("cattle_category_id = ?", req.CattleCategoryId)
  385. }
  386. if req.FormulaTypeId > 0 {
  387. pref.Where("formula_type_id = ?", req.FormulaTypeId)
  388. }
  389. if req.IsShow > 0 {
  390. pref.Where("is_show = ?", req.IsShow)
  391. }
  392. if req.DataSource > 0 {
  393. pref.Where("data_source = ?", req.DataSource)
  394. }
  395. if req.Remarks != "" {
  396. pref.Where("remarks = ?", req.Remarks)
  397. }
  398. if err := pref.Order("id desc").Count(&count).Limit(int(req.Pagination.PageSize)).Offset(int(req.Pagination.PageOffset)).
  399. Find(&feedFormula).Error; err != nil {
  400. return nil, xerr.WithStack(err)
  401. }
  402. return &operationPb.SearchFeedFormulaListResponse{
  403. Code: http.StatusOK,
  404. Msg: "ok",
  405. Data: &operationPb.SearchFeedFormulaListData{
  406. Page: req.Pagination.Page,
  407. PageSize: req.Pagination.PageSize,
  408. Total: int32(count),
  409. List: model.FeedFormulaSlice(feedFormula).ToPB(),
  410. },
  411. }, nil
  412. }
  413. // SearchFeedFormulaById 查询指定数据
  414. func (s *StoreEntry) SearchFeedFormulaById(ctx context.Context, foodFormulaId int64) (*model.FeedFormula, error) {
  415. feedFormula := &model.FeedFormula{}
  416. if err := s.DB.Model(new(model.FeedFormula)).
  417. Where("is_delete = ?", operationPb.IsShow_OK).
  418. Where("id = ?", foodFormulaId).
  419. First(feedFormula).Error; err != nil {
  420. return nil, xerr.WithStack(err)
  421. }
  422. return feedFormula, nil
  423. }
  424. // IsShowFeedFormula 是否启用和是否可修改
  425. func (s *StoreEntry) IsShowFeedFormula(ctx context.Context, req *operationPb.IsShowModifyFeedFormula) error {
  426. feedFormula := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  427. if err := s.DB.First(feedFormula).Error; err != nil {
  428. if errors.Is(err, gorm.ErrRecordNotFound) {
  429. return xerr.Custom("该数据不存在")
  430. }
  431. return xerr.WithStack(err)
  432. }
  433. if req.EditType == 1 {
  434. if err := s.DB.Model(new(model.FeedFormula)).Where("id = ?", req.FeedFormulaId).Update("is_show", req.IsShow).Error; err != nil {
  435. return xerr.WithStack(err)
  436. }
  437. }
  438. if req.EditType == 2 {
  439. if err := s.DB.Model(new(model.FeedFormula)).Where("id = ?", req.FeedFormulaId).Update("is_modify", req.IsShow).Error; err != nil {
  440. return xerr.WithStack(err)
  441. } else {
  442. s.PastureFeedFormulaIsModify(ctx, req.FeedFormulaId, req.IsShow)
  443. }
  444. }
  445. return nil
  446. }
  447. // DeleteFeedFormula 是否删除
  448. func (s *StoreEntry) DeleteFeedFormula(ctx context.Context, feedFormulaId int64) error {
  449. feedFormula := &model.FeedFormula{Id: feedFormulaId}
  450. if err := s.DB.First(feedFormula).Error; err != nil {
  451. if errors.Is(err, gorm.ErrRecordNotFound) {
  452. return xerr.Custom("该数据不存在")
  453. }
  454. return xerr.WithStack(err)
  455. }
  456. if err := s.DB.Model(new(model.FeedFormula)).Where("id = ?", feedFormula.Id).Update("is_delete", operationPb.IsShow_NO).Error; err != nil {
  457. return xerr.WithStack(err)
  458. }
  459. return nil
  460. }
  461. // ExcelImportFeedFormula 导入excel
  462. func (s *StoreEntry) ExcelImportFeedFormula(ctx context.Context, req io.Reader) error {
  463. xlsx, err := excelize.OpenReader(req)
  464. if err != nil {
  465. return xerr.WithStack(err)
  466. }
  467. defer xlsx.Close()
  468. rows, err := xlsx.GetRows(xlsx.GetSheetName(xlsx.GetActiveSheetIndex()))
  469. if err != nil {
  470. return xerr.WithStack(err)
  471. }
  472. if len(rows) > 10000 {
  473. rows = rows[:10000]
  474. }
  475. feedFormulaList := make([]*model.FeedFormula, 0)
  476. for i, row := range rows {
  477. if i == 0 {
  478. continue
  479. }
  480. var (
  481. name, encodeNumber, cattleCategoryName, formulaTypeName, dataSourceName, remarks, isShowStr string
  482. isShow operationPb.IsShow_Kind
  483. )
  484. for k, v := range row {
  485. if k == 0 {
  486. name = v
  487. }
  488. if k == 1 {
  489. encodeNumber = v
  490. }
  491. if k == 2 {
  492. cattleCategoryName = v
  493. }
  494. if k == 3 {
  495. formulaTypeName = v
  496. }
  497. if k == 4 {
  498. dataSourceName = v
  499. }
  500. if k == 5 {
  501. remarks = v
  502. }
  503. if k == 6 {
  504. isShowStr = v
  505. }
  506. }
  507. if isShowStr == "是" {
  508. isShow = operationPb.IsShow_OK
  509. } else {
  510. isShow = operationPb.IsShow_NO
  511. }
  512. feedFormulaItem := &model.FeedFormula{
  513. Name: name,
  514. EncodeNumber: encodeNumber,
  515. CattleCategoryName: cattleCategoryName,
  516. FormulaTypeName: formulaTypeName,
  517. Remarks: remarks,
  518. IsShow: isShow,
  519. IsDelete: operationPb.IsShow_OK,
  520. DataSourceId: operationPb.DataSource_EXCEL_IMPORT,
  521. DataSourceName: dataSourceName,
  522. }
  523. feedFormulaList = append(feedFormulaList, feedFormulaItem)
  524. }
  525. if len(feedFormulaList) > 0 {
  526. if err = s.DB.Create(feedFormulaList).Error; err != nil {
  527. return xerr.WithStack(err)
  528. }
  529. }
  530. return nil
  531. }
  532. // ExcelExportFeedFormula 流式导出excel
  533. func (s *StoreEntry) ExcelExportFeedFormula(ctx context.Context, req *operationPb.SearchFeedFormulaRequest) (*bytes.Buffer, error) {
  534. res, err := s.SearchFeedFormulaList(ctx, req)
  535. if err != nil {
  536. return nil, xerr.WithStack(err)
  537. }
  538. if len(res.Data.List) <= 0 {
  539. return nil, xerr.Custom("数据为空")
  540. }
  541. file := excelize.NewFile()
  542. defer file.Close()
  543. streamWriter, err := file.NewStreamWriter("Sheet1")
  544. if err != nil {
  545. return nil, xerr.WithStack(err)
  546. }
  547. titles := []interface{}{"配方名称", "配方编码", "畜牧类别", "配方类别", "来源", "备注", "是否启用",
  548. "饲料组", "饲料名称", "重量(kg)", "搅拌延迟(min)", "是否锁定牛头数比例", "顺序"}
  549. if err = streamWriter.SetRow("A1", titles); err != nil {
  550. return nil, xerr.WithStack(err)
  551. }
  552. for i, item := range res.Data.List {
  553. cell, err := excelize.CoordinatesToCellName(1, i+2)
  554. if err != nil {
  555. zaplog.Error("exclude CoordinatesToCellName", zap.Any("Err", err))
  556. continue
  557. }
  558. row := make([]interface{}, 0)
  559. row = append(row, item.Name, item.EncodeNumber, item.CattleCategoryName, item.FormulaTypeName, item.DataSourceName,
  560. item.Remarks, item.IsShow)
  561. if err = streamWriter.SetRow(cell, row); err != nil {
  562. return nil, xerr.WithStack(err)
  563. }
  564. }
  565. if err = streamWriter.Flush(); err != nil {
  566. return nil, xerr.WithStack(err)
  567. }
  568. return file.WriteToBuffer()
  569. }
  570. // ExcelTemplateFeedFormula 导出模板
  571. func (s *StoreEntry) ExcelTemplateFeedFormula(ctx context.Context) (*bytes.Buffer, error) {
  572. file := excelize.NewFile()
  573. defer file.Close()
  574. streamWriter, err := file.NewStreamWriter("Sheet1")
  575. if err != nil {
  576. return nil, xerr.WithStack(err)
  577. }
  578. titles := []interface{}{"配方名称", "配方编码", "畜牧类别", "配方类别", "来源", "备注", "是否启用",
  579. "饲料组", "饲料名称", "重量(kg)", "搅拌延迟(min)", "是否锁定牛头数比例", "顺序"}
  580. if err = streamWriter.SetRow("A1", titles); err != nil {
  581. return nil, xerr.WithStack(err)
  582. }
  583. if err = streamWriter.Flush(); err != nil {
  584. return nil, xerr.WithStack(err)
  585. }
  586. return file.WriteToBuffer()
  587. }
  588. // EncodeNumber 配方编码
  589. func (s *StoreEntry) EncodeNumber(ctx context.Context) string {
  590. currTime := time.Now().Format(model.LayoutDate)
  591. prefix := fmt.Sprintf("%s_%s", EncodeNumberPrefix, currTime)
  592. data := &model.UniqueData{}
  593. if err := s.DB.Order("id desc").Where("prefix = ?", prefix).First(data).Error; err != nil {
  594. if !errors.Is(err, gorm.ErrRecordNotFound) {
  595. return ""
  596. }
  597. ud, _ := strconv.Atoi(currTime)
  598. result := ud*100 + 1
  599. newData := &model.UniqueData{
  600. Prefix: prefix,
  601. Data: int64(result),
  602. }
  603. if err = s.DB.Create(newData).Error; err != nil {
  604. zaplog.Error("EncodeNumber Create", zap.Any("data", newData), zap.Any("Err", err))
  605. return ""
  606. }
  607. return fmt.Sprintf("%d", newData.Data)
  608. }
  609. data.Data += 1
  610. if err := s.DB.Model(new(model.UniqueData)).Where("prefix = ?", prefix).Update("data", data.Data).Error; err != nil {
  611. return ""
  612. } else {
  613. return fmt.Sprintf("%d", data.Data)
  614. }
  615. }
  616. // DistributeFeedFormula 配方下发牧场
  617. func (s *StoreEntry) DistributeFeedFormula(ctx context.Context, req *operationPb.DistributeFeedFormulaRequest) error {
  618. distributeData, err := s.checkoutDistributeData(ctx, req)
  619. if err != nil {
  620. return xerr.WithStack(err)
  621. }
  622. wg := sync.WaitGroup{}
  623. wg.Add(len(distributeData.PastureList))
  624. var muError error
  625. for _, pasture := range distributeData.PastureList {
  626. go func(p *model.GroupPasture) {
  627. defer wg.Done()
  628. request := &model.DistributeFeedFormulaRequest{
  629. PastureId: p.Id,
  630. FeedFormula: distributeData.FeedFormulaList,
  631. FeedFormulaDetail: distributeData.FeedFormulaDetail,
  632. }
  633. response := &model.PastureResponse{}
  634. defer func() {
  635. if response.Code == http.StatusOK {
  636. s.DB.Create(model.NewFeedFormulaDistributeLogList(distributeData.FeedFormulaList, p.Id, p.Name, operationPb.IsShow_OK))
  637. } else {
  638. muError = multierr.Append(muError, xerr.Custom(response.Msg))
  639. }
  640. }()
  641. if _, err = s.PastureHttpClient(ctx, model.FeedFormulaDistributeUrl, p.Id, request, response); err != nil {
  642. muError = multierr.Append(muError, err)
  643. zaplog.Error("DistributeFeedFormula", zap.Any("pasture", p), zap.Any("body", distributeData.FeedFormulaList), zap.Any("err", err), zap.Any("response", response))
  644. b, _ := json.Marshal(request)
  645. res, _ := json.Marshal(response)
  646. pastureDataLog := model.NewPastureDataLog(p.Id, PastureDataLogType["FeedFormula_Distribute"], model.FeedFormulaDistributeUrl, string(b), string(res))
  647. s.DB.Create(pastureDataLog)
  648. }
  649. }(pasture)
  650. }
  651. wg.Wait()
  652. return muError
  653. }
  654. // CancelDistributeFeedFormula 取消配方下发牧场
  655. func (s *StoreEntry) CancelDistributeFeedFormula(ctx context.Context, req *operationPb.DistributeFeedFormulaRequest) error {
  656. distributeData, err := s.checkoutDistributeData(ctx, req)
  657. if err != nil {
  658. return xerr.WithStack(err)
  659. }
  660. wg := sync.WaitGroup{}
  661. wg.Add(len(distributeData.PastureList))
  662. var muError error
  663. for _, pasture := range distributeData.PastureList {
  664. go func(p *model.GroupPasture) {
  665. defer wg.Done()
  666. pastureDataId := make([]int64, 0)
  667. for _, v := range distributeData.FeedFormulaList {
  668. if v.PastureId == p.Id {
  669. pastureDataId = append(pastureDataId, v.PastureDataId)
  670. }
  671. }
  672. if len(pastureDataId) <= 0 {
  673. return
  674. }
  675. request := &model.CancelDistributeFeedFormulaRequest{
  676. PastureId: p.Id,
  677. PastureDataId: pastureDataId,
  678. }
  679. response := &model.PastureResponse{}
  680. if _, err = s.PastureHttpClient(ctx, model.FeedFormulaCancelDistributeUrl, p.Id, request, response); err != nil {
  681. zaplog.Error("DistributeFeedFormula", zap.Any("pasture", p), zap.Any("body", distributeData.FeedFormulaList), zap.Any("err", err), zap.Any("response", response))
  682. b, _ := json.Marshal(request)
  683. res, _ := json.Marshal(response)
  684. pastureDataLog := model.NewPastureDataLog(p.Id, PastureDataLogType["FeedFormula_Cancel_Distribute"], model.FeedFormulaCancelDistributeUrl, string(b), string(res))
  685. s.DB.Create(pastureDataLog)
  686. }
  687. }(pasture)
  688. }
  689. wg.Wait()
  690. return muError
  691. }
  692. // EditRecodeFeedFormula 配方修改记录
  693. func (s *StoreEntry) EditRecodeFeedFormula(ctx context.Context, req *operationPb.EditRecodeFeedFormulaRequest) (*operationPb.EditRecodeFeedFormulaResponse, error) {
  694. feedFormulaData := &model.FeedFormula{Id: int64(req.FeedFormulaId)}
  695. if err := s.DB.Model(new(model.FeedFormula)).First(feedFormulaData).Error; err != nil {
  696. return nil, xerr.WithStack(err)
  697. }
  698. res := &operationPb.EditRecodeFeedFormulaResponse{
  699. Code: http.StatusOK,
  700. Msg: "ok",
  701. Data: make([]*operationPb.EditRecodeFeedFormulaData, 0),
  702. }
  703. feedFormulaEditRecordList := make([]*model.FeedFormulaEditRecord, 0)
  704. pref := s.DB.Model(new(model.FeedFormulaEditRecord)).Where("status > 0").Where("feed_formula_id = ?", req.FeedFormulaId)
  705. if req.PastureId > 0 {
  706. pref.Where("pasture_id = ?", req.PastureId)
  707. }
  708. if req.StartTime > 0 && req.EndTime > 0 && req.EndTime >= req.StartTime {
  709. pref.Where("created_at >= ?", req.StartTime).Where("created_at <= ?", req.EndTime)
  710. }
  711. if err := pref.Order("group_id").Find(&feedFormulaEditRecordList).Error; err != nil {
  712. return res, xerr.WithStack(err)
  713. }
  714. groupByFeedFormulaEditRecordList := make(map[int64][]*model.FeedFormulaEditRecord)
  715. for _, v := range feedFormulaEditRecordList {
  716. if groupByFeedFormulaEditRecordList[v.GroupId] == nil {
  717. groupByFeedFormulaEditRecordList[v.GroupId] = make([]*model.FeedFormulaEditRecord, 0)
  718. }
  719. groupByFeedFormulaEditRecordList[v.GroupId] = append(groupByFeedFormulaEditRecordList[v.GroupId], v)
  720. }
  721. editRecodeFeedFormulaDataList := make([]*operationPb.EditRecodeFeedFormulaData, 0)
  722. for _, data := range groupByFeedFormulaEditRecordList {
  723. var modifyDetail = ""
  724. var pastureId int32 = 0
  725. var pastureName = ""
  726. var createTime int64 = 0
  727. for i, v := range data {
  728. if i == 0 {
  729. modifyDetail += fmt.Sprintf("%s\n ", v.PastureName)
  730. pastureId = int32(v.PastureId)
  731. pastureName = v.PastureName
  732. createTime = v.CreatedAt
  733. }
  734. switch v.Status {
  735. case operationPb.FeedFormulaEditRecordType_INSERT:
  736. modifyDetail += fmt.Sprintf(`%s新增了饲料%s\n `, v.OperationName, v.ForageName)
  737. case operationPb.FeedFormulaEditRecordType_UPDATE:
  738. modifyDetail += fmt.Sprintf(`%s将%s的%s"%s"更新为"%s"\n `, v.OperationName, v.ForageName, v.FieldName, v.BeforeValue, v.AfterValue)
  739. case operationPb.FeedFormulaEditRecordType_DELETE:
  740. modifyDetail += fmt.Sprintf(`%s删除了%s\n `, v.OperationName, v.ForageName)
  741. }
  742. }
  743. editRecodeFeedFormulaDataList = append(editRecodeFeedFormulaDataList, &operationPb.EditRecodeFeedFormulaData{
  744. PastureId: pastureId,
  745. PastureName: pastureName,
  746. ModifyTime: time.Unix(createTime, 0).Format(model.LayoutTime),
  747. ModifyDetail: modifyDetail,
  748. })
  749. }
  750. res.Data = editRecodeFeedFormulaDataList
  751. return res, nil
  752. }
  753. func (s *StoreEntry) FeedFormulaDetailList(ctx context.Context, req *operationPb.FeedFormulaDetailRequest) (*operationPb.FeedFormulaDetailResponse, error) {
  754. res := &operationPb.FeedFormulaDetailResponse{
  755. Code: http.StatusOK,
  756. Msg: "ok",
  757. Data: make([]*operationPb.AddFeedFormulaDetail, 0),
  758. }
  759. feedFormula, err := s.SearchFeedFormulaById(ctx, int64(req.FeedFormulaId))
  760. if err != nil {
  761. return nil, xerr.WithStack(err)
  762. }
  763. feedFormulaId := feedFormula.Id
  764. if feedFormula.PastureDataId > 0 {
  765. feedFormulaId = feedFormula.PastureDataId
  766. }
  767. list, err := s.SearchFeedFormalDetailById(ctx, feedFormulaId, feedFormula.PastureId)
  768. if err != nil {
  769. return nil, xerr.WithStack(err)
  770. }
  771. if len(list) <= 0 {
  772. list, err = s.SearchFeedFormalDetailById(ctx, feedFormula.Id, 0)
  773. if err != nil {
  774. return nil, xerr.WithStack(err)
  775. }
  776. }
  777. res.Data = model.FeedFormulaDetailSlice(list).ToPB()
  778. return res, nil
  779. }
  780. // FeedFormulaUsage 配方使用概况
  781. func (s *StoreEntry) FeedFormulaUsage(ctx context.Context, req *operationPb.FeedFormulaUsageRequest) (*operationPb.FeedFormulaUsageResponse, error) {
  782. feedFormulaDistributeLogList := make([]*model.FeedFormulaDistributeLog, 0)
  783. if err := s.DB.Model(new(model.FeedFormulaDistributeLog)).
  784. Where("feed_formula_id = ?", req.FeedFormulaId).
  785. Where("is_show = ?", operationPb.IsShow_OK).Group("pasture_id").
  786. Find(&feedFormulaDistributeLogList).Error; err != nil {
  787. return nil, xerr.WithStack(err)
  788. }
  789. res := &operationPb.FeedFormulaUsageResponse{
  790. Code: http.StatusOK,
  791. Msg: "ok",
  792. Data: make([]*operationPb.FeedFormulaUsageList, 0),
  793. }
  794. wg := sync.WaitGroup{}
  795. wg.Add(len(feedFormulaDistributeLogList))
  796. for _, list := range feedFormulaDistributeLogList {
  797. go func(l *model.FeedFormulaDistributeLog) {
  798. defer wg.Done()
  799. groupDetail, err := s.PastureDetailById(ctx, l.PastureId)
  800. if err != nil {
  801. zaplog.Error("FeedFormulaUsage", zap.Any("PastureDetailById", err))
  802. return
  803. }
  804. req.PastureId = int32(groupDetail.PastureId)
  805. response := &operationPb.PastureFeedFormulaUsageResponse{}
  806. if _, err = s.PastureHttpClient(ctx, model.FeedUsageURl, groupDetail.Id, req, response); err != nil {
  807. zaplog.Error("FeedFormulaUsage", zap.Any("PastureDetailById", err))
  808. return
  809. }
  810. if response.Code == http.StatusOK {
  811. data := &operationPb.FeedFormulaUsageList{
  812. PastureId: int32(groupDetail.Id),
  813. PastureName: groupDetail.Name,
  814. MixedFodderAccurateRatio: response.Data.MixedFodderAccurateRatio,
  815. MixedFodderCorrectRatio: response.Data.MixedFodderCorrectRatio,
  816. SprinkleFodderAccurateRatio: response.Data.SprinkleFodderAccurateRatio,
  817. SprinkleFodderCorrectRatio: response.Data.SprinkleFodderCorrectRatio,
  818. AddFeedTime: response.Data.AddFeedTime,
  819. SprinkleTime: response.Data.SprinkleTime,
  820. StirTime: response.Data.StirTime,
  821. LastEditTime: response.Data.LastEditTime,
  822. }
  823. res.Data = append(res.Data, data)
  824. } else {
  825. zaplog.Error("FeedFormulaUsage-http", zap.Any("response", response))
  826. return
  827. }
  828. }(list)
  829. }
  830. wg.Wait()
  831. return res, nil
  832. }
  833. func (s *StoreEntry) PastureFeedFormulaIsModify(ctx context.Context, feedFormulaId int32, isModify operationPb.IsShow_Kind) {
  834. feedFormulaDistributeLogList := make([]*model.FeedFormulaDistributeLog, 0)
  835. if err := s.DB.Where("is_show = ?", operationPb.IsShow_OK).
  836. Where("feed_formula_id = ?", feedFormulaId).
  837. Group("pasture_id").Find(&feedFormulaDistributeLogList).Error; err != nil {
  838. zaplog.Error("PastureFeedFormulaIsModify", zap.Any("err", err), zap.Any("feed_formula_id", feedFormulaId))
  839. return
  840. }
  841. for _, v := range feedFormulaDistributeLogList {
  842. response := &model.PastureResponse{}
  843. request := &model.FeedFormulaIsModifyRequest{
  844. PastureId: v.PastureId,
  845. FeedFormulaId: v.FeedFormulaId,
  846. IsModify: int32(isModify),
  847. }
  848. if _, err := s.PastureHttpClient(ctx, model.FeedFormulaIsModifyUrl, v.Id, request, response); err != nil {
  849. zaplog.Error("PastureFeedFormulaIsModify", zap.Any("request", request), zap.Any("err", err), zap.Any("response", response))
  850. b, _ := json.Marshal(request)
  851. res, _ := json.Marshal(response)
  852. pastureDataLog := model.NewPastureDataLog(v.PastureId, PastureDataLogType["FeedFormula_IsModify"], model.FeedFormulaIsModifyUrl, string(b), string(res))
  853. s.DB.Create(pastureDataLog)
  854. }
  855. }
  856. }
  857. func (s *StoreEntry) checkoutDistributeData(ctx context.Context, req *operationPb.DistributeFeedFormulaRequest) (*model.DistributeData, error) {
  858. result := &model.DistributeData{
  859. PastureList: make([]*model.GroupPasture, 0),
  860. FeedFormulaList: make([]*model.FeedFormula, 0),
  861. FeedFormulaDetail: make([]*model.FeedFormulaDetail, 0),
  862. }
  863. if err := s.DB.Where("id IN ?", req.PastureIds).Where("is_delete = ?", operationPb.IsShow_OK).Find(&result.PastureList).Error; err != nil {
  864. return result, xerr.WithStack(err)
  865. }
  866. if err := s.DB.Where("id IN ?", req.FeedFormulaIds).Find(&result.FeedFormulaList).Error; err != nil {
  867. return result, xerr.WithStack(err)
  868. }
  869. feedFormulaDetailList := make([]*model.FeedFormulaDetail, 0)
  870. for _, v := range req.FeedFormulaIds {
  871. feedFormulaDetail := make([]*model.FeedFormulaDetail, 0)
  872. if err := s.DB.Model(new(model.FeedFormulaDetail)).Where("feed_formula_id = ?", v).Find(&feedFormulaDetail).Error; err != nil {
  873. if errors.Is(err, gorm.ErrRecordNotFound) {
  874. return result, xerr.Customf("该配方没有添加相关饲料:%d", v)
  875. }
  876. return result, xerr.WithStack(err)
  877. } else {
  878. feedFormulaDetailList = append(feedFormulaDetailList, feedFormulaDetail...)
  879. }
  880. }
  881. result.FeedFormulaDetail = feedFormulaDetailList
  882. if len(result.PastureList) <= 0 || len(result.FeedFormulaList) <= 0 {
  883. return result, xerr.Customf("数据错误")
  884. }
  885. return result, nil
  886. }
  887. func (s *StoreEntry) checkoutDistributeLog(ctx context.Context, pastureId, feedFormulaId int64) bool {
  888. res := &model.FeedFormulaDistributeLog{}
  889. if err := s.DB.Model(new(model.FeedFormulaDistributeLog)).Where("feed_formula_id = ?", feedFormulaId).
  890. Where("pasture_id = ?", pastureId).Where("is_show = ?", operationPb.IsShow_OK).First(res).Error; err != nil {
  891. return false
  892. }
  893. if res.IsShow == operationPb.IsShow_OK {
  894. return true
  895. }
  896. return false
  897. }
  898. func (s *StoreEntry) SearchFeedFormalDetailById(ctx context.Context, feedFormulaId, pastureId int64) ([]*model.FeedFormulaDetail, error) {
  899. res := make([]*model.FeedFormulaDetail, 0)
  900. if err := s.DB.Model(new(model.FeedFormulaDetail)).Where("pasture_id = ?", pastureId).
  901. Where("feed_formula_id = ?", feedFormulaId).
  902. Where("is_show = ?", operationPb.IsShow_OK).
  903. Order("id desc").Find(&res).Error; err != nil {
  904. return nil, xerr.WithStack(err)
  905. }
  906. return res, nil
  907. }