Merge branch 'fix/master-kandang-capacity' into 'development'

[FIX/BE][ISSUE#259] kandang capacity and fix err response

See merge request mbugroup/lti-api!59
This commit is contained in:
Adnan Zahir
2025-11-14 16:56:27 +07:00
15 changed files with 129 additions and 84 deletions
Vendored
BIN
View File
Binary file not shown.
+40 -8
View File
@@ -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
}
BIN
View File
Binary file not shown.
@@ -0,0 +1,2 @@
ALTER TABLE kandangs
DROP COLUMN IF EXISTS capacity;
@@ -0,0 +1,2 @@
ALTER TABLE kandangs
ADD COLUMN capacity NUMERIC(15,3) NOT NULL;
+5 -12
View File
@@ -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))
@@ -577,8 +578,6 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
Uom: "Ekor",
Category: "Day Old Chick",
Price: 1,
},
{
Name: "Ayam Mati",
@@ -587,8 +586,6 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
Uom: "Ekor",
Category: "Day Old Chick",
Price: 1,
},
{
Name: "Ayam Culling",
@@ -597,8 +594,6 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
Uom: "Ekor",
Category: "Day Old Chick",
Price: 1,
},
{
Name: "Telur Konsumsi Baik",
@@ -607,7 +602,6 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
Uom: "Unit",
Category: "Telur",
Price: 1,
},
{
Name: "Telur Pecah",
@@ -616,7 +610,6 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
Uom: "Unit",
Category: "Telur",
Price: 1,
},
{
Name: "281 SPECIAL STARTER",
+1
View File
@@ -11,6 +11,7 @@ type Kandang struct {
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"`
@@ -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,
}
+2 -2
View File
@@ -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)
@@ -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)
@@ -3,6 +3,7 @@ package validation
type Create struct {
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"`
@@ -11,6 +12,7 @@ type Create struct {
type Update struct {
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"`
+4 -2
View File
@@ -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,
@@ -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),
+2 -2
View File
@@ -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
+4 -2
View File
@@ -15,7 +15,8 @@ type {{Pascal .Entity}}BaseDTO struct {
}
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"`
@@ -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,