Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DE-1091] Release 0.5.0 #37

Merged
merged 3 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 0 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ on:
env:
TEST_API_KEY: ${{secrets.TEST_API_KEY}}
TEST_API_PASSWORD: ${{secrets.TEST_API_PASSWORD}}
TEST_DOMAIN: ${{vars.TEST_DOMAIN}}
TEST_SUBDOMAIN: ${{vars.TEST_SUBDOMAIN}}

jobs:
Expand Down
20 changes: 9 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
## Introduction

Maxio Advanced Billing (formerly Chargify) provides an HTTP-based API that conforms to the principles of REST.
One of the many reasons to use Advanced Billing is the immense feature set and surrounding community [client libraries](page:development-tools/client-libraries).
One of the many reasons to use Advanced Billing is the immense feature set and surrounding community [client libraries](http://localhost:8080/go/development-tools/development-tools/client-libraries).
The Maxio API returns JSON responses as the primary and recommended format, but XML is also provided as a backwards compatible option for Merchants who require it.

### Steps to make your first Maxio Advanced Billing API call
Expand Down Expand Up @@ -38,10 +38,10 @@ The following section explains how to use the advancedbilling library in a new p
To use the package in your application, you can install the package from [pkg.go.dev](https://pkg.go.dev/) using the following command:

```bash
$ go get github.com/maxio-com/ab-golang-sdk@v0.4.2
$ go get github.com/maxio-com/ab-golang-sdk@v5.0.0
```

You can also view the package at: https://pkg.go.dev/github.com/maxio-com/ab-golang-sdk@v0.4.2
You can also view the package at: https://pkg.go.dev/github.com/maxio-com/ab-golang-sdk@v5.0.0

## Initialize the API Client

Expand All @@ -51,9 +51,8 @@ The following parameters are configurable for the API Client:

| Parameter | Type | Description |
| --- | --- | --- |
| `subdomain` | `string` | The subdomain for your Advanced Billing site.<br>*Default*: `"subdomain"` |
| `domain` | `string` | The Advanced Billing server domain.<br>*Default*: `"chargify.com"` |
| `environment` | `Environment` | The API environment. <br> **Default: `Environment.PRODUCTION`** |
| `site` | `string` | The subdomain for your Advanced Billing site.<br>*Default*: `"subdomain"` |
| `environment` | `Environment` | The API environment. <br> **Default: `Environment.US`** |
| `httpConfiguration` | [`HttpConfiguration`](doc/http-configuration.md) | Configurable http client options like timeout and retries. |
| `basicAuthCredentials` | [`BasicAuthCredentials`](doc/auth/basic-authentication.md) | The Credentials Setter for Basic Authentication |

Expand All @@ -67,15 +66,14 @@ client := advancedbilling.NewClient(
advancedbilling.WithTimeout(120),
),
),
advancedbilling.WithEnvironment(advancedbilling.PRODUCTION),
advancedbilling.WithEnvironment(advancedbilling.US),
advancedbilling.WithBasicAuthCredentials(
advancedbilling.NewBasicAuthCredentials(
"BasicAuthUserName",
"BasicAuthPassword",
),
),
advancedbilling.WithSubdomain("subdomain"),
advancedbilling.WithDomain("chargify.com"),
advancedbilling.WithSite("subdomain"),
),
)
```
Expand All @@ -88,8 +86,8 @@ The SDK can be configured to use a different environment for making API calls. A

| Name | Description |
| --- | --- |
| production | **Default** Production server |
| environment2 | Production server |
| US | **Default** Default Advanced Billing environment hosted in US. Valid for the majority of our customers. |
| EU | Advanced Billing environment hosted in EU. Use only when you requested EU hosting for your AB account. |

## Authorization

Expand Down
22 changes: 14 additions & 8 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ func NewClient(configuration Configuration) ClientInterface {
configuration: configuration,
}

client.userAgent = utilities.UpdateUserAgent("AB SDK Go:0.4.2 on OS {os-info}")
client.userAgent = utilities.UpdateUserAgent("AB SDK Go:5.0.0 on OS {os-info}")
client.callBuilderFactory = callBuilderHandler(
func(server string) string {
if server == "" {
server = "default"
server = "production"
}
return getBaseUri(Server(server), client.configuration)
},
Expand Down Expand Up @@ -334,14 +334,20 @@ func (c *client) GetCallBuilder() https.CallBuilderFactory {
func getBaseUri(
server Server,
configuration Configuration) string {
if configuration.Environment() == Environment(PRODUCTION) {
if server == Server(ENUMDEFAULT) {
return fmt.Sprintf("https://%v.%v", configuration.Subdomain(), configuration.Domain())
if configuration.Environment() == Environment(US) {
if server == Server(PRODUCTION) {
return fmt.Sprintf("https://%v.chargify.com", configuration.Site())
}
if server == Server(EBB) {
return fmt.Sprintf("https://events.chargify.com/%v", configuration.Site())
}
}
if configuration.Environment() == Environment(ENVIRONMENT2) {
if server == Server(ENUMDEFAULT) {
return "https://events.chargify.com"
if configuration.Environment() == Environment(EU) {
if server == Server(PRODUCTION) {
return fmt.Sprintf("https://%v.ebilling.maxio.com", configuration.Site())
}
if server == Server(EBB) {
return fmt.Sprintf("https://events.chargify.com/%v", configuration.Site())
}
}
return "TODO: Select a valid server."
Expand Down
18 changes: 14 additions & 4 deletions component_price_points_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ func (c *ComponentPricePointsController) CreateComponentPricePoint(
fmt.Sprintf("/components/%v/price_points.json", componentId),
)
req.Authenticate(NewAuth("BasicAuth"))
req.AppendErrors(map[string]https.ErrorBuilder[error]{
"422": {TemplatedMessage: "HTTP Response Not OK. Status code: {$statusCode}. Response: '{$response.body}'.", Unmarshaller: errors.NewErrorArrayMapResponse},
})
req.Header("Content-Type", "application/json")
if body != nil {
req.Json(body)
Expand Down Expand Up @@ -159,6 +162,9 @@ func (c *ComponentPricePointsController) BulkCreateComponentPricePoints(
fmt.Sprintf("/components/%v/price_points/bulk.json", componentId),
)
req.Authenticate(NewAuth("BasicAuth"))
req.AppendErrors(map[string]https.ErrorBuilder[error]{
"422": {TemplatedMessage: "HTTP Response Not OK. Status code: {$statusCode}. Response: '{$response.body}'.", Unmarshaller: errors.NewErrorListResponse},
})
req.Header("Content-Type", "application/json")
if body != nil {
req.Json(body)
Expand Down Expand Up @@ -212,14 +218,15 @@ func (c *ComponentPricePointsController) UpdateComponentPricePoint(
return models.NewApiResponse(result, resp), err
}

// ReadComponentPricePoint takes context, componentId, pricePointId as parameters and
// ReadComponentPricePoint takes context, componentId, pricePointId, currencyPrices as parameters and
// returns an models.ApiResponse with models.ComponentPricePointResponse data and
// an error if there was an issue with the request or response.
// Use this endpoint to retrieve details for a specific component price point. You can achieve this by using either the component price point ID or handle.
func (c *ComponentPricePointsController) ReadComponentPricePoint(
ctx context.Context,
componentId models.ReadComponentPricePointComponentId,
pricePointId models.ReadComponentPricePointPricePointId) (
pricePointId models.ReadComponentPricePointPricePointId,
currencyPrices *bool) (
models.ApiResponse[models.ComponentPricePointResponse],
error) {
req := c.prepareRequest(
Expand All @@ -228,6 +235,9 @@ func (c *ComponentPricePointsController) ReadComponentPricePoint(
fmt.Sprintf("/components/%v/price_points/%v.json", componentId, pricePointId),
)
req.Authenticate(NewAuth("BasicAuth"))
if currencyPrices != nil {
req.QueryParam("currency_prices", *currencyPrices)
}

var result models.ComponentPricePointResponse
decoder, resp, err := req.CallAsJson()
Expand Down Expand Up @@ -315,7 +325,7 @@ func (c *ComponentPricePointsController) CreateCurrencyPrices(
)
req.Authenticate(NewAuth("BasicAuth"))
req.AppendErrors(map[string]https.ErrorBuilder[error]{
"422": {Message: "Unprocessable Entity (WebDAV)", Unmarshaller: errors.NewErrorArrayMapResponse},
"422": {TemplatedMessage: "HTTP Response Not OK. Status code: {$statusCode}. Response: '{$response.body}'.", Unmarshaller: errors.NewErrorArrayMapResponse},
})
req.Header("Content-Type", "application/json")
if body != nil {
Expand Down Expand Up @@ -350,7 +360,7 @@ func (c *ComponentPricePointsController) UpdateCurrencyPrices(
)
req.Authenticate(NewAuth("BasicAuth"))
req.AppendErrors(map[string]https.ErrorBuilder[error]{
"422": {Message: "Unprocessable Entity (WebDAV)", Unmarshaller: errors.NewErrorArrayMapResponse},
"422": {TemplatedMessage: "HTTP Response Not OK. Status code: {$statusCode}. Response: '{$response.body}'.", Unmarshaller: errors.NewErrorArrayMapResponse},
})
req.Header("Content-Type", "application/json")
if body != nil {
Expand Down
44 changes: 14 additions & 30 deletions configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ type ConfigurationOptions func(*Configuration)
// Configuration holds configuration settings.
type Configuration struct {
environment Environment
subdomain string
domain string
site string
httpConfiguration HttpConfiguration
basicAuthCredentials BasicAuthCredentials
}
Expand Down Expand Up @@ -46,17 +45,10 @@ func WithEnvironment(environment Environment) ConfigurationOptions {
}
}

// WithSubdomain is an option that sets the Subdomain in the Configuration.
func WithSubdomain(subdomain string) ConfigurationOptions {
// WithSite is an option that sets the Site in the Configuration.
func WithSite(site string) ConfigurationOptions {
return func(c *Configuration) {
c.subdomain = subdomain
}
}

// WithDomain is an option that sets the Domain in the Configuration.
func WithDomain(domain string) ConfigurationOptions {
return func(c *Configuration) {
c.domain = domain
c.site = site
}
}

Expand All @@ -79,14 +71,9 @@ func (c Configuration) Environment() Environment {
return c.environment
}

// Subdomain returns the subdomain from the Configuration.
func (c Configuration) Subdomain() string {
return c.subdomain
}

// Domain returns the domain from the Configuration.
func (c Configuration) Domain() string {
return c.domain
// Site returns the site from the Configuration.
func (c Configuration) Site() string {
return c.site
}

// HttpConfiguration returns the httpConfiguration from the Configuration.
Expand All @@ -108,13 +95,9 @@ func CreateConfigurationFromEnvironment(options ...ConfigurationOptions) Configu
if environment != "" {
config.environment = Environment(environment)
}
subdomain := os.Getenv("ADVANCEDBILLING_SUBDOMAIN")
if subdomain != "" {
config.subdomain = subdomain
}
domain := os.Getenv("ADVANCEDBILLING_DOMAIN")
if domain != "" {
config.domain = domain
site := os.Getenv("ADVANCEDBILLING_SITE")
if site != "" {
config.site = site
}
basicAuthUserName := os.Getenv("ADVANCEDBILLING_BASIC_AUTH_USER_NAME")
if basicAuthUserName != "" {
Expand All @@ -134,15 +117,16 @@ func CreateConfigurationFromEnvironment(options ...ConfigurationOptions) Configu
type Server string

const (
ENUMDEFAULT Server = "default"
PRODUCTION Server = "production"
EBB Server = "ebb"
)

// Environment represents available environments.
type Environment string

const (
PRODUCTION Environment = "production"
ENVIRONMENT2 Environment = "environment2"
US Environment = "US"
EU Environment = "EU"
)

// CreateRetryConfiguration creates a new RetryConfiguration with the provided options.
Expand Down
32 changes: 23 additions & 9 deletions coupons_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ func NewCouponsController(baseController baseController) *CouponsController {
// Additionally, for documentation on how to apply a coupon to a subscription within the Advanced Billing UI, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupons-and-Subscriptions).
// ## Create Coupon
// This request will create a coupon, based on the provided information.
// When creating a coupon, you must specify a product family using the `product_family_id`. If no `product_family_id` is passed, the first product family available is used. You will also need to formulate your URL to cite the Product Family ID in your request.
// You can restrict a coupon to only apply to specific products / components by optionally passing in hashes of `restricted_products` and/or `restricted_components` in the format:
// `{ "<product/component_id>": boolean_value }`
// You can create either a flat amount coupon, by specyfing `amount_in_cents`, or percentage coupon by specyfing `percentage`.
// You can restrict a coupon to only apply to specific products / components by optionally passing in `restricted_products` and/or `restricted_components` objects in the format:
// `{ "<product_id/component_id>": boolean_value }`
func (c *CouponsController) CreateCoupon(
ctx context.Context,
productFamilyId int,
body *models.CreateOrUpdateCoupon) (
body *models.CouponRequest) (
models.ApiResponse[models.CouponResponse],
error) {
req := c.prepareRequest(
Expand Down Expand Up @@ -123,15 +123,16 @@ func (c *CouponsController) ListCouponsForProductFamily(
return models.NewApiResponse(result, resp), err
}

// FindCoupon takes context, productFamilyId, code as parameters and
// FindCoupon takes context, productFamilyId, code, currencyPrices as parameters and
// returns an models.ApiResponse with models.CouponResponse data and
// an error if there was an issue with the request or response.
// You can search for a coupon via the API with the find method. By passing a code parameter, the find will attempt to locate a coupon that matches that code. If no coupon is found, a 404 is returned.
// If you have more than one product family and if the coupon you are trying to find does not belong to the default product family in your site, then you will need to specify (either in the url or as a query string param) the product family id.
func (c *CouponsController) FindCoupon(
ctx context.Context,
productFamilyId *int,
code *string) (
code *string,
currencyPrices *bool) (
models.ApiResponse[models.CouponResponse],
error) {
req := c.prepareRequest(ctx, "GET", "/coupons/find.json")
Expand All @@ -142,6 +143,9 @@ func (c *CouponsController) FindCoupon(
if code != nil {
req.QueryParam("code", *code)
}
if currencyPrices != nil {
req.QueryParam("currency_prices", *currencyPrices)
}
var result models.CouponResponse
decoder, resp, err := req.CallAsJson()
if err != nil {
Expand All @@ -152,7 +156,7 @@ func (c *CouponsController) FindCoupon(
return models.NewApiResponse(result, resp), err
}

// ReadCoupon takes context, productFamilyId, couponId as parameters and
// ReadCoupon takes context, productFamilyId, couponId, currencyPrices as parameters and
// returns an models.ApiResponse with models.CouponResponse data and
// an error if there was an issue with the request or response.
// You can retrieve the Coupon via the API with the Show method. You must identify the Coupon in this call by the ID parameter that Advanced Billing assigns.
Expand All @@ -162,7 +166,8 @@ func (c *CouponsController) FindCoupon(
func (c *CouponsController) ReadCoupon(
ctx context.Context,
productFamilyId int,
couponId int) (
couponId int,
currencyPrices *bool) (
models.ApiResponse[models.CouponResponse],
error) {
req := c.prepareRequest(
Expand All @@ -171,6 +176,9 @@ func (c *CouponsController) ReadCoupon(
fmt.Sprintf("/product_families/%v/coupons/%v.json", productFamilyId, couponId),
)
req.Authenticate(NewAuth("BasicAuth"))
if currencyPrices != nil {
req.QueryParam("currency_prices", *currencyPrices)
}

var result models.CouponResponse
decoder, resp, err := req.CallAsJson()
Expand All @@ -193,7 +201,7 @@ func (c *CouponsController) UpdateCoupon(
ctx context.Context,
productFamilyId int,
couponId int,
body *models.CreateOrUpdateCoupon) (
body *models.CouponRequest) (
models.ApiResponse[models.CouponResponse],
error) {
req := c.prepareRequest(
Expand All @@ -202,6 +210,9 @@ func (c *CouponsController) UpdateCoupon(
fmt.Sprintf("/product_families/%v/coupons/%v.json", productFamilyId, couponId),
)
req.Authenticate(NewAuth("BasicAuth"))
req.AppendErrors(map[string]https.ErrorBuilder[error]{
"422": {TemplatedMessage: "HTTP Response Not OK. Status code: {$statusCode}. Response: '{$response.body}'.", Unmarshaller: errors.NewErrorListResponse},
})
req.Header("Content-Type", "application/json")
if body != nil {
req.Json(body)
Expand Down Expand Up @@ -380,6 +391,9 @@ func (c *CouponsController) CreateOrUpdateCouponCurrencyPrices(
fmt.Sprintf("/coupons/%v/currency_prices.json", couponId),
)
req.Authenticate(NewAuth("BasicAuth"))
req.AppendErrors(map[string]https.ErrorBuilder[error]{
"422": {TemplatedMessage: "HTTP Response Not OK. Status code: {$statusCode}. Response: '{$response.body}'.", Unmarshaller: errors.NewErrorStringMapResponse},
})
req.Header("Content-Type", "application/json")
if body != nil {
req.Json(body)
Expand Down
5 changes: 2 additions & 3 deletions default_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ func DefaultHttpConfiguration() HttpConfiguration {
// DefaultConfiguration returns the default Configuration.
func DefaultConfiguration() Configuration {
return newConfiguration(
WithEnvironment(PRODUCTION),
WithSubdomain("subdomain"),
WithDomain("chargify.com"),
WithEnvironment(US),
WithSite("subdomain"),
WithHttpConfiguration(DefaultHttpConfiguration()),
)
}
Loading
Loading