diff --git a/.DS_Store b/.DS_Store index 4c14efd8..e39247fd 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/internal/common/validation/validation.go b/internal/common/validation/validation.go index 426974f3..330009e6 100644 --- a/internal/common/validation/validation.go +++ b/internal/common/validation/validation.go @@ -3,6 +3,8 @@ package validation import ( "errors" "fmt" + "reflect" + "strings" "github.com/go-playground/validator/v10" ) @@ -21,34 +23,41 @@ var customMessages = map[string]string{ "alphanum": "Field %s must contain only alphanumeric characters", "oneof": "Invalid value for field %s", "password": "Field %s must be at least 8 characters, contain uppercase, lowercase, number, and special character", + "gt": "Invalid %s, must be greater than %s", } -func CustomErrorMessages(err error) map[string]string { +func CustomErrorMessages(err error) (string, map[string]string) { var validationErrors validator.ValidationErrors if errors.As(err, &validationErrors) { return generateErrorMessages(validationErrors) } - return nil + return "", nil } -func generateErrorMessages(validationErrors validator.ValidationErrors) map[string]string { +func generateErrorMessages(validationErrors validator.ValidationErrors) (string, map[string]string) { errorsMap := make(map[string]string) - for _, err := range validationErrors { + var firstMessage string + for i, err := range validationErrors { fieldName := err.StructNamespace() tag := err.Tag() customMessage := customMessages[tag] + var msg string if customMessage != "" { - errorsMap[fieldName] = formatErrorMessage(customMessage, err, tag) + msg = formatErrorMessage(customMessage, err, tag) } else { - errorsMap[fieldName] = defaultErrorMessage(err) + msg = defaultErrorMessage(err) + } + errorsMap[fieldName] = msg + if i == 0 { + firstMessage = msg } } - return errorsMap + return firstMessage, errorsMap } func formatErrorMessage(customMessage string, err validator.FieldError, tag string) string { - if tag == "min" || tag == "max" || tag == "len" { + if tag == "min" || tag == "max" || tag == "len" || tag == "gt" { return fmt.Sprintf(customMessage, err.Field(), err.Param()) } return fmt.Sprintf(customMessage, err.Field()) @@ -61,6 +70,16 @@ func defaultErrorMessage(err validator.FieldError) string { func Validator() *validator.Validate { validate := validator.New() + validate.RegisterTagNameFunc(func(fld reflect.StructField) string { + if jsonTag := getTagName(fld, "json"); jsonTag != "" { + return jsonTag + } + if queryTag := getTagName(fld, "query"); queryTag != "" { + return queryTag + } + return fld.Name + }) + if err := validate.RegisterValidation("password", Password); err != nil { return nil } @@ -72,3 +91,16 @@ func Validator() *validator.Validate { } return validate } + +func getTagName(fld reflect.StructField, tag string) string { + value, ok := fld.Tag.Lookup(tag) + if !ok || value == "-" { + return "" + } + + name := strings.Split(value, ",")[0] + if name == "" || name == "-" { + return "" + } + return name +} diff --git a/internal/config/.DS_Store b/internal/config/.DS_Store index 5008ddfc..6dacdd03 100644 Binary files a/internal/config/.DS_Store and b/internal/config/.DS_Store differ diff --git a/internal/database/migrations/20251114084320_update_kandang_capacity.down.sql b/internal/database/migrations/20251114084320_update_kandang_capacity.down.sql new file mode 100644 index 00000000..4afc4f12 --- /dev/null +++ b/internal/database/migrations/20251114084320_update_kandang_capacity.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE kandangs + DROP COLUMN IF EXISTS capacity; diff --git a/internal/database/migrations/20251114084320_update_kandang_capacity.up.sql b/internal/database/migrations/20251114084320_update_kandang_capacity.up.sql new file mode 100644 index 00000000..e1ea4410 --- /dev/null +++ b/internal/database/migrations/20251114084320_update_kandang_capacity.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE kandangs + ADD COLUMN capacity NUMERIC(15,3) NOT NULL; diff --git a/internal/database/seed/seeder.go b/internal/database/seed/seeder.go index 24425917..bb72417a 100644 --- a/internal/database/seed/seeder.go +++ b/internal/database/seed/seeder.go @@ -235,13 +235,14 @@ func seedKandangs(tx *gorm.DB, createdBy uint, locations map[string]uint, users seeds := []struct { Name string Status utils.KandangStatus + Capacity float64 Location string PicKey string }{ - {Name: "Singaparna 1", Status: utils.KandangStatusNonActive, Location: "Singaparna", PicKey: "admin"}, - {Name: "Singaparna 2", Status: utils.KandangStatusNonActive, Location: "Singaparna", PicKey: "admin"}, - {Name: "Cikaum 1", Status: utils.KandangStatusNonActive, Location: "Cikaum", PicKey: "admin"}, - {Name: "Cikaum 2", Status: utils.KandangStatusNonActive, Location: "Cikaum", PicKey: "admin"}, + {Name: "Singaparna 1", Status: utils.KandangStatusNonActive, Capacity: 50000, Location: "Singaparna", PicKey: "admin"}, + {Name: "Singaparna 2", Status: utils.KandangStatusNonActive, Capacity: 50000, Location: "Singaparna", PicKey: "admin"}, + {Name: "Cikaum 1", Status: utils.KandangStatusNonActive, Capacity: 50000, Location: "Cikaum", PicKey: "admin"}, + {Name: "Cikaum 2", Status: utils.KandangStatusNonActive, Capacity: 50000, Location: "Cikaum", PicKey: "admin"}, } result := make(map[string]uint, len(seeds)) @@ -571,52 +572,44 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories Flags: []utils.FlagType{utils.FlagDOC}, }, { - Name: "Ayam Afkir", - Brand: "-", - Sku: "1", - Uom: "Ekor", - Category: "Day Old Chick", - Price: 1, - - + Name: "Ayam Afkir", + Brand: "-", + Sku: "1", + Uom: "Ekor", + Category: "Day Old Chick", + Price: 1, }, { - Name: "Ayam Mati", - Brand: "-", - Sku: "2", - Uom: "Ekor", - Category: "Day Old Chick", - Price: 1, - - + Name: "Ayam Mati", + Brand: "-", + Sku: "2", + Uom: "Ekor", + Category: "Day Old Chick", + Price: 1, }, { - Name: "Ayam Culling", - Brand: "-", - Sku: "3", - Uom: "Ekor", - Category: "Day Old Chick", - Price: 1, - - + Name: "Ayam Culling", + Brand: "-", + Sku: "3", + Uom: "Ekor", + Category: "Day Old Chick", + Price: 1, }, { - Name: "Telur Konsumsi Baik", - Brand: "-", - Sku: "4", - Uom: "Unit", - Category: "Telur", - Price: 1, - + Name: "Telur Konsumsi Baik", + Brand: "-", + Sku: "4", + Uom: "Unit", + Category: "Telur", + Price: 1, }, { - Name: "Telur Pecah", - Brand: "-", - Sku: "5", - Uom: "Unit", - Category: "Telur", - Price: 1, - + Name: "Telur Pecah", + Brand: "-", + Sku: "5", + Uom: "Unit", + Category: "Telur", + Price: 1, }, { Name: "281 SPECIAL STARTER", diff --git a/internal/entities/kandang.go b/internal/entities/kandang.go index 178681f0..882184b3 100644 --- a/internal/entities/kandang.go +++ b/internal/entities/kandang.go @@ -7,17 +7,18 @@ import ( ) type Kandang struct { - Id uint `gorm:"primaryKey"` - Name string `gorm:"not null;uniqueIndex:kandangs_name_unique,where:deleted_at IS NULL"` - Status string `gorm:"type:varchar(50);not null"` - LocationId uint `gorm:"not null"` - PicId uint `gorm:"not null"` - CreatedBy uint `gorm:"not null"` - CreatedAt time.Time `gorm:"autoCreateTime"` - UpdatedAt time.Time `gorm:"autoUpdateTime"` - DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` - CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"` - Location Location `gorm:"foreignKey:LocationId;references:Id"` - Pic User `gorm:"foreignKey:PicId;references:Id"` + Id uint `gorm:"primaryKey"` + Name string `gorm:"not null;uniqueIndex:kandangs_name_unique,where:deleted_at IS NULL"` + Status string `gorm:"type:varchar(50);not null"` + LocationId uint `gorm:"not null"` + Capacity float64 `gorm:"not null"` + PicId uint `gorm:"not null"` + CreatedBy uint `gorm:"not null"` + CreatedAt time.Time `gorm:"autoCreateTime"` + UpdatedAt time.Time `gorm:"autoUpdateTime"` + DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` + CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"` + Location Location `gorm:"foreignKey:LocationId;references:Id"` + Pic User `gorm:"foreignKey:PicId;references:Id"` ProjectFlockKandangs []ProjectFlockKandang `gorm:"foreignKey:KandangId;references:Id" json:"-"` } diff --git a/internal/modules/master/kandangs/dto/kandang.dto.go b/internal/modules/master/kandangs/dto/kandang.dto.go index deed483c..284ca166 100644 --- a/internal/modules/master/kandangs/dto/kandang.dto.go +++ b/internal/modules/master/kandangs/dto/kandang.dto.go @@ -14,6 +14,7 @@ type KandangBaseDTO struct { Id uint `json:"id"` Name string `json:"name"` Status string `json:"status"` + Capacity float64 `json:"capacity"` Location *locationDTO.LocationBaseDTO `json:"location"` Pic *userDTO.UserBaseDTO `json:"pic"` } @@ -48,6 +49,7 @@ func ToKandangBaseDTO(e entity.Kandang) KandangBaseDTO { Id: e.Id, Name: e.Name, Status: e.Status, + Capacity: e.Capacity, Location: location, Pic: pic, } diff --git a/internal/modules/master/kandangs/route.go b/internal/modules/master/kandangs/route.go index 6a425b64..1e384b1f 100644 --- a/internal/modules/master/kandangs/route.go +++ b/internal/modules/master/kandangs/route.go @@ -1,7 +1,7 @@ package kandangs import ( - m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + // m "gitlab.com/mbugroup/lti-api.git/internal/middleware" controller "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/controllers" kandang "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/services" user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" @@ -13,7 +13,7 @@ func KandangRoutes(v1 fiber.Router, u user.UserService, s kandang.KandangService ctrl := controller.NewKandangController(s) route := v1.Group("/kandangs") - route.Use(m.Auth(u)) + // route.Use(m.Auth(u)) route.Get("/", ctrl.GetAll) route.Post("/", ctrl.CreateOne) diff --git a/internal/modules/master/kandangs/services/kandang.service.go b/internal/modules/master/kandangs/services/kandang.service.go index 1c0eed6a..e65348fc 100644 --- a/internal/modules/master/kandangs/services/kandang.service.go +++ b/internal/modules/master/kandangs/services/kandang.service.go @@ -134,6 +134,7 @@ func (s *kandangService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit createBody := &entity.Kandang{ Name: req.Name, LocationId: req.LocationId, + Capacity: req.Capacity, Status: status, PicId: req.PicId, CreatedBy: 1, @@ -194,6 +195,10 @@ func (s kandangService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) updateBody["pic_id"] = *req.PicId } + if req.Capacity != nil { + updateBody["capacity"] = *req.Capacity + } + finalStatus := strings.ToUpper(existing.Status) if req.Status != nil { status := strings.ToUpper(*req.Status) diff --git a/internal/modules/master/kandangs/validations/kandang.validation.go b/internal/modules/master/kandangs/validations/kandang.validation.go index f6886991..6d7c090b 100644 --- a/internal/modules/master/kandangs/validations/kandang.validation.go +++ b/internal/modules/master/kandangs/validations/kandang.validation.go @@ -1,19 +1,21 @@ package validation type Create struct { - Name string `json:"name" validate:"required_strict,min=3"` - Status string `json:"status,omitempty" validate:"omitempty,min=3"` - LocationId uint `json:"location_id" validate:"required_strict,number,gt=0"` - PicId uint `json:"pic_id" validate:"required_strict,number,gt=0"` - ProjectFlockId *uint `json:"project_flock_id" validate:"omitempty,number,gt=0"` + Name string `json:"name" validate:"required_strict,min=3"` + Status string `json:"status,omitempty" validate:"omitempty,min=3"` + Capacity float64 `json:"capacity" validate:"required_strict,gt=0"` + LocationId uint `json:"location_id" validate:"required_strict,number,gt=0"` + PicId uint `json:"pic_id" validate:"required_strict,number,gt=0"` + ProjectFlockId *uint `json:"project_flock_id" validate:"omitempty,number,gt=0"` } type Update struct { - Name *string `json:"name,omitempty" validate:"omitempty"` - Status *string `json:"status,omitempty" validate:"omitempty,min=3"` - LocationId *uint `json:"location_id,omitempty" validate:"omitempty,number,gt=0"` - PicId *uint `json:"pic_id,omitempty" validate:"omitempty,number,gt=0"` - ProjectFlockId *uint `json:"project_flock_id,omitempty" validate:"omitempty,number,gt=0"` + Name *string `json:"name,omitempty" validate:"omitempty"` + Status *string `json:"status,omitempty" validate:"omitempty,min=3"` + Capacity *float64 `json:"capacity" validate:"omitempty,gt=0"` + LocationId *uint `json:"location_id,omitempty" validate:"omitempty,number,gt=0"` + PicId *uint `json:"pic_id,omitempty" validate:"omitempty,number,gt=0"` + ProjectFlockId *uint `json:"project_flock_id,omitempty" validate:"omitempty,number,gt=0"` } type Query struct { diff --git a/internal/modules/master/uoms/dto/uom.dto.go b/internal/modules/master/uoms/dto/uom.dto.go index 476309b2..2e614de0 100644 --- a/internal/modules/master/uoms/dto/uom.dto.go +++ b/internal/modules/master/uoms/dto/uom.dto.go @@ -15,7 +15,8 @@ type UomBaseDTO struct { } type UomListDTO struct { - UomBaseDTO + Id uint `json:"id"` + Name string `json:"name"` CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` @@ -42,7 +43,8 @@ func ToUomListDTO(e entity.Uom) UomListDTO { } return UomListDTO{ - UomBaseDTO: ToUomBaseDTO(e), + Id: e.Id, + Name: e.Name, CreatedAt: e.CreatedAt, UpdatedAt: e.UpdatedAt, CreatedUser: createdUser, diff --git a/internal/modules/production/recordings/dto/recording.dto.go b/internal/modules/production/recordings/dto/recording.dto.go index e8d04758..218aba4f 100644 --- a/internal/modules/production/recordings/dto/recording.dto.go +++ b/internal/modules/production/recordings/dto/recording.dto.go @@ -67,6 +67,7 @@ type RecordingStockDTO struct { } type RecordingEggDTO struct { + Id uint `json:"id"` ProductWarehouseId uint `json:"product_warehouse_id"` Qty int `json:"qty"` ProductWarehouse *RecordingProductWarehouseDTO `json:"product_warehouse,omitempty"` @@ -199,6 +200,7 @@ func ToRecordingEggDTOs(eggs []entity.RecordingEgg) []RecordingEggDTO { result := make([]RecordingEggDTO, len(eggs)) for i, egg := range eggs { result[i] = RecordingEggDTO{ + Id: egg.Id, ProductWarehouseId: egg.ProductWarehouseId, Qty: egg.Qty, ProductWarehouse: toRecordingProductWarehouseDTO(&egg.ProductWarehouse), diff --git a/internal/utils/error.go b/internal/utils/error.go index e63e81a2..e409e50c 100644 --- a/internal/utils/error.go +++ b/internal/utils/error.go @@ -10,8 +10,8 @@ import ( ) func ErrorHandler(c *fiber.Ctx, err error) error { - if errorsMap := validation.CustomErrorMessages(err); len(errorsMap) > 0 { - return response.Error(c, fiber.StatusBadRequest, "Bad Request", errorsMap) + if message, errorsMap := validation.CustomErrorMessages(err); len(errorsMap) > 0 { + return response.Error(c, fiber.StatusBadRequest, message, nil) } var fiberErr *fiber.Error diff --git a/tools/templates/dto.tmpl b/tools/templates/dto.tmpl index a03d7018..39b92884 100644 --- a/tools/templates/dto.tmpl +++ b/tools/templates/dto.tmpl @@ -10,15 +10,16 @@ import ( // === DTO Structs === type {{Pascal .Entity}}BaseDTO struct { - Id uint `json:"id"` - Name string `json:"name"` + Id uint `json:"id"` + Name string `json:"name"` } type {{Pascal .Entity}}ListDTO struct { - {{Pascal .Entity}}BaseDTO + Id uint `json:"id"` + Name string `json:"name"` CreatedUser *userDTO.UserBaseDTO `json:"created_user"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } type {{Pascal .Entity}}DetailDTO struct { @@ -42,7 +43,8 @@ func To{{Pascal .Entity}}ListDTO(e entity.{{Pascal .Entity}}) {{Pascal .Entity}} } return {{Pascal .Entity}}ListDTO{ - {{Pascal .Entity}}BaseDTO: To{{Pascal .Entity}}BaseDTO(e), + Id: e.Id, + Name: e.Name, CreatedAt: e.CreatedAt, UpdatedAt: e.UpdatedAt, CreatedUser: createdUser,