diff --git a/address/address.go b/address/address.go index 14cc632..0744b1c 100644 --- a/address/address.go +++ b/address/address.go @@ -1,5 +1,7 @@ package address +import "strings" + type AddressType string type ContactType string type SalutationType string @@ -52,19 +54,6 @@ type Address struct { Custom interface{} } -// Person is a field Customer and of Address -// Only Customer->Person has Contacts -type Person struct { - FirstName string - MiddleName string - LastName string - Title TitleType - Salutation SalutationType - Birthday string - Contacts map[string]*Contact // key must be contactID - DefaultContacts map[ContactType]string // reference by contactID -} - func (address *Address) GetID() string { return address.Id } @@ -97,3 +86,16 @@ func (address *Address) Equals(otherAddress *Address) bool { return equal } + +func (address *Address) TrimSpace() { + if address == nil { + return + } + address.Person.TrimSpace() + address.Street = strings.TrimSpace(address.Street) + address.StreetNumber = strings.TrimSpace(address.StreetNumber) + address.ZIP = strings.TrimSpace(address.ZIP) + address.City = strings.TrimSpace(address.City) + address.Country = strings.TrimSpace(address.Country) + address.CountryCode = strings.TrimSpace(address.CountryCode) +} diff --git a/address/person.go b/address/person.go new file mode 100644 index 0000000..2e4b3b0 --- /dev/null +++ b/address/person.go @@ -0,0 +1,30 @@ +package address + +import ( + "strings" +) + +// Person is a field Customer and of Address +// Only Customer->Person has Contacts +type Person struct { + FirstName string + MiddleName string + LastName string + Title TitleType + Salutation SalutationType + Birthday string + Contacts map[string]*Contact // key must be contactID + DefaultContacts map[ContactType]string // reference by contactID +} + +func (person *Person) TrimSpace() { + if person == nil { + return + } + person.FirstName = strings.TrimSpace(person.FirstName) + person.MiddleName = strings.TrimSpace(person.MiddleName) + person.LastName = strings.TrimSpace(person.LastName) + person.Title = TitleType(strings.TrimSpace(string(person.Title))) + person.Salutation = SalutationType(strings.TrimSpace(string(person.Salutation))) + person.Birthday = strings.TrimSpace(person.Birthday) +} diff --git a/address/validation.go b/address/validation.go new file mode 100644 index 0000000..fd32983 --- /dev/null +++ b/address/validation.go @@ -0,0 +1,63 @@ +package address + +import ( + "errors" + + "github.com/hashicorp/go-multierror" +) + +func (addr *Address) IsComplete() error { + addr.TrimSpace() + // Return error if required field is missing + var mErr *multierror.Error + + if addr == nil { + mErr = multierror.Append(mErr, errors.New("address is nil")) + return mErr.ErrorOrNil() + } + + errPerson := addr.Person.IsComplete() + if errPerson != nil { + mErr = multierror.Append(mErr, errPerson) + } + + if addr.Street == "" { + mErr = multierror.Append(mErr, errors.New("address street is empty")) + } + if addr.StreetNumber == "" { + mErr = multierror.Append(mErr, errors.New("address street number is empty")) + } + if len(addr.ZIP) < 4 { + mErr = multierror.Append(mErr, errors.New("address zip is not valid")) + } + if addr.City == "" { + mErr = multierror.Append(mErr, errors.New("address city is empty")) + } + if addr.Country == "" { + mErr = multierror.Append(mErr, errors.New("address country is empty")) + } + if addr.CountryCode == "" { + mErr = multierror.Append(mErr, errors.New("address country code is empty")) + } + + return mErr.ErrorOrNil() +} + +func (person *Person) IsComplete() error { + var mErr *multierror.Error + if person == nil { + mErr = multierror.Append(mErr, errors.New("person is nil")) + return mErr.ErrorOrNil() + } + person.TrimSpace() + if person.Salutation == "" { + mErr = multierror.Append(mErr, errors.New("person salutation is empty")) + } + if person.FirstName == "" { + mErr = multierror.Append(mErr, errors.New("person firstname is empty")) + } + if person.LastName == "" { + mErr = multierror.Append(mErr, errors.New("person lastname is empty")) + } + return mErr.ErrorOrNil() +} diff --git a/customer/customer.go b/customer/customer.go index b22babc..ecacb5b 100644 --- a/customer/customer.go +++ b/customer/customer.go @@ -61,7 +61,6 @@ type Customer struct { Email string // unique, used as Login Credential Person *address.Person IsGuest bool - IsComplete bool // upsert checks if customer data is complete, so that a customer could place an order Company *Company Addresses []*address.Address Localization *Localization @@ -189,44 +188,6 @@ func (customer *Customer) OverrideId(id string) error { return customer.Upsert() } -// checkFields Checks if all required fields are specified -// @TODO which are teh required fields -func CheckRequiredAddressFields(address *address.Address) error { - // Return error if required field is missing - var mErr *multierror.Error - - if address.Person == nil { - mErr = multierror.Append(mErr, errors.New("required person is nil")) - } else { - if address.Person.Salutation == "" { - mErr = multierror.Append(mErr, errors.New("required person salutation is empty")) - } - if address.Person.FirstName == "" { - mErr = multierror.Append(mErr, errors.New("required person firstname is empty")) - } - if address.Person.LastName == "" { - mErr = multierror.Append(mErr, errors.New("required person lastname is empty")) - } - } - if address.Street == "" { - mErr = multierror.Append(mErr, errors.New("required address street is empty")) - } - if address.StreetNumber == "" { - mErr = multierror.Append(mErr, errors.New("required address street number is empty")) - } - if address.ZIP == "" { - mErr = multierror.Append(mErr, errors.New("required address zip is empty")) - } - if address.City == "" { - mErr = multierror.Append(mErr, errors.New("required address city is empty")) - } - if address.Country == "" { - mErr = multierror.Append(mErr, errors.New("required address country is empty")) - } - - return mErr.ErrorOrNil() -} - func (customer *Customer) AddDefaultBillingAddress(addr *address.Address) (string, error) { addr.Type = address.AddressDefaultBilling return customer.AddAddress(addr) @@ -239,7 +200,7 @@ func (customer *Customer) AddDefaultShippingAddress(addr *address.Address) (stri // AddAddress adds a new address to the customers profile and returns its unique id func (customer *Customer) AddAddress(addr *address.Address) (string, error) { - err := CheckRequiredAddressFields(addr) + err := addr.IsComplete() if err != nil { log.Println("Error", err) return "", err @@ -307,7 +268,7 @@ func (customer *Customer) ChangeAddress(addr *address.Address) error { log.Println("Error: Could not find address with id "+addr.GetID(), "for customer ", customer.Person.LastName) return err } - err = CheckRequiredAddressFields(addr) + err = addr.IsComplete() if err != nil { return err } diff --git a/customer/customer_test.go b/customer/customer_test.go index a377339..b506dd6 100644 --- a/customer/customer_test.go +++ b/customer/customer_test.go @@ -149,7 +149,8 @@ func TestCustomerChangeAddress(t *testing.T) { Street: "Holzweg", StreetNumber: "5", City: "Bern", - Country: "CH", + Country: "Schweiz", + CountryCode: "CH", ZIP: "1234", } log.Println("Original Address:") @@ -170,7 +171,8 @@ func TestCustomerChangeAddress(t *testing.T) { Street: "Steinweg", StreetNumber: "5", City: "Bern", - Country: "CH", + Country: "Schweiz", + CountryCode: "CH", ZIP: "1234", } err = customer.ChangeAddress(addressNew) @@ -193,7 +195,7 @@ func TestCustomerChangeAddress(t *testing.T) { } } -func TestCheckRequiredAddressFields(t *testing.T) { +func TestAddressComplete(t *testing.T) { type args struct { address *address.Address } @@ -207,7 +209,7 @@ func TestCheckRequiredAddressFields(t *testing.T) { args: args{ address: &address.Address{}, }, - wantErr: "6 errors occurred:\n\t* required person is nil\n\t* required address street is empty\n\t* required address street number is empty\n\t* required address zip is empty\n\t* required address city is empty\n\t* required address country is empty\n\n", + wantErr: "7 errors occurred:\n\t* person is nil\n\t* address street is empty\n\t* address street number is empty\n\t* address zip is not valid\n\t* address city is empty\n\t* address country is empty\n\t* address country code is empty\n\n", }, { name: "all person fields empty", @@ -216,12 +218,13 @@ func TestCheckRequiredAddressFields(t *testing.T) { Person: &address.Person{}, Street: "x", StreetNumber: "x", - ZIP: "x", + ZIP: "xxxx", City: "x", Country: "x", + CountryCode: "x", }, }, - wantErr: "3 errors occurred:\n\t* required person salutation is empty\n\t* required person firstname is empty\n\t* required person lastname is empty\n\n", + wantErr: "3 errors occurred:\n\t* person salutation is empty\n\t* person firstname is empty\n\t* person lastname is empty\n\n", }, { name: "all fields set", @@ -234,9 +237,10 @@ func TestCheckRequiredAddressFields(t *testing.T) { }, Street: "x", StreetNumber: "x", - ZIP: "x", + ZIP: "xxxx", City: "x", Country: "x", + CountryCode: "x", }, }, wantErr: "", @@ -244,7 +248,7 @@ func TestCheckRequiredAddressFields(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := CheckRequiredAddressFields(tt.args.address) + err := tt.args.address.IsComplete() if tt.wantErr != "" { assert.EqualError(t, err, tt.wantErr) } else { diff --git a/customer/validation.go b/customer/validation.go new file mode 100644 index 0000000..223fd66 --- /dev/null +++ b/customer/validation.go @@ -0,0 +1,39 @@ +package customer + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-multierror" +) + +// IsCustomerComplete returns an error if not all mandatory data is set +func (customer *Customer) IsCustomerComplete() error { + addr, err := customer.GetDefaultBillingAddress() + if err != nil { + return err + } + + var mErr *multierror.Error + if e := customer.GetEmail(); !strings.ContainsRune(e, '@') { + mErr = multierror.Append(mErr, fmt.Errorf("invalid email address %q", e)) + } + + if err := addr.IsComplete(); err != nil { + mErr = multierror.Append(mErr, err) + } + + person := customer.GetPerson() + if err := person.IsComplete(); err != nil { + mErr = multierror.Append(mErr, fmt.Errorf("person is not complete")) + } + + // Birthday is not part of regular person.IsComplete() check + if person != nil { + if len(person.Birthday) != 10 { + mErr = multierror.Append(mErr, fmt.Errorf("person birthday not valid")) + } + } + + return mErr.ErrorOrNil() +}