mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat(BE): recording
This commit is contained in:
@@ -11,8 +11,7 @@ type Recording struct {
|
|||||||
ProjectFlockKandangId uint `gorm:"column:project_flock_id;not null;index"`
|
ProjectFlockKandangId uint `gorm:"column:project_flock_id;not null;index"`
|
||||||
RecordDatetime time.Time `gorm:"column:record_datetime;not null"`
|
RecordDatetime time.Time `gorm:"column:record_datetime;not null"`
|
||||||
RecordDate *time.Time `gorm:"column:record_date"`
|
RecordDate *time.Time `gorm:"column:record_date"`
|
||||||
Status int `gorm:"column:status;not null;default:0"`
|
Ontime int `gorm:"column:ontime;not null;default:0"`
|
||||||
Ontime bool `gorm:"column:ontime;not null;default:false"`
|
|
||||||
Day *int `gorm:"column:day"`
|
Day *int `gorm:"column:day"`
|
||||||
TotalDepletion *int `gorm:"column:total_depletion"`
|
TotalDepletion *int `gorm:"column:total_depletion"`
|
||||||
CumDepletionRate *float64 `gorm:"column:cum_depletion_rate"`
|
CumDepletionRate *float64 `gorm:"column:cum_depletion_rate"`
|
||||||
|
|||||||
-1
@@ -67,7 +67,6 @@ func (r *projectFlockKandangRepositoryImpl) GetByID(ctx context.Context, id uint
|
|||||||
Preload("ProjectFlock").
|
Preload("ProjectFlock").
|
||||||
Preload("ProjectFlock.Flock").
|
Preload("ProjectFlock.Flock").
|
||||||
Preload("Kandang").
|
Preload("Kandang").
|
||||||
Preload("CreatedUser").
|
|
||||||
First(record, id).Error; err != nil {
|
First(record, id).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ func (u *RecordingController) GetOne(c *fiber.Ctx) error {
|
|||||||
Code: fiber.StatusOK,
|
Code: fiber.StatusOK,
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Message: "Get recording successfully",
|
Message: "Get recording successfully",
|
||||||
Data: dto.ToRecordingListDTO(*result),
|
Data: dto.ToRecordingDetailDTO(*result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ func (u *RecordingController) CreateOne(c *fiber.Ctx) error {
|
|||||||
Code: fiber.StatusCreated,
|
Code: fiber.StatusCreated,
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Message: "Create recording successfully",
|
Message: "Create recording successfully",
|
||||||
Data: dto.ToRecordingListDTO(*result),
|
Data: dto.ToRecordingDetailDTO(*result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ func (u *RecordingController) UpdateOne(c *fiber.Ctx) error {
|
|||||||
Code: fiber.StatusOK,
|
Code: fiber.StatusOK,
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Message: "Update recording successfully",
|
Message: "Update recording successfully",
|
||||||
Data: dto.ToRecordingListDTO(*result),
|
Data: dto.ToRecordingDetailDTO(*result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ type RecordingBaseDTO struct {
|
|||||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
||||||
RecordDatetime time.Time `json:"record_datetime"`
|
RecordDatetime time.Time `json:"record_datetime"`
|
||||||
RecordDate *time.Time `json:"record_date,omitempty"`
|
RecordDate *time.Time `json:"record_date,omitempty"`
|
||||||
Status int `json:"status"`
|
|
||||||
Ontime bool `json:"ontime"`
|
Ontime bool `json:"ontime"`
|
||||||
Day *int `json:"day,omitempty"`
|
Day *int `json:"day,omitempty"`
|
||||||
TotalDepletion *int `json:"total_depletion,omitempty"`
|
TotalDepletion *int `json:"total_depletion,omitempty"`
|
||||||
@@ -37,18 +36,51 @@ type RecordingListDTO struct {
|
|||||||
|
|
||||||
type RecordingDetailDTO struct {
|
type RecordingDetailDTO struct {
|
||||||
RecordingListDTO
|
RecordingListDTO
|
||||||
|
BodyWeights []RecordingBodyWeightDTO `json:"body_weights"`
|
||||||
|
Depletions []RecordingDepletionDTO `json:"depletions"`
|
||||||
|
Stocks []RecordingStockDTO `json:"stocks"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecordingBodyWeightDTO struct {
|
||||||
|
Weight float64 `json:"weight"`
|
||||||
|
Qty int `json:"qty"`
|
||||||
|
Notes *string `json:"notes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecordingDepletionDTO struct {
|
||||||
|
ProductWarehouseId uint `json:"product_warehouse_id"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
Notes *string `json:"notes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecordingStockDTO struct {
|
||||||
|
ProductWarehouseId uint `json:"product_warehouse_id"`
|
||||||
|
Increase *float64 `json:"increase,omitempty"`
|
||||||
|
Decrease *float64 `json:"decrease,omitempty"`
|
||||||
|
UsageAmount *int64 `json:"usage_amount,omitempty"`
|
||||||
|
Notes *string `json:"notes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Mapper Functions ===
|
// === Mapper Functions ===
|
||||||
|
|
||||||
func ToRecordingBaseDTO(e entity.Recording) RecordingBaseDTO {
|
func ToRecordingBaseDTO(e entity.Recording) RecordingBaseDTO {
|
||||||
|
recordDate := e.RecordDate
|
||||||
|
if recordDate == nil {
|
||||||
|
rd := time.Date(
|
||||||
|
e.RecordDatetime.Year(),
|
||||||
|
e.RecordDatetime.Month(),
|
||||||
|
e.RecordDatetime.Day(),
|
||||||
|
0, 0, 0, 0,
|
||||||
|
e.RecordDatetime.Location(),
|
||||||
|
)
|
||||||
|
recordDate = &rd
|
||||||
|
}
|
||||||
return RecordingBaseDTO{
|
return RecordingBaseDTO{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
ProjectFlockKandangId: e.ProjectFlockKandangId,
|
ProjectFlockKandangId: e.ProjectFlockKandangId,
|
||||||
RecordDatetime: e.RecordDatetime,
|
RecordDatetime: e.RecordDatetime,
|
||||||
RecordDate: e.RecordDate,
|
RecordDate: recordDate,
|
||||||
Status: e.Status,
|
Ontime: e.Ontime == 1,
|
||||||
Ontime: e.Ontime,
|
|
||||||
Day: e.Day,
|
Day: e.Day,
|
||||||
TotalDepletion: e.TotalDepletion,
|
TotalDepletion: e.TotalDepletion,
|
||||||
CumDepletionRate: e.CumDepletionRate,
|
CumDepletionRate: e.CumDepletionRate,
|
||||||
@@ -88,5 +120,46 @@ func ToRecordingListDTOs(e []entity.Recording) []RecordingListDTO {
|
|||||||
func ToRecordingDetailDTO(e entity.Recording) RecordingDetailDTO {
|
func ToRecordingDetailDTO(e entity.Recording) RecordingDetailDTO {
|
||||||
return RecordingDetailDTO{
|
return RecordingDetailDTO{
|
||||||
RecordingListDTO: ToRecordingListDTO(e),
|
RecordingListDTO: ToRecordingListDTO(e),
|
||||||
|
BodyWeights: ToRecordingBodyWeightDTOs(e.BodyWeights),
|
||||||
|
Depletions: ToRecordingDepletionDTOs(e.Depletions),
|
||||||
|
Stocks: ToRecordingStockDTOs(e.Stocks),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ToRecordingBodyWeightDTOs(bodyWeights []entity.RecordingBW) []RecordingBodyWeightDTO {
|
||||||
|
result := make([]RecordingBodyWeightDTO, len(bodyWeights))
|
||||||
|
for i, bw := range bodyWeights {
|
||||||
|
result[i] = RecordingBodyWeightDTO{
|
||||||
|
Weight: bw.Weight,
|
||||||
|
Qty: bw.Qty,
|
||||||
|
Notes: bw.Notes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToRecordingDepletionDTOs(depletions []entity.RecordingDepletion) []RecordingDepletionDTO {
|
||||||
|
result := make([]RecordingDepletionDTO, len(depletions))
|
||||||
|
for i, d := range depletions {
|
||||||
|
result[i] = RecordingDepletionDTO{
|
||||||
|
ProductWarehouseId: d.ProductWarehouseId,
|
||||||
|
Total: d.Total,
|
||||||
|
Notes: d.Notes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToRecordingStockDTOs(stocks []entity.RecordingStock) []RecordingStockDTO {
|
||||||
|
result := make([]RecordingStockDTO, len(stocks))
|
||||||
|
for i, s := range stocks {
|
||||||
|
result[i] = RecordingStockDTO{
|
||||||
|
ProductWarehouseId: s.ProductWarehouseId,
|
||||||
|
Increase: s.Increase,
|
||||||
|
Decrease: s.Decrease,
|
||||||
|
UsageAmount: s.UsageAmount,
|
||||||
|
Notes: s.Notes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
|
||||||
|
rProjectFlockKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||||
rRecording "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
rRecording "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||||
sRecording "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/services"
|
sRecording "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/services"
|
||||||
|
|
||||||
@@ -16,11 +18,12 @@ type RecordingModule struct{}
|
|||||||
|
|
||||||
func (RecordingModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
func (RecordingModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
||||||
recordingRepo := rRecording.NewRecordingRepository(db)
|
recordingRepo := rRecording.NewRecordingRepository(db)
|
||||||
|
projectFlockKandangRepo := rProjectFlockKandang.NewProjectFlockKandangRepository(db)
|
||||||
|
productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db)
|
||||||
userRepo := rUser.NewUserRepository(db)
|
userRepo := rUser.NewUserRepository(db)
|
||||||
|
|
||||||
recordingService := sRecording.NewRecordingService(recordingRepo, validate)
|
recordingService := sRecording.NewRecordingService(recordingRepo, projectFlockKandangRepo, productWarehouseRepo, validate)
|
||||||
userService := sUser.NewUserService(userRepo, validate)
|
userService := sUser.NewUserService(userRepo, validate)
|
||||||
|
|
||||||
RecordingRoutes(router, userService, recordingService)
|
RecordingRoutes(router, userService, recordingService)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
|
||||||
|
rProjectFlockKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||||
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/validations"
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/validations"
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
@@ -28,16 +30,25 @@ type RecordingService interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type recordingService struct {
|
type recordingService struct {
|
||||||
Log *logrus.Logger
|
Log *logrus.Logger
|
||||||
Validate *validator.Validate
|
Validate *validator.Validate
|
||||||
Repository repository.RecordingRepository
|
Repository repository.RecordingRepository
|
||||||
|
ProjectFlockKandangRepo rProjectFlockKandang.ProjectFlockKandangRepository
|
||||||
|
ProductWarehouseRepo rProductWarehouse.ProductWarehouseRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRecordingService(repo repository.RecordingRepository, validate *validator.Validate) RecordingService {
|
func NewRecordingService(
|
||||||
|
repo repository.RecordingRepository,
|
||||||
|
projectFlockKandangRepo rProjectFlockKandang.ProjectFlockKandangRepository,
|
||||||
|
productWarehouseRepo rProductWarehouse.ProductWarehouseRepository,
|
||||||
|
validate *validator.Validate,
|
||||||
|
) RecordingService {
|
||||||
return &recordingService{
|
return &recordingService{
|
||||||
Log: utils.Log,
|
Log: utils.Log,
|
||||||
Validate: validate,
|
Validate: validate,
|
||||||
Repository: repo,
|
Repository: repo,
|
||||||
|
ProjectFlockKandangRepo: projectFlockKandangRepo,
|
||||||
|
ProductWarehouseRepo: productWarehouseRepo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,9 +109,16 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
recordTime, err := time.Parse(time.RFC3339, req.RecordDatetime)
|
if _, err := s.ProjectFlockKandangRepo.GetByID(c.Context(), req.ProjectFlockKandangId); err != nil {
|
||||||
if err != nil {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "record_datetime must be in RFC3339 format")
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Project flock kandang not found")
|
||||||
|
}
|
||||||
|
s.Log.Errorf("Failed to get project flock kandang: %+v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.ensureProductWarehousesExist(c, req.Stocks, req.Depletions); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := s.Repository.DB().WithContext(c.Context()).Begin()
|
tx := s.Repository.DB().WithContext(c.Context()).Begin()
|
||||||
@@ -122,20 +140,22 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
status := 0
|
currentTime := time.Now().UTC()
|
||||||
if req.Status != nil {
|
recordTime := currentTime
|
||||||
status = *req.Status
|
recordDate := time.Date(
|
||||||
}
|
recordTime.Year(),
|
||||||
ontime := false
|
recordTime.Month(),
|
||||||
if req.Ontime != nil {
|
recordTime.Day(),
|
||||||
ontime = *req.Ontime
|
0, 0, 0, 0,
|
||||||
}
|
recordTime.Location(),
|
||||||
|
)
|
||||||
|
ontimeFlag := computeOntime(recordTime, currentTime)
|
||||||
|
|
||||||
recording := &entity.Recording{
|
recording := &entity.Recording{
|
||||||
ProjectFlockKandangId: req.ProjectFlockKandangId,
|
ProjectFlockKandangId: req.ProjectFlockKandangId,
|
||||||
RecordDatetime: recordTime,
|
RecordDatetime: recordTime,
|
||||||
Status: status,
|
RecordDate: &recordDate,
|
||||||
Ontime: ontime,
|
Ontime: boolToInt(ontimeFlag),
|
||||||
Day: &nextDay,
|
Day: &nextDay,
|
||||||
CreatedBy: 1, // TODO: replace with authenticated user
|
CreatedBy: 1, // TODO: replace with authenticated user
|
||||||
}
|
}
|
||||||
@@ -203,33 +223,13 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBody := make(map[string]any)
|
ontimeValue := boolToInt(computeOntime(recording.RecordDatetime, time.Now().UTC()))
|
||||||
|
if err := tx.Model(&entity.Recording{}).Where("id = ?", id).Update("ontime", ontimeValue).Error; err != nil {
|
||||||
if req.RecordDatetime != nil {
|
_ = tx.Rollback()
|
||||||
parsed, err := time.Parse(time.RFC3339, *req.RecordDatetime)
|
s.Log.Errorf("Failed to refresh ontime flag: %+v", err)
|
||||||
if err != nil {
|
return nil, err
|
||||||
_ = tx.Rollback()
|
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "record_datetime must be in RFC3339 format")
|
|
||||||
}
|
|
||||||
updateBody["record_datetime"] = parsed
|
|
||||||
recording.RecordDatetime = parsed
|
|
||||||
}
|
|
||||||
if req.Status != nil {
|
|
||||||
updateBody["status"] = *req.Status
|
|
||||||
recording.Status = *req.Status
|
|
||||||
}
|
|
||||||
if req.Ontime != nil {
|
|
||||||
updateBody["ontime"] = *req.Ontime
|
|
||||||
recording.Ontime = *req.Ontime
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(updateBody) > 0 {
|
|
||||||
if err := tx.Model(&entity.Recording{}).Where("id = ?", id).Updates(updateBody).Error; err != nil {
|
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to update recording: %+v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
recording.Ontime = ontimeValue
|
||||||
|
|
||||||
if req.BodyWeights != nil {
|
if req.BodyWeights != nil {
|
||||||
if err := s.replaceBodyWeights(tx, recording.Id, req.BodyWeights); err != nil {
|
if err := s.replaceBodyWeights(tx, recording.Id, req.BodyWeights); err != nil {
|
||||||
@@ -239,6 +239,10 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if req.Stocks != nil {
|
if req.Stocks != nil {
|
||||||
|
if err := s.ensureProductWarehousesExist(c, req.Stocks, nil); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := s.replaceStocks(tx, recording.Id, req.Stocks); err != nil {
|
if err := s.replaceStocks(tx, recording.Id, req.Stocks); err != nil {
|
||||||
_ = tx.Rollback()
|
_ = tx.Rollback()
|
||||||
s.Log.Errorf("Failed to update stocks: %+v", err)
|
s.Log.Errorf("Failed to update stocks: %+v", err)
|
||||||
@@ -246,6 +250,10 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if req.Depletions != nil {
|
if req.Depletions != nil {
|
||||||
|
if err := s.ensureProductWarehousesExist(c, nil, req.Depletions); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := s.replaceDepletions(tx, recording.Id, req.Depletions); err != nil {
|
if err := s.replaceDepletions(tx, recording.Id, req.Depletions); err != nil {
|
||||||
_ = tx.Rollback()
|
_ = tx.Rollback()
|
||||||
s.Log.Errorf("Failed to update depletions: %+v", err)
|
s.Log.Errorf("Failed to update depletions: %+v", err)
|
||||||
@@ -280,6 +288,38 @@ func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error {
|
|||||||
|
|
||||||
// === Persistence Helpers ===
|
// === Persistence Helpers ===
|
||||||
|
|
||||||
|
func (s *recordingService) ensureProductWarehousesExist(c *fiber.Ctx, stocks []validation.Stock, depletions []validation.Depletion) error {
|
||||||
|
idSet := make(map[uint]struct{})
|
||||||
|
|
||||||
|
for _, stock := range stocks {
|
||||||
|
if stock.ProductWarehouseId != 0 {
|
||||||
|
idSet[stock.ProductWarehouseId] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, dep := range depletions {
|
||||||
|
if dep.ProductWarehouseId != 0 {
|
||||||
|
idSet[dep.ProductWarehouseId] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(idSet) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for id := range idSet {
|
||||||
|
ok, err := s.ProductWarehouseRepo.ExistsByID(c.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to validate product warehouse %d: %+v", id, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Product warehouse %d not found", id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *recordingService) generateNextDay(tx *gorm.DB, projectFlockKandangId uint) (int, error) {
|
func (s *recordingService) generateNextDay(tx *gorm.DB, projectFlockKandangId uint) (int, error) {
|
||||||
var days []int
|
var days []int
|
||||||
if err := tx.Model(&entity.Recording{}).
|
if err := tx.Model(&entity.Recording{}).
|
||||||
@@ -319,6 +359,17 @@ func nextRecordingDay(days []int) int {
|
|||||||
return len(normalized) + 1
|
return len(normalized) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func computeOntime(recordDatetime, reference time.Time) bool {
|
||||||
|
return !recordDatetime.Before(reference)
|
||||||
|
}
|
||||||
|
|
||||||
|
func boolToInt(v bool) int {
|
||||||
|
if v {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func (s *recordingService) persistBodyWeights(tx *gorm.DB, recordingID uint, payload []validation.BodyWeight) error {
|
func (s *recordingService) persistBodyWeights(tx *gorm.DB, recordingID uint, payload []validation.BodyWeight) error {
|
||||||
if len(payload) == 0 {
|
if len(payload) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -24,21 +24,15 @@ type (
|
|||||||
|
|
||||||
type Create struct {
|
type Create struct {
|
||||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id" validate:"required,number,min=1"`
|
ProjectFlockKandangId uint `json:"project_flock_kandang_id" validate:"required,number,min=1"`
|
||||||
RecordDatetime string `json:"record_datetime" validate:"required,datetime=2006-01-02T15:04:05Z07:00"`
|
|
||||||
Status *int `json:"status,omitempty" validate:"omitempty,oneof=0 1 2 3"`
|
|
||||||
Ontime *bool `json:"ontime,omitempty" validate:"omitempty"`
|
|
||||||
BodyWeights []BodyWeight `json:"body_weights,omitempty" validate:"omitempty,dive"`
|
BodyWeights []BodyWeight `json:"body_weights,omitempty" validate:"omitempty,dive"`
|
||||||
Stocks []Stock `json:"stocks,omitempty" validate:"omitempty,dive"`
|
Stocks []Stock `json:"stocks,omitempty" validate:"omitempty,dive"`
|
||||||
Depletions []Depletion `json:"depletions,omitempty" validate:"omitempty,dive"`
|
Depletions []Depletion `json:"depletions,omitempty" validate:"omitempty,dive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
RecordDatetime *string `json:"record_datetime,omitempty" validate:"omitempty,datetime=2006-01-02T15:04:05Z07:00"`
|
BodyWeights []BodyWeight `json:"body_weights,omitempty" validate:"omitempty,dive"`
|
||||||
Status *int `json:"status,omitempty" validate:"omitempty,oneof=0 1 2 3"`
|
Stocks []Stock `json:"stocks,omitempty" validate:"omitempty,dive"`
|
||||||
Ontime *bool `json:"ontime,omitempty" validate:"omitempty"`
|
Depletions []Depletion `json:"depletions,omitempty" validate:"omitempty,dive"`
|
||||||
BodyWeights []BodyWeight `json:"body_weights,omitempty" validate:"omitempty,dive"`
|
|
||||||
Stocks []Stock `json:"stocks,omitempty" validate:"omitempty,dive"`
|
|
||||||
Depletions []Depletion `json:"depletions,omitempty" validate:"omitempty,dive"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user