package validator import ( "apskel-pos-be/internal/contract" "errors" "strings" "github.com/go-playground/validator/v10" ) type CustomerValidator interface { ValidateCreateCustomerRequest(req *contract.CreateCustomerRequest) (error, string) ValidateUpdateCustomerRequest(req *contract.UpdateCustomerRequest) (error, string) ValidateListCustomersRequest(req *contract.ListCustomersRequest) (error, string) ValidateSetDefaultCustomerRequest(req *contract.SetDefaultCustomerRequest) (error, string) } type CustomerValidatorImpl struct { validate *validator.Validate } func NewCustomerValidator() *CustomerValidatorImpl { return &CustomerValidatorImpl{ validate: validator.New(), } } // ValidateCreateCustomer validates create customer request func (v *CustomerValidatorImpl) ValidateCreateCustomerRequest(req *contract.CreateCustomerRequest) (error, string) { if err := v.validate.Struct(req); err != nil { return err, "VALIDATION_ERROR" } // Additional custom validations if req.Name != "" { req.Name = strings.TrimSpace(req.Name) if req.Name == "" { return errors.New("name cannot be empty or whitespace only"), "INVALID_NAME" } if len(req.Name) > 255 { return errors.New("name cannot exceed 255 characters"), "INVALID_NAME" } } if req.Email != nil && *req.Email != "" { *req.Email = strings.TrimSpace(strings.ToLower(*req.Email)) if *req.Email == "" { return errors.New("email cannot be empty or whitespace only"), "INVALID_EMAIL" } if len(*req.Email) > 255 { return errors.New("email cannot exceed 255 characters"), "INVALID_EMAIL" } } if req.Phone != nil && *req.Phone != "" { *req.Phone = strings.TrimSpace(*req.Phone) if *req.Phone == "" { return errors.New("phone cannot be empty or whitespace only"), "INVALID_PHONE" } if len(*req.Phone) > 20 { return errors.New("phone cannot exceed 20 characters"), "INVALID_PHONE" } } if req.Address != nil && *req.Address != "" { *req.Address = strings.TrimSpace(*req.Address) if *req.Address == "" { return errors.New("address cannot be empty or whitespace only"), "INVALID_ADDRESS" } if len(*req.Address) > 500 { return errors.New("address cannot exceed 500 characters"), "INVALID_ADDRESS" } } return nil, "" } // ValidateUpdateCustomer validates update customer request func (v *CustomerValidatorImpl) ValidateUpdateCustomerRequest(req *contract.UpdateCustomerRequest) (error, string) { if err := v.validate.Struct(req); err != nil { return err, "VALIDATION_ERROR" } // Check if at least one field is provided if req.Name == nil && req.Email == nil && req.Phone == nil && req.Address == nil && req.IsActive == nil { return errors.New("at least one field must be provided for update"), "MISSING_FIELDS" } // Additional custom validations if req.Name != nil && *req.Name != "" { *req.Name = strings.TrimSpace(*req.Name) if *req.Name == "" { return errors.New("name cannot be empty or whitespace only"), "INVALID_NAME" } if len(*req.Name) > 255 { return errors.New("name cannot exceed 255 characters"), "INVALID_NAME" } } if req.Email != nil && *req.Email != "" { *req.Email = strings.TrimSpace(strings.ToLower(*req.Email)) if *req.Email == "" { return errors.New("email cannot be empty or whitespace only"), "INVALID_EMAIL" } if len(*req.Email) > 255 { return errors.New("email cannot exceed 255 characters"), "INVALID_EMAIL" } } if req.Phone != nil && *req.Phone != "" { *req.Phone = strings.TrimSpace(*req.Phone) if *req.Phone == "" { return errors.New("phone cannot be empty or whitespace only"), "INVALID_PHONE" } if len(*req.Phone) > 20 { return errors.New("phone cannot exceed 20 characters"), "INVALID_PHONE" } } if req.Address != nil && *req.Address != "" { *req.Address = strings.TrimSpace(*req.Address) if *req.Address == "" { return errors.New("address cannot be empty or whitespace only"), "INVALID_ADDRESS" } if len(*req.Address) > 500 { return errors.New("address cannot exceed 500 characters"), "INVALID_ADDRESS" } } return nil, "" } // ValidateListCustomersRequest validates list customers request func (v *CustomerValidatorImpl) ValidateListCustomersRequest(req *contract.ListCustomersRequest) (error, string) { if err := v.validate.Struct(req); err != nil { return err, "VALIDATION_ERROR" } // Additional custom validations if req.Search != "" { req.Search = strings.TrimSpace(req.Search) if len(req.Search) > 100 { return errors.New("search term cannot exceed 100 characters"), "INVALID_SEARCH" } } if req.SortBy != "" { req.SortBy = strings.ToLower(strings.TrimSpace(req.SortBy)) validSortFields := map[string]bool{ "name": true, "email": true, "created_at": true, "updated_at": true, } if !validSortFields[req.SortBy] { return errors.New("invalid sort field"), "INVALID_SORT_FIELD" } } if req.SortOrder != "" { req.SortOrder = strings.ToLower(strings.TrimSpace(req.SortOrder)) if req.SortOrder != "asc" && req.SortOrder != "desc" { return errors.New("sort order must be 'asc' or 'desc'"), "INVALID_SORT_ORDER" } } return nil, "" } // ValidateSetDefaultCustomer validates set default customer request func (v *CustomerValidatorImpl) ValidateSetDefaultCustomerRequest(req *contract.SetDefaultCustomerRequest) (error, string) { if err := v.validate.Struct(req); err != nil { return err, "VALIDATION_ERROR" } return nil, "" }