apskel-pos-backend/internal/validator/order_ingredient_transaction_validator.go
2025-09-12 15:37:19 +07:00

121 lines
4.0 KiB
Go

package validator
import (
"apskel-pos-be/internal/models"
"fmt"
"strings"
"github.com/go-playground/validator/v10"
)
type OrderIngredientTransactionValidator interface {
ValidateCreateOrderIngredientTransactionRequest(req *models.CreateOrderIngredientTransactionRequest) error
ValidateUpdateOrderIngredientTransactionRequest(req *models.UpdateOrderIngredientTransactionRequest) error
ValidateListOrderIngredientTransactionsRequest(req *models.ListOrderIngredientTransactionsRequest) error
}
type OrderIngredientTransactionValidatorImpl struct {
validator *validator.Validate
}
func NewOrderIngredientTransactionValidator() OrderIngredientTransactionValidator {
v := validator.New()
return &OrderIngredientTransactionValidatorImpl{
validator: v,
}
}
func (v *OrderIngredientTransactionValidatorImpl) ValidateCreateOrderIngredientTransactionRequest(req *models.CreateOrderIngredientTransactionRequest) error {
if err := v.validator.Struct(req); err != nil {
var validationErrors []string
for _, err := range err.(validator.ValidationErrors) {
validationErrors = append(validationErrors, fmt.Sprintf("%s: %s", err.Field(), getValidationMessage(err)))
}
return fmt.Errorf("validation failed: %s", strings.Join(validationErrors, ", "))
}
// Custom validations
if req.GrossQty < req.NetQty {
return fmt.Errorf("gross quantity must be greater than or equal to net quantity")
}
expectedWasteQty := req.GrossQty - req.NetQty
if req.WasteQty != expectedWasteQty {
return fmt.Errorf("waste quantity must equal gross quantity minus net quantity")
}
return nil
}
func (v *OrderIngredientTransactionValidatorImpl) ValidateUpdateOrderIngredientTransactionRequest(req *models.UpdateOrderIngredientTransactionRequest) error {
if err := v.validator.Struct(req); err != nil {
var validationErrors []string
for _, err := range err.(validator.ValidationErrors) {
validationErrors = append(validationErrors, fmt.Sprintf("%s: %s", err.Field(), getValidationMessage(err)))
}
return fmt.Errorf("validation failed: %s", strings.Join(validationErrors, ", "))
}
// Custom validations for partial updates
if req.GrossQty != nil && req.NetQty != nil {
if *req.GrossQty < *req.NetQty {
return fmt.Errorf("gross quantity must be greater than or equal to net quantity")
}
}
if req.GrossQty != nil && req.NetQty != nil && req.WasteQty != nil {
expectedWasteQty := *req.GrossQty - *req.NetQty
if *req.WasteQty != expectedWasteQty {
return fmt.Errorf("waste quantity must equal gross quantity minus net quantity")
}
}
return nil
}
func (v *OrderIngredientTransactionValidatorImpl) ValidateListOrderIngredientTransactionsRequest(req *models.ListOrderIngredientTransactionsRequest) error {
if err := v.validator.Struct(req); err != nil {
var validationErrors []string
for _, err := range err.(validator.ValidationErrors) {
validationErrors = append(validationErrors, fmt.Sprintf("%s: %s", err.Field(), getValidationMessage(err)))
}
return fmt.Errorf("validation failed: %s", strings.Join(validationErrors, ", "))
}
// Custom validations
if req.StartDate != nil && req.EndDate != nil {
if req.StartDate.After(*req.EndDate) {
return fmt.Errorf("start date must be before end date")
}
}
return nil
}
func getValidationMessage(err validator.FieldError) string {
switch err.Tag() {
case "required":
return "is required"
case "min":
return fmt.Sprintf("must be at least %s", err.Param())
case "max":
return fmt.Sprintf("must be at most %s", err.Param())
case "gt":
return fmt.Sprintf("must be greater than %s", err.Param())
case "gte":
return fmt.Sprintf("must be greater than or equal to %s", err.Param())
case "lt":
return fmt.Sprintf("must be less than %s", err.Param())
case "lte":
return fmt.Sprintf("must be less than or equal to %s", err.Param())
case "email":
return "must be a valid email address"
case "uuid":
return "must be a valid UUID"
case "len":
return fmt.Sprintf("must be exactly %s characters long", err.Param())
default:
return "is invalid"
}
}