Merge branch 'dev/ragil-before-sso' into 'development-before-sso'

fix(BE-78)change typedata in recording dto and validation for create and update

See merge request mbugroup/lti-api!51
This commit is contained in:
Hafizh A. Y.
2025-11-05 08:58:45 +00:00
3 changed files with 110 additions and 81 deletions
@@ -2,10 +2,12 @@ package dto
import ( import (
"math" "math"
"strings"
"time" "time"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities" entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto" approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
productWarehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/adjustments/dto"
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
"gitlab.com/mbugroup/lti-api.git/internal/utils" "gitlab.com/mbugroup/lti-api.git/internal/utils"
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals" approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
@@ -17,19 +19,19 @@ type RecordingBaseDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
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"`
Day *int `json:"day,omitempty"` Day int `json:"day"`
ProjectFlockCategory *string `json:"project_flock_category,omitempty"` ProjectFlockCategory string `json:"project_flock_category"`
TotalDepletionQty *float64 `json:"total_depletion_qty,omitempty"` TotalDepletionQty float64 `json:"total_depletion_qty"`
CumDepletionRate *float64 `json:"cum_depletion_rate,omitempty"` CumDepletionRate float64 `json:"cum_depletion_rate"`
DailyGain *float64 `json:"daily_gain,omitempty"` DailyGain float64 `json:"daily_gain"`
AvgDailyGain *float64 `json:"avg_daily_gain,omitempty"` AvgDailyGain float64 `json:"avg_daily_gain"`
CumIntake *int `json:"cum_intake,omitempty"` CumIntake int `json:"cum_intake"`
FcrValue *float64 `json:"fcr_value,omitempty"` FcrValue float64 `json:"fcr_value"`
TotalChickQty *float64 `json:"total_chick_qty,omitempty"` TotalChickQty float64 `json:"total_chick_qty"`
Approval approvalDTO.ApprovalBaseDTO `json:"approval"` Approval approvalDTO.ApprovalBaseDTO `json:"approval"`
EggGradingStatus *string `json:"egg_grading_status,omitempty"` EggGradingStatus *string `json:"egg_grading_status"`
EggGradingPendingQty *int `json:"egg_grading_pending_qty,omitempty"` EggGradingPendingQty *int `json:"egg_grading_pending_qty"`
EggGradingCompletedQty *int `json:"egg_grading_completed_qty,omitempty"` EggGradingCompletedQty *int `json:"egg_grading_completed_qty"`
} }
type RecordingListDTO struct { type RecordingListDTO struct {
@@ -54,31 +56,23 @@ type RecordingBodyWeightDTO struct {
} }
type RecordingDepletionDTO struct { type RecordingDepletionDTO struct {
ProductWarehouseId uint `json:"product_warehouse_id"` ProductWarehouseId uint `json:"product_warehouse_id"`
Qty float64 `json:"qty"` Qty float64 `json:"qty"`
ProductWarehouse *RecordingProductWarehouseDTO `json:"product_warehouse,omitempty"` ProductWarehouse productWarehouseDTO.ProductWarehouseDTO `json:"product_warehouse"`
} }
type RecordingStockDTO struct { type RecordingStockDTO struct {
ProductWarehouseId uint `json:"product_warehouse_id"` ProductWarehouseId uint `json:"product_warehouse_id"`
UsageAmount *float64 `json:"usage_amount,omitempty"` UsageAmount float64 `json:"usage_amount"`
PendingQty *float64 `json:"pending_qty,omitempty"` PendingQty *float64 `json:"pending_qty,omitempty"`
ProductWarehouse *RecordingProductWarehouseDTO `json:"product_warehouse,omitempty"` ProductWarehouse productWarehouseDTO.ProductWarehouseDTO `json:"product_warehouse"`
} }
type RecordingEggDTO struct { type RecordingEggDTO struct {
ProductWarehouseId uint `json:"product_warehouse_id"` ProductWarehouseId uint `json:"product_warehouse_id"`
Qty int `json:"qty"` Qty int `json:"qty"`
ProductWarehouse *RecordingProductWarehouseDTO `json:"product_warehouse,omitempty"` ProductWarehouse productWarehouseDTO.ProductWarehouseDTO `json:"product_warehouse"`
Gradings []RecordingEggGradingDTO `json:"gradings,omitempty"` Gradings []RecordingEggGradingDTO `json:"gradings,omitempty"`
}
type RecordingProductWarehouseDTO struct {
Id uint `json:"id"`
ProductId uint `json:"product_id"`
ProductName string `json:"product_name"`
WarehouseId uint `json:"warehouse_id"`
WarehouseName string `json:"warehouse_name"`
} }
type RecordingEggGradingDTO struct { type RecordingEggGradingDTO struct {
@@ -89,12 +83,46 @@ type RecordingEggGradingDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToRecordingBaseDTO(e entity.Recording) RecordingBaseDTO { func ToRecordingBaseDTO(e entity.Recording) RecordingBaseDTO {
var projectFlockCategory *string var (
projectFlockCategory string
day int
totalDepletionQty float64
cumDepletionRate float64
dailyGain float64
avgDailyGain float64
cumIntake int
fcrValue float64
totalChickQty float64
)
if e.Day != nil {
day = *e.Day
}
if e.TotalDepletionQty != nil {
totalDepletionQty = *e.TotalDepletionQty
}
if e.CumDepletionRate != nil {
cumDepletionRate = *e.CumDepletionRate
}
if e.DailyGain != nil {
dailyGain = *e.DailyGain
}
if e.AvgDailyGain != nil {
avgDailyGain = *e.AvgDailyGain
}
if e.CumIntake != nil {
cumIntake = *e.CumIntake
}
if e.FcrValue != nil {
fcrValue = *e.FcrValue
}
if e.TotalChickQty != nil {
totalChickQty = *e.TotalChickQty
}
if e.ProjectFlockKandang != nil && e.ProjectFlockKandang.ProjectFlock.Id != 0 { if e.ProjectFlockKandang != nil && e.ProjectFlockKandang.ProjectFlock.Id != 0 {
category := e.ProjectFlockKandang.ProjectFlock.Category category := e.ProjectFlockKandang.ProjectFlock.Category
if category != "" { projectFlockCategory = category
projectFlockCategory = &category
}
} }
latestApproval := defaultRecordingLatestApproval(e) latestApproval := defaultRecordingLatestApproval(e)
@@ -109,15 +137,15 @@ func ToRecordingBaseDTO(e entity.Recording) RecordingBaseDTO {
Id: e.Id, Id: e.Id,
ProjectFlockKandangId: e.ProjectFlockKandangId, ProjectFlockKandangId: e.ProjectFlockKandangId,
RecordDatetime: e.RecordDatetime, RecordDatetime: e.RecordDatetime,
Day: e.Day, Day: day,
ProjectFlockCategory: projectFlockCategory, ProjectFlockCategory: projectFlockCategory,
TotalDepletionQty: e.TotalDepletionQty, TotalDepletionQty: totalDepletionQty,
CumDepletionRate: e.CumDepletionRate, CumDepletionRate: cumDepletionRate,
DailyGain: e.DailyGain, DailyGain: dailyGain,
AvgDailyGain: e.AvgDailyGain, AvgDailyGain: avgDailyGain,
CumIntake: e.CumIntake, CumIntake: cumIntake,
FcrValue: e.FcrValue, FcrValue: fcrValue,
TotalChickQty: e.TotalChickQty, TotalChickQty: totalChickQty,
Approval: latestApproval, Approval: latestApproval,
EggGradingStatus: gradingStatus, EggGradingStatus: gradingStatus,
EggGradingPendingQty: gradingPending, EggGradingPendingQty: gradingPending,
@@ -149,12 +177,21 @@ func ToRecordingListDTOs(e []entity.Recording) []RecordingListDTO {
} }
func ToRecordingDetailDTO(e entity.Recording) RecordingDetailDTO { func ToRecordingDetailDTO(e entity.Recording) RecordingDetailDTO {
listDTO := ToRecordingListDTO(e)
var eggs []RecordingEggDTO
if strings.EqualFold(listDTO.ProjectFlockCategory, string(utils.ProjectFlockCategoryLaying)) {
eggs = ToRecordingEggDTOs(e.Eggs)
} else if len(e.Eggs) > 0 {
eggs = ToRecordingEggDTOs(e.Eggs)
}
return RecordingDetailDTO{ return RecordingDetailDTO{
RecordingListDTO: ToRecordingListDTO(e), RecordingListDTO: listDTO,
BodyWeights: ToRecordingBodyWeightDTOs(e.BodyWeights), BodyWeights: ToRecordingBodyWeightDTOs(e.BodyWeights),
Depletions: ToRecordingDepletionDTOs(e.Depletions), Depletions: ToRecordingDepletionDTOs(e.Depletions),
Stocks: ToRecordingStockDTOs(e.Stocks), Stocks: ToRecordingStockDTOs(e.Stocks),
Eggs: ToRecordingEggDTOs(e.Eggs), Eggs: eggs,
} }
} }
@@ -176,7 +213,7 @@ func ToRecordingDepletionDTOs(depletions []entity.RecordingDepletion) []Recordin
result[i] = RecordingDepletionDTO{ result[i] = RecordingDepletionDTO{
ProductWarehouseId: d.ProductWarehouseId, ProductWarehouseId: d.ProductWarehouseId,
Qty: d.Qty, Qty: d.Qty,
ProductWarehouse: toRecordingProductWarehouseDTO(&d.ProductWarehouse), ProductWarehouse: mapProductWarehouseDTO(&d.ProductWarehouse),
} }
} }
return result return result
@@ -185,11 +222,16 @@ func ToRecordingDepletionDTOs(depletions []entity.RecordingDepletion) []Recordin
func ToRecordingStockDTOs(stocks []entity.RecordingStock) []RecordingStockDTO { func ToRecordingStockDTOs(stocks []entity.RecordingStock) []RecordingStockDTO {
result := make([]RecordingStockDTO, len(stocks)) result := make([]RecordingStockDTO, len(stocks))
for i, s := range stocks { for i, s := range stocks {
var usageAmount float64
if s.UsageQty != nil {
usageAmount = *s.UsageQty
}
result[i] = RecordingStockDTO{ result[i] = RecordingStockDTO{
ProductWarehouseId: s.ProductWarehouseId, ProductWarehouseId: s.ProductWarehouseId,
UsageAmount: s.UsageQty, UsageAmount: usageAmount,
PendingQty: s.PendingQty, PendingQty: s.PendingQty,
ProductWarehouse: toRecordingProductWarehouseDTO(&s.ProductWarehouse), ProductWarehouse: mapProductWarehouseDTO(&s.ProductWarehouse),
} }
} }
return result return result
@@ -201,7 +243,7 @@ func ToRecordingEggDTOs(eggs []entity.RecordingEgg) []RecordingEggDTO {
result[i] = RecordingEggDTO{ result[i] = RecordingEggDTO{
ProductWarehouseId: egg.ProductWarehouseId, ProductWarehouseId: egg.ProductWarehouseId,
Qty: egg.Qty, Qty: egg.Qty,
ProductWarehouse: toRecordingProductWarehouseDTO(&egg.ProductWarehouse), ProductWarehouse: mapProductWarehouseDTO(&egg.ProductWarehouse),
Gradings: ToRecordingEggGradingDTOs(egg.GradingEggs), Gradings: ToRecordingEggGradingDTOs(egg.GradingEggs),
} }
} }
@@ -224,25 +266,17 @@ func ToRecordingEggGradingDTOs(gradings []entity.GradingEgg) []RecordingEggGradi
return result return result
} }
func toRecordingProductWarehouseDTO(pw *entity.ProductWarehouse) *RecordingProductWarehouseDTO { func mapProductWarehouseDTO(pw *entity.ProductWarehouse) productWarehouseDTO.ProductWarehouseDTO {
if pw == nil || pw.Id == 0 { if pw == nil {
return nil return productWarehouseDTO.ProductWarehouseDTO{}
} }
dto := RecordingProductWarehouseDTO{ mapped := productWarehouseDTO.ToProductWarehouseDTO(pw)
Id: pw.Id, if mapped == nil {
ProductId: pw.ProductId, return productWarehouseDTO.ProductWarehouseDTO{}
WarehouseId: pw.WarehouseId,
} }
if pw.Product.Id != 0 { return *mapped
dto.ProductName = pw.Product.Name
}
if pw.Warehouse.Id != 0 {
dto.WarehouseName = pw.Warehouse.Name
}
return &dto
} }
const goodEggProductWarehouseID uint = 5 const goodEggProductWarehouseID uint = 5
@@ -2,14 +2,14 @@ package validation
type ( type (
BodyWeight struct { BodyWeight struct {
AvgWeight float64 `json:"avg_weight" validate:"required"` AvgWeight float64 `json:"avg_weight" validate:"required"`
Qty float64 `json:"qty" validate:"required,gt=0"` Qty float64 `json:"qty" validate:"required,gt=0"`
TotalWeight *float64 `json:"total_weight,omitempty" validate:"omitempty,gt=0"` TotalWeight float64 `json:"total_weight" validate:"required,gte=0"`
} }
Stock struct { Stock struct {
ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,number,min=1"` ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,number,min=1"`
Qty *float64 `json:"qty,omitempty" validate:"required_without=UsageAmount,gte=0"` Qty float64 `json:"qty" validate:"required,gte=0"`
PendingQty *float64 `json:"pending_qty,omitempty" validate:"omitempty,gte=0"` PendingQty *float64 `json:"pending_qty,omitempty" validate:"omitempty,gte=0"`
} }
@@ -26,10 +26,10 @@ 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"`
BodyWeights []BodyWeight `json:"body_weights,omitempty" validate:"omitempty,dive"` BodyWeights []BodyWeight `json:"body_weights" validate:"dive"`
Stocks []Stock `json:"stocks,omitempty" validate:"omitempty,dive"` Stocks []Stock `json:"stocks" validate:"dive"`
Depletions []Depletion `json:"depletions,omitempty" validate:"omitempty,dive"` Depletions []Depletion `json:"depletions" validate:"dive"`
Eggs []Egg `json:"eggs,omitempty" validate:"omitempty,dive"` Eggs []Egg `json:"eggs" validate:"omitempty,dive"`
} }
type Update struct { type Update struct {
+4 -9
View File
@@ -13,16 +13,15 @@ func MapBodyWeights(recordingID uint, items []validation.BodyWeight) []entity.Re
result := make([]entity.RecordingBW, 0, len(items)) result := make([]entity.RecordingBW, 0, len(items))
for _, item := range items { for _, item := range items {
totalWeight := item.TotalWeight totalWeight := item.TotalWeight
if totalWeight == nil { if totalWeight <= 0 {
calculated := item.AvgWeight * item.Qty totalWeight = item.AvgWeight * item.Qty
totalWeight = &calculated
} }
result = append(result, entity.RecordingBW{ result = append(result, entity.RecordingBW{
RecordingId: recordingID, RecordingId: recordingID,
AvgWeight: item.AvgWeight, AvgWeight: item.AvgWeight,
Qty: item.Qty, Qty: item.Qty,
TotalWeight: *totalWeight, TotalWeight: totalWeight,
}) })
} }
return result return result
@@ -35,12 +34,8 @@ func MapStocks(recordingID uint, items []validation.Stock) []entity.RecordingSto
result := make([]entity.RecordingStock, 0, len(items)) result := make([]entity.RecordingStock, 0, len(items))
for _, item := range items { for _, item := range items {
var usageAmount float64
if item.Qty != nil {
usageAmount = *item.Qty
}
usagePtr := new(float64) usagePtr := new(float64)
*usagePtr = usageAmount *usagePtr = item.Qty
pending := item.PendingQty pending := item.PendingQty
if pending == nil { if pending == nil {
pending = new(float64) pending = new(float64)