diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2cc5af06..658f3b52 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,15 +17,10 @@ env: jobs: build: runs-on: ubuntu-latest - strategy: - matrix: - go-version: [ '1.18', '1.19', '1.20', '1.21.x' ] steps: - uses: actions/checkout@v4 - name: Setup Go uses: actions/setup-go@v4 - with: - go-version: ${{ matrix.go-version }} - name: Install dependencies run: | go get . diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..7c6a0d4a --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/apimatic/go-core-runtime v0.0.13 h1:KBrOoUbgdIYbjH+TrQNXkbK7QGBovdX43wr7q5Ta6yE= +github.com/apimatic/go-core-runtime v0.0.13/go.mod h1:kyqGg2v3OTV7o2fXHgbHLZPMinqZvIqw1JwdEd64OzM= diff --git a/models/coupon.go b/models/coupon.go index d7e55a28..101e78b9 100644 --- a/models/coupon.go +++ b/models/coupon.go @@ -1,210 +1,210 @@ package models import ( - "encoding/json" + "encoding/json" ) // Coupon represents a Coupon struct. type Coupon struct { - Id *int `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Code *string `json:"code,omitempty"` - Description *string `json:"description,omitempty"` - Amount Optional[float64] `json:"amount"` - AmountInCents Optional[int] `json:"amount_in_cents"` - ProductFamilyId *int `json:"product_family_id,omitempty"` - ProductFamilyName Optional[string] `json:"product_family_name"` - StartDate *string `json:"start_date,omitempty"` - EndDate Optional[string] `json:"end_date"` - Percentage Optional[string] `json:"percentage"` - Recurring *bool `json:"recurring,omitempty"` - RecurringScheme *RecurringScheme `json:"recurring_scheme,omitempty"` - DurationPeriodCount Optional[int] `json:"duration_period_count"` - DurationInterval Optional[int] `json:"duration_interval"` - DurationIntervalUnit Optional[string] `json:"duration_interval_unit"` - DurationIntervalSpan Optional[string] `json:"duration_interval_span"` - AllowNegativeBalance *bool `json:"allow_negative_balance,omitempty"` - ArchivedAt Optional[string] `json:"archived_at"` - ConversionLimit Optional[string] `json:"conversion_limit"` - Stackable *bool `json:"stackable,omitempty"` - CompoundingStrategy *interface{} `json:"compounding_strategy,omitempty"` - UseSiteExchangeRate *bool `json:"use_site_exchange_rate,omitempty"` - CreatedAt *string `json:"created_at,omitempty"` - UpdatedAt *string `json:"updated_at,omitempty"` - DiscountType *DiscountType `json:"discount_type,omitempty"` - ExcludeMidPeriodAllocations *bool `json:"exclude_mid_period_allocations,omitempty"` - ApplyOnCancelAtEndOfPeriod *bool `json:"apply_on_cancel_at_end_of_period,omitempty"` - CouponRestrictions []CouponRestriction `json:"coupon_restrictions,omitempty"` + Id *int `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Code *string `json:"code,omitempty"` + Description *string `json:"description,omitempty"` + Amount Optional[float64] `json:"amount"` + AmountInCents Optional[int] `json:"amount_in_cents"` + ProductFamilyId *int `json:"product_family_id,omitempty"` + ProductFamilyName Optional[string] `json:"product_family_name"` + StartDate *string `json:"start_date,omitempty"` + EndDate Optional[string] `json:"end_date"` + Percentage Optional[string] `json:"percentage"` + Recurring *bool `json:"recurring,omitempty"` + RecurringScheme *RecurringScheme `json:"recurring_scheme,omitempty"` + DurationPeriodCount Optional[int] `json:"duration_period_count"` + DurationInterval Optional[int] `json:"duration_interval"` + DurationIntervalUnit Optional[string] `json:"duration_interval_unit"` + DurationIntervalSpan Optional[string] `json:"duration_interval_span"` + AllowNegativeBalance *bool `json:"allow_negative_balance,omitempty"` + ArchivedAt Optional[string] `json:"archived_at"` + ConversionLimit Optional[string] `json:"conversion_limit"` + Stackable *bool `json:"stackable,omitempty"` + CompoundingStrategy *interface{} `json:"compounding_strategy,omitempty"` + UseSiteExchangeRate *bool `json:"use_site_exchange_rate,omitempty"` + CreatedAt *string `json:"created_at,omitempty"` + UpdatedAt *string `json:"updated_at,omitempty"` + DiscountType *DiscountType `json:"discount_type,omitempty"` + ExcludeMidPeriodAllocations *bool `json:"exclude_mid_period_allocations,omitempty"` + ApplyOnCancelAtEndOfPeriod *bool `json:"apply_on_cancel_at_end_of_period,omitempty"` + CouponRestrictions []CouponRestriction `json:"coupon_restrictions,omitempty"` } -// MarshalJSON implements the json.Marshaler interface for Coupon. +// MarshalJSON implements the json.Marshaler interface for Coupon. // It customizes the JSON marshaling process for Coupon objects. func (c *Coupon) MarshalJSON() ( - []byte, - error) { - return json.Marshal(c.toMap()) + []byte, + error) { + return json.Marshal(c.toMap()) } // toMap converts the Coupon object to a map representation for JSON marshaling. func (c *Coupon) toMap() map[string]any { - structMap := make(map[string]any) - if c.Id != nil { - structMap["id"] = c.Id - } - if c.Name != nil { - structMap["name"] = c.Name - } - if c.Code != nil { - structMap["code"] = c.Code - } - if c.Description != nil { - structMap["description"] = c.Description - } - if c.Amount.IsValueSet() { - structMap["amount"] = c.Amount.Value() - } - if c.AmountInCents.IsValueSet() { - structMap["amount_in_cents"] = c.AmountInCents.Value() - } - if c.ProductFamilyId != nil { - structMap["product_family_id"] = c.ProductFamilyId - } - if c.ProductFamilyName.IsValueSet() { - structMap["product_family_name"] = c.ProductFamilyName.Value() - } - if c.StartDate != nil { - structMap["start_date"] = c.StartDate - } - if c.EndDate.IsValueSet() { - structMap["end_date"] = c.EndDate.Value() - } - if c.Percentage.IsValueSet() { - structMap["percentage"] = c.Percentage.Value() - } - if c.Recurring != nil { - structMap["recurring"] = c.Recurring - } - if c.RecurringScheme != nil { - structMap["recurring_scheme"] = c.RecurringScheme - } - if c.DurationPeriodCount.IsValueSet() { - structMap["duration_period_count"] = c.DurationPeriodCount.Value() - } - if c.DurationInterval.IsValueSet() { - structMap["duration_interval"] = c.DurationInterval.Value() - } - if c.DurationIntervalUnit.IsValueSet() { - structMap["duration_interval_unit"] = c.DurationIntervalUnit.Value() - } - if c.DurationIntervalSpan.IsValueSet() { - structMap["duration_interval_span"] = c.DurationIntervalSpan.Value() - } - if c.AllowNegativeBalance != nil { - structMap["allow_negative_balance"] = c.AllowNegativeBalance - } - if c.ArchivedAt.IsValueSet() { - structMap["archived_at"] = c.ArchivedAt.Value() - } - if c.ConversionLimit.IsValueSet() { - structMap["conversion_limit"] = c.ConversionLimit.Value() - } - if c.Stackable != nil { - structMap["stackable"] = c.Stackable - } - if c.CompoundingStrategy != nil { - structMap["compounding_strategy"] = c.CompoundingStrategy - } - if c.UseSiteExchangeRate != nil { - structMap["use_site_exchange_rate"] = c.UseSiteExchangeRate - } - if c.CreatedAt != nil { - structMap["created_at"] = c.CreatedAt - } - if c.UpdatedAt != nil { - structMap["updated_at"] = c.UpdatedAt - } - if c.DiscountType != nil { - structMap["discount_type"] = c.DiscountType - } - if c.ExcludeMidPeriodAllocations != nil { - structMap["exclude_mid_period_allocations"] = c.ExcludeMidPeriodAllocations - } - if c.ApplyOnCancelAtEndOfPeriod != nil { - structMap["apply_on_cancel_at_end_of_period"] = c.ApplyOnCancelAtEndOfPeriod - } - if c.CouponRestrictions != nil { - structMap["coupon_restrictions"] = c.CouponRestrictions - } - return structMap + structMap := make(map[string]any) + if c.Id != nil { + structMap["id"] = c.Id + } + if c.Name != nil { + structMap["name"] = c.Name + } + if c.Code != nil { + structMap["code"] = c.Code + } + if c.Description != nil { + structMap["description"] = c.Description + } + if c.Amount.IsValueSet() { + structMap["amount"] = c.Amount.Value() + } + if c.AmountInCents.IsValueSet() { + structMap["amount_in_cents"] = c.AmountInCents.Value() + } + if c.ProductFamilyId != nil { + structMap["product_family_id"] = c.ProductFamilyId + } + if c.ProductFamilyName.IsValueSet() { + structMap["product_family_name"] = c.ProductFamilyName.Value() + } + if c.StartDate != nil { + structMap["start_date"] = c.StartDate + } + if c.EndDate.IsValueSet() { + structMap["end_date"] = c.EndDate.Value() + } + if c.Percentage.IsValueSet() { + structMap["percentage"] = c.Percentage.Value() + } + if c.Recurring != nil { + structMap["recurring"] = c.Recurring + } + if c.RecurringScheme != nil { + structMap["recurring_scheme"] = c.RecurringScheme + } + if c.DurationPeriodCount.IsValueSet() { + structMap["duration_period_count"] = c.DurationPeriodCount.Value() + } + if c.DurationInterval.IsValueSet() { + structMap["duration_interval"] = c.DurationInterval.Value() + } + if c.DurationIntervalUnit.IsValueSet() { + structMap["duration_interval_unit"] = c.DurationIntervalUnit.Value() + } + if c.DurationIntervalSpan.IsValueSet() { + structMap["duration_interval_span"] = c.DurationIntervalSpan.Value() + } + if c.AllowNegativeBalance != nil { + structMap["allow_negative_balance"] = c.AllowNegativeBalance + } + if c.ArchivedAt.IsValueSet() { + structMap["archived_at"] = c.ArchivedAt.Value() + } + if c.ConversionLimit.IsValueSet() { + structMap["conversion_limit"] = c.ConversionLimit.Value() + } + if c.Stackable != nil { + structMap["stackable"] = c.Stackable + } + if c.CompoundingStrategy != nil { + structMap["compounding_strategy"] = c.CompoundingStrategy + } + if c.UseSiteExchangeRate != nil { + structMap["use_site_exchange_rate"] = c.UseSiteExchangeRate + } + if c.CreatedAt != nil { + structMap["created_at"] = c.CreatedAt + } + if c.UpdatedAt != nil { + structMap["updated_at"] = c.UpdatedAt + } + if c.DiscountType != nil { + structMap["discount_type"] = c.DiscountType + } + if c.ExcludeMidPeriodAllocations != nil { + structMap["exclude_mid_period_allocations"] = c.ExcludeMidPeriodAllocations + } + if c.ApplyOnCancelAtEndOfPeriod != nil { + structMap["apply_on_cancel_at_end_of_period"] = c.ApplyOnCancelAtEndOfPeriod + } + if c.CouponRestrictions != nil { + structMap["coupon_restrictions"] = c.CouponRestrictions + } + return structMap } -// UnmarshalJSON implements the json.Unmarshaler interface for Coupon. +// UnmarshalJSON implements the json.Unmarshaler interface for Coupon. // It customizes the JSON unmarshaling process for Coupon objects. func (c *Coupon) UnmarshalJSON(input []byte) error { - temp := &struct { - Id *int `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Code *string `json:"code,omitempty"` - Description *string `json:"description,omitempty"` - Amount Optional[float64] `json:"amount"` - AmountInCents Optional[int] `json:"amount_in_cents"` - ProductFamilyId *int `json:"product_family_id,omitempty"` - ProductFamilyName Optional[string] `json:"product_family_name"` - StartDate *string `json:"start_date,omitempty"` - EndDate Optional[string] `json:"end_date"` - Percentage Optional[string] `json:"percentage"` - Recurring *bool `json:"recurring,omitempty"` - RecurringScheme *RecurringScheme `json:"recurring_scheme,omitempty"` - DurationPeriodCount Optional[int] `json:"duration_period_count"` - DurationInterval Optional[int] `json:"duration_interval"` - DurationIntervalUnit Optional[string] `json:"duration_interval_unit"` - DurationIntervalSpan Optional[string] `json:"duration_interval_span"` - AllowNegativeBalance *bool `json:"allow_negative_balance,omitempty"` - ArchivedAt Optional[string] `json:"archived_at"` - ConversionLimit Optional[string] `json:"conversion_limit"` - Stackable *bool `json:"stackable,omitempty"` - CompoundingStrategy *interface{} `json:"compounding_strategy,omitempty"` - UseSiteExchangeRate *bool `json:"use_site_exchange_rate,omitempty"` - CreatedAt *string `json:"created_at,omitempty"` - UpdatedAt *string `json:"updated_at,omitempty"` - DiscountType *DiscountType `json:"discount_type,omitempty"` - ExcludeMidPeriodAllocations *bool `json:"exclude_mid_period_allocations,omitempty"` - ApplyOnCancelAtEndOfPeriod *bool `json:"apply_on_cancel_at_end_of_period,omitempty"` - CouponRestrictions []CouponRestriction `json:"coupon_restrictions,omitempty"` - }{} - err := json.Unmarshal(input, &temp) - if err != nil { - return err - } - - c.Id = temp.Id - c.Name = temp.Name - c.Code = temp.Code - c.Description = temp.Description - c.Amount = temp.Amount - c.AmountInCents = temp.AmountInCents - c.ProductFamilyId = temp.ProductFamilyId - c.ProductFamilyName = temp.ProductFamilyName - c.StartDate = temp.StartDate - c.EndDate = temp.EndDate - c.Percentage = temp.Percentage - c.Recurring = temp.Recurring - c.RecurringScheme = temp.RecurringScheme - c.DurationPeriodCount = temp.DurationPeriodCount - c.DurationInterval = temp.DurationInterval - c.DurationIntervalUnit = temp.DurationIntervalUnit - c.DurationIntervalSpan = temp.DurationIntervalSpan - c.AllowNegativeBalance = temp.AllowNegativeBalance - c.ArchivedAt = temp.ArchivedAt - c.ConversionLimit = temp.ConversionLimit - c.Stackable = temp.Stackable - c.CompoundingStrategy = temp.CompoundingStrategy - c.UseSiteExchangeRate = temp.UseSiteExchangeRate - c.CreatedAt = temp.CreatedAt - c.UpdatedAt = temp.UpdatedAt - c.DiscountType = temp.DiscountType - c.ExcludeMidPeriodAllocations = temp.ExcludeMidPeriodAllocations - c.ApplyOnCancelAtEndOfPeriod = temp.ApplyOnCancelAtEndOfPeriod - c.CouponRestrictions = temp.CouponRestrictions - return nil + temp := &struct { + Id *int `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Code *string `json:"code,omitempty"` + Description *string `json:"description,omitempty"` + Amount Optional[float64] `json:"amount"` + AmountInCents Optional[int] `json:"amount_in_cents"` + ProductFamilyId *int `json:"product_family_id,omitempty"` + ProductFamilyName Optional[string] `json:"product_family_name"` + StartDate *string `json:"start_date,omitempty"` + EndDate Optional[string] `json:"end_date"` + Percentage Optional[string] `json:"percentage"` + Recurring *bool `json:"recurring,omitempty"` + RecurringScheme *RecurringScheme `json:"recurring_scheme,omitempty"` + DurationPeriodCount Optional[int] `json:"duration_period_count"` + DurationInterval Optional[int] `json:"duration_interval"` + DurationIntervalUnit Optional[string] `json:"duration_interval_unit"` + DurationIntervalSpan Optional[string] `json:"duration_interval_span"` + AllowNegativeBalance *bool `json:"allow_negative_balance,omitempty"` + ArchivedAt Optional[string] `json:"archived_at"` + ConversionLimit Optional[string] `json:"conversion_limit"` + Stackable *bool `json:"stackable,omitempty"` + CompoundingStrategy *interface{} `json:"compounding_strategy,omitempty"` + UseSiteExchangeRate *bool `json:"use_site_exchange_rate,omitempty"` + CreatedAt *string `json:"created_at,omitempty"` + UpdatedAt *string `json:"updated_at,omitempty"` + DiscountType *DiscountType `json:"discount_type,omitempty"` + ExcludeMidPeriodAllocations *bool `json:"exclude_mid_period_allocations,omitempty"` + ApplyOnCancelAtEndOfPeriod *bool `json:"apply_on_cancel_at_end_of_period,omitempty"` + CouponRestrictions []CouponRestriction `json:"coupon_restrictions,omitempty"` + }{} + err := json.Unmarshal(input, &temp) + if err != nil { + return err + } + + c.Id = temp.Id + c.Name = temp.Name + c.Code = temp.Code + c.Description = temp.Description + c.Amount = temp.Amount + c.AmountInCents = temp.AmountInCents + c.ProductFamilyId = temp.ProductFamilyId + c.ProductFamilyName = temp.ProductFamilyName + c.StartDate = temp.StartDate + c.EndDate = temp.EndDate + c.Percentage = temp.Percentage + c.Recurring = temp.Recurring + c.RecurringScheme = temp.RecurringScheme + c.DurationPeriodCount = temp.DurationPeriodCount + c.DurationInterval = temp.DurationInterval + c.DurationIntervalUnit = temp.DurationIntervalUnit + c.DurationIntervalSpan = temp.DurationIntervalSpan + c.AllowNegativeBalance = temp.AllowNegativeBalance + c.ArchivedAt = temp.ArchivedAt + c.ConversionLimit = temp.ConversionLimit + c.Stackable = temp.Stackable + c.CompoundingStrategy = temp.CompoundingStrategy + c.UseSiteExchangeRate = temp.UseSiteExchangeRate + c.CreatedAt = temp.CreatedAt + c.UpdatedAt = temp.UpdatedAt + c.DiscountType = temp.DiscountType + c.ExcludeMidPeriodAllocations = temp.ExcludeMidPeriodAllocations + c.ApplyOnCancelAtEndOfPeriod = temp.ApplyOnCancelAtEndOfPeriod + c.CouponRestrictions = temp.CouponRestrictions + return nil } diff --git a/test/api_test.go b/test/api_test.go index c2b17e0c..21000c9e 100644 --- a/test/api_test.go +++ b/test/api_test.go @@ -1,13 +1,11 @@ package test import ( - "context" - "net/http" "testing" "github.com/caarlos0/env/v10" + "github.com/jaswdr/faker" advancedbilling "github.com/maxio-com/ab-golang-sdk" - "github.com/maxio-com/ab-golang-sdk/models" "github.com/stretchr/testify/suite" ) @@ -18,14 +16,21 @@ type Config struct { Subdomain string `env:"TEST_SUBDOMAIN,required"` } -type APITestSuite struct { +type APISuite struct { suite.Suite + fkr faker.Faker client advancedbilling.ClientInterface unauthorizedClient advancedbilling.ClientInterface } -func (s *APITestSuite) SetupTest() { +func TestAPITestSuite(t *testing.T) { + suite.Run(t, new(APISuite)) +} + +func (s *APISuite) SetupTest() { + s.fkr = faker.New() + cfg := Config{} if err := env.Parse(&cfg); err != nil { panic(err) @@ -46,90 +51,3 @@ func (s *APITestSuite) SetupTest() { s.client = advancedbilling.NewClient(config) s.unauthorizedClient = advancedbilling.NewClient(configUnauthorized) } - -func (s *APITestSuite) TestExample() { - s.T().Log(s.client.Configuration().Domain()) -} - -func (s *APITestSuite) TestReadSite() { - cases := []struct { - name string - client advancedbilling.ClientInterface - assert func(*testing.T, models.ApiResponse[models.SiteResponse]) - expectedErr bool - }{ - { - name: "success", - client: s.client, - expectedErr: false, - assert: func(t *testing.T, resp models.ApiResponse[models.SiteResponse]) { - s.Equal(http.StatusOK, resp.Response.StatusCode, "status code") - - respSite := resp.Data.Site - s.Equal(4718, *respSite.Id, "ID") - s.Equal("GO SDK env", *respSite.Name, "Name") - s.Equal("go-sdk", *respSite.Subdomain, "Subdomain") - s.Equal("USD", *respSite.Currency, "Currency") - s.Equal(722159, *respSite.SellerId, "SellerID") - s.EqualValues([]string{}, respSite.NonPrimaryCurrencies, "NonPrimaryCurrencies") - s.True(*respSite.RelationshipInvoicingEnabled, "RelationshipInvoiceEnabled") - s.False(*respSite.CustomerHierarchyEnabled, "CustomerHierarchyEnabled,") - s.False(*respSite.WhopaysEnabled, "WhopaysEnabled") - s.Equal("self-ungrouped", *respSite.WhopaysDefaultPayer, "WhopaysDefaultPayer") - s.Equal(string(models.PaymentCollectionMethod_AUTOMATIC), *respSite.DefaultPaymentCollectionMethod, "DefaultPaymentCollectionMethod") - - allocationSettings := respSite.AllocationSettings - s.Equal(models.CreditType_PRORATED, *allocationSettings.UpgradeCharge.Value(), "UpgradeCharge") - s.Equal(models.CreditType_NONE, *allocationSettings.DowngradeCredit.Value(), "DowngradeCredit") - s.Equal("true", *allocationSettings.AccrueCharge, "AccrueCharge") - - organizationAddress := respSite.OrganizationAddress - s.Equal("Asdf Street", *organizationAddress.Street.Value(), "Street") - s.Equal("123/444", *organizationAddress.Line2.Value(), "Line2") - s.Equal("San Antonio", *organizationAddress.City.Value(), "City") - s.Equal("TX", *organizationAddress.State.Value(), "State") - s.Equal("78015", *organizationAddress.Zip.Value(), "Zip") - s.Equal("US", *organizationAddress.Country.Value(), "Country") - s.Equal("Developer Experience", *organizationAddress.Name.Value(), "AddressName") - s.Equal("555 111 222", *organizationAddress.Phone.Value(), "Phone") - - taxConfiguration := respSite.TaxConfiguration - s.Equal(models.TaxConfigurationKind_CUSTOM, *taxConfiguration.Kind, "Kind") - s.Equal(models.TaxDestinationAddress_SHIPPINGTHENBILLING, *taxConfiguration.DestinationAddress, "TaxDestinationAddress") - s.False(*taxConfiguration.FullyConfigured, "FullyConfigured") - - netTerms := respSite.NetTerms - s.Equal(0, *netTerms.DefaultNetTerms, "DefaultNetTerms") - s.Equal(0, *netTerms.AutomaticNetTerms, "AutomaticNetTerms") - s.Equal(0, *netTerms.RemittanceNetTerms, "RemittanceNetTerms") - s.False(*netTerms.NetTermsOnRemittanceSignupsEnabled, "NetTermsOnRemittanceSignupsEnabled") - s.False(*netTerms.CustomNetTermsEnabled, "CustomNetTermsEnabled") - - s.True(*respSite.Test, "Test") - }, - }, - { - name: "unauthorized", - client: s.unauthorizedClient, - assert: func(t *testing.T, resp models.ApiResponse[models.SiteResponse]) { - s.Equal(http.StatusUnauthorized, resp.Response.StatusCode) - }, - expectedErr: true, - }, - } - - for _, c := range cases { - s.T().Run(c.name, func(t *testing.T) { - resp, err := c.client.SitesController().ReadSite(context.Background()) - if !c.expectedErr { - s.NoErrorf(err, "could not read site") - } - c.assert(t, resp) - }) - } - -} - -func TestAPITestSuite(t *testing.T) { - suite.Run(t, new(APITestSuite)) -} diff --git a/test/go.mod b/test/go.mod index 902e2d82..432926af 100644 --- a/test/go.mod +++ b/test/go.mod @@ -5,6 +5,7 @@ go 1.21 require ( github.com/apimatic/go-core-runtime v0.0.13 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/jaswdr/faker v1.19.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/test/go.sum b/test/go.sum index 99fb14b3..744496ff 100644 --- a/test/go.sum +++ b/test/go.sum @@ -4,6 +4,8 @@ github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdz github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jaswdr/faker v1.19.1 h1:xBoz8/O6r0QAR8eEvKJZMdofxiRH+F0M/7MU9eNKhsM= +github.com/jaswdr/faker v1.19.1/go.mod h1:x7ZlyB1AZqwqKZgyQlnqEG8FDptmHlncA5u2zY/yi6w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= diff --git a/test/helpers_test.go b/test/helpers_test.go new file mode 100644 index 00000000..f3cbee24 --- /dev/null +++ b/test/helpers_test.go @@ -0,0 +1,163 @@ +package test + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/maxio-com/ab-golang-sdk/models" +) + +func (s *APISuite) createCustomer(ctx context.Context) models.Customer { + person := s.fkr.Person() + + resp, err := s.client.CustomersController().CreateCustomer(ctx, &models.CreateCustomerRequest{ + Customer: models.CreateCustomer{ + FirstName: person.FirstName(), + LastName: person.LastName(), + Email: person.Contact().Email, + Organization: strPtr(s.fkr.Company().Name()), + Reference: strPtr(fmt.Sprintf("%d", s.fkr.RandomNumber(10))), + Address: strPtr(person.Faker.Address().StreetAddress()), + City: strPtr(person.Faker.Address().City()), + State: strPtr(person.Faker.Address().State()), + Zip: strPtr(person.Faker.Address().PostCode()), + Country: strPtr(person.Faker.Address().Country()), + Phone: strPtr(person.Faker.Address().Country()), + }, + }) + + s.NoErrorf(err, "create customer err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create customer status code") + + return resp.Data.Customer +} + +func (s *APISuite) createProductFamily(ctx context.Context) models.ProductFamily { + resp, err := s.client.ProductFamiliesController().CreateProductFamily(ctx, &models.CreateProductFamilyRequest{ + ProductFamily: models.CreateProductFamily{ + Name: strPtr(s.fkr.Company().Name()), + }, + }) + + s.NoErrorf(err, "create product family err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create product family status code") + + return *resp.Data.ProductFamily +} + +func (s *APISuite) createProduct(ctx context.Context, productFamilyID int) models.Product { + resp, err := s.client.ProductsController().CreateProduct(ctx, productFamilyID, &models.CreateOrUpdateProductRequest{ + Product: models.CreateOrUpdateProduct{ + Name: s.fkr.RandomStringWithLength(30), + Description: "Testable product", + PriceInCents: 50, + Interval: 1, + IntervalUnit: models.IntervalUnit_MONTH, + }, + }) + + s.NoErrorf(err, "create product err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create product status code") + + return resp.Data.Product +} + +func (s *APISuite) createCoupon(ctx context.Context, productFamilyID int) models.Coupon { + coupon := &models.Coupon{ + Name: strPtr("100\\% off first month of usage"), + Code: strPtr("100OFF" + s.fkr.RandomStringWithLength(30)), + Description: strPtr("100\\% off one-time"), + Percentage: models.NewOptional[string](strPtr("50")), + AllowNegativeBalance: boolPtr(false), + Recurring: boolPtr(false), + EndDate: models.NewOptional[string](strPtr(newDate())), + ProductFamilyId: &productFamilyID, + Stackable: boolPtr(false), + ExcludeMidPeriodAllocations: boolPtr(true), + ApplyOnCancelAtEndOfPeriod: boolPtr(true), + } + + resp, err := s.client.CouponsController().CreateCoupon(ctx, productFamilyID, &models.CreateOrUpdateCoupon{ + Coupon: interfacePtr(coupon), + }) + + s.NoErrorf(err, "create coupon err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create coupon err") + + return *resp.Data.Coupon +} + +type MeteredComponent struct { + Name string `json:"name"` + UnitName string `json:"unit_name"` + Taxable bool `json:"taxable"` + PricingScheme string `json:"pricing_scheme"` + Prices []Price `json:"prices"` +} + +type Price struct { + StartingQuantity int `json:"starting_quantity"` + UnitPrice int `json:"unit_price"` +} + +func (s *APISuite) createMeteredComponent(ctx context.Context, productFamilyID int) models.Component { + component := struct { + MeteredComponent MeteredComponent `json:"metered_component"` + }{ + MeteredComponent: MeteredComponent{ + Name: "test 2", + UnitName: "test message", + Taxable: false, + PricingScheme: "stairstep", + Prices: []Price{{ + StartingQuantity: 1, + UnitPrice: 1, + }, + }, + }, + } + + resp, err := s.client.ComponentsController().CreateComponent( + ctx, + productFamilyID, + models.ComponentKindPath_METEREDCOMPONENTS, + interfacePtr(component), + ) + + s.NoErrorf(err, "create component err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create component err") + + return resp.Data.Component +} + +func strPtr(v string) *string { + return &v +} + +func boolPtr(v bool) *bool { + return &v +} + +func intPtr(v int) *int { + return &v +} + +func interfacePtr(v interface{}) *interface{} { + return &v +} + +func toPtr[T any](v T) *T { + return &v +} + +func newDate() string { + t := time.Now().Add(time.Hour) + + return fmt.Sprintf("%d-%d-%d", t.Year(), t.Month(), t.Day()) +} + +func timePtr(v time.Time) *time.Time { + return &v +} diff --git a/test/site_test.go b/test/site_test.go new file mode 100644 index 00000000..d7cd0b4c --- /dev/null +++ b/test/site_test.go @@ -0,0 +1,89 @@ +package test + +import ( + "context" + "net/http" + "testing" + + advancedbilling "github.com/maxio-com/ab-golang-sdk" + "github.com/maxio-com/ab-golang-sdk/models" +) + +func (s *APISuite) TestReadSite() { + cases := []struct { + name string + client advancedbilling.ClientInterface + assert func(*testing.T, models.ApiResponse[models.SiteResponse]) + expectedErr bool + }{ + { + name: "success", + client: s.client, + expectedErr: false, + assert: func(t *testing.T, resp models.ApiResponse[models.SiteResponse]) { + s.Equal(http.StatusOK, resp.Response.StatusCode, "status code") + + respSite := resp.Data.Site + s.Equal(4718, *respSite.Id, "ID") + s.Equal("GO SDK env", *respSite.Name, "Name") + s.Equal("go-sdk", *respSite.Subdomain, "Subdomain") + s.Equal("USD", *respSite.Currency, "Currency") + s.Equal(722159, *respSite.SellerId, "SellerID") + s.EqualValues([]string{}, respSite.NonPrimaryCurrencies, "NonPrimaryCurrencies") + s.True(*respSite.RelationshipInvoicingEnabled, "RelationshipInvoiceEnabled") + s.False(*respSite.CustomerHierarchyEnabled, "CustomerHierarchyEnabled,") + s.False(*respSite.WhopaysEnabled, "WhopaysEnabled") + s.Equal("self-ungrouped", *respSite.WhopaysDefaultPayer, "WhopaysDefaultPayer") + s.Equal(string(models.PaymentCollectionMethod_AUTOMATIC), *respSite.DefaultPaymentCollectionMethod, "DefaultPaymentCollectionMethod") + + allocationSettings := respSite.AllocationSettings + s.Equal(models.CreditType_PRORATED, *allocationSettings.UpgradeCharge.Value(), "UpgradeCharge") + s.Equal(models.CreditType_NONE, *allocationSettings.DowngradeCredit.Value(), "DowngradeCredit") + s.Equal("true", *allocationSettings.AccrueCharge, "AccrueCharge") + + organizationAddress := respSite.OrganizationAddress + s.Equal("Asdf Street", *organizationAddress.Street.Value(), "Street") + s.Equal("123/444", *organizationAddress.Line2.Value(), "Line2") + s.Equal("San Antonio", *organizationAddress.City.Value(), "City") + s.Equal("TX", *organizationAddress.State.Value(), "State") + s.Equal("78015", *organizationAddress.Zip.Value(), "Zip") + s.Equal("US", *organizationAddress.Country.Value(), "Country") + s.Equal("Developer Experience", *organizationAddress.Name.Value(), "AddressName") + s.Equal("555 111 222", *organizationAddress.Phone.Value(), "Phone") + + taxConfiguration := respSite.TaxConfiguration + s.Equal(models.TaxConfigurationKind_CUSTOM, *taxConfiguration.Kind, "Kind") + s.Equal(models.TaxDestinationAddress_SHIPPINGTHENBILLING, *taxConfiguration.DestinationAddress, "TaxDestinationAddress") + s.False(*taxConfiguration.FullyConfigured, "FullyConfigured") + + netTerms := respSite.NetTerms + s.Equal(0, *netTerms.DefaultNetTerms, "DefaultNetTerms") + s.Equal(0, *netTerms.AutomaticNetTerms, "AutomaticNetTerms") + s.Equal(0, *netTerms.RemittanceNetTerms, "RemittanceNetTerms") + s.False(*netTerms.NetTermsOnRemittanceSignupsEnabled, "NetTermsOnRemittanceSignupsEnabled") + s.False(*netTerms.CustomNetTermsEnabled, "CustomNetTermsEnabled") + + s.True(*respSite.Test, "Test") + }, + }, + { + name: "unauthorized", + client: s.unauthorizedClient, + assert: func(t *testing.T, resp models.ApiResponse[models.SiteResponse]) { + s.Equal(http.StatusUnauthorized, resp.Response.StatusCode) + }, + expectedErr: true, + }, + } + + for _, c := range cases { + s.T().Run(c.name, func(t *testing.T) { + resp, err := c.client.SitesController().ReadSite(context.Background()) + if !c.expectedErr { + s.NoErrorf(err, "could not read site") + } + c.assert(t, resp) + }) + } + +} diff --git a/test/subscription_test.go b/test/subscription_test.go new file mode 100644 index 00000000..c589879f --- /dev/null +++ b/test/subscription_test.go @@ -0,0 +1,174 @@ +package test + +import ( + "context" + "net/http" + "testing" + "time" + + advancedbilling "github.com/maxio-com/ab-golang-sdk" + "github.com/maxio-com/ab-golang-sdk/models" +) + +func (s *APISuite) TestSubscriptionCreate() { + ctx := context.Background() + + customer := s.createCustomer(ctx) + productFamily := s.createProductFamily(ctx) + product := s.createProduct(ctx, *productFamily.Id) + coupon := s.createCoupon(ctx, *productFamily.Id) + component := s.createMeteredComponent(ctx, *productFamily.Id) + + cases := []struct { + name string + client advancedbilling.ClientInterface + subscription models.CreateSubscription + assert func(*testing.T, models.ApiResponse[models.SubscriptionResponse], models.CreateSubscription, error) + }{ + { + name: "valid", + client: s.client, + subscription: s.newSubscription( + customer, + product, + *coupon.Code, + []models.CreateSubscriptionComponent{ + { + ComponentId: interfacePtr(*component.Id), + Enabled: boolPtr(true), + UnitBalance: intPtr(1), + }, + }, + ), + assert: func(t *testing.T, resp models.ApiResponse[models.SubscriptionResponse], subscription models.CreateSubscription, err error) { + s.NoError(err) + s.Equal(http.StatusCreated, resp.Response.StatusCode) + + createdSubscription := resp.Data.Subscription + s.Equal(models.SubscriptionState_AWAITINGSIGNUP, *createdSubscription.State) + + s.Equal(subscription.ProductId, createdSubscription.Product.Id) + s.Equal(subscription.PaymentCollectionMethod, createdSubscription.PaymentCollectionMethod) + s.Equal(subscription.CustomerId, createdSubscription.Customer.Id) + s.Equal(subscription.Currency, createdSubscription.Currency) + s.Equal(subscription.CouponCode, createdSubscription.CouponCode.Value()) + s.Equal(subscription.CustomerId, createdSubscription.Customer.Id) + s.Equal(subscription.ProductId, createdSubscription.Product.Id) + + listResp, err := s.client.SubscriptionComponentsController().ListSubscriptionComponents( + ctx, + *createdSubscription.Id, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + ) + + s.NoError(err) + s.Equal(http.StatusOK, listResp.Response.StatusCode) + + prices := *component.Prices.Value() + s.Equal( + *prices[0].StartingQuantity, + *listResp.Data[0].Component.UnitBalance, + ) + + readSubResp, err := s.client.SubscriptionsController().ReadSubscription( + ctx, + *createdSubscription.Id, + []models.SubscriptionInclude{ + models.SubscriptionInclude_COUPONS, + }, + ) + + s.NoError(err) + s.Equal(http.StatusOK, readSubResp.Response.StatusCode) + s.Len(readSubResp.Data.Subscription.CouponCodes, 1) + s.Equal(*coupon.Code, readSubResp.Data.Subscription.CouponCodes[0]) + }, + }, + { + name: "invalid coupon code", + client: s.client, + subscription: s.newSubscription( + customer, + product, + "invalid coupon code", + []models.CreateSubscriptionComponent{}, + ), + assert: func(t *testing.T, ar models.ApiResponse[models.SubscriptionResponse], subscription models.CreateSubscription, err error) { + s.Equal(http.StatusUnprocessableEntity, ar.Response.StatusCode) + }, + }, + { + name: "unauthorized", + client: s.unauthorizedClient, + subscription: s.newSubscription( + customer, + product, + *coupon.Code, + []models.CreateSubscriptionComponent{ + { + ComponentId: interfacePtr(*component.Id), + Enabled: boolPtr(true), + UnitBalance: intPtr(1), + }, + }, + ), + assert: func(t *testing.T, ar models.ApiResponse[models.SubscriptionResponse], cs models.CreateSubscription, err error) { + s.Equal(http.StatusUnauthorized, ar.Response.StatusCode) + }, + }, + } + + for _, c := range cases { + s.T().Run(c.name, func(t *testing.T) { + resp, err := c.client.SubscriptionsController().CreateSubscription( + ctx, + &models.CreateSubscriptionRequest{ + Subscription: c.subscription, + }, + ) + + c.assert(t, resp, c.subscription, err) + }) + } +} + +func (s *APISuite) newSubscription( + customer models.Customer, + product models.Product, + couponCode string, + components []models.CreateSubscriptionComponent, +) models.CreateSubscription { + return models.CreateSubscription{ + ProductId: product.Id, + PaymentCollectionMethod: toPtr[models.PaymentCollectionMethod](models.PaymentCollectionMethod_AUTOMATIC), + CustomerId: customer.Id, + Currency: strPtr("USD"), + InitialBillingAt: strPtr("2029-08-29T12:00:00-04:00"), + CouponCode: &couponCode, + Components: components, + PaymentProfileAttributes: &models.PaymentProfileAttributes{ + FirstName: strPtr("Joe"), + LastName: strPtr("Smith"), + FullNumber: strPtr("4111111111111111"), + CardType: toPtr[models.CardType](models.CardType_VISA), + ExpirationMonth: interfacePtr(1), + ExpirationYear: interfacePtr(time.Now().Year() + 1), + BillingAddress: strPtr("123 Mass Ave."), + BillingCity: strPtr("Boston"), + BillingState: strPtr("MA"), + BillingCountry: strPtr("US"), + BillingZip: strPtr("02120"), + }, + } +}