Skip to content

Commit

Permalink
[DE-1044] Coupon fixes (#164)
Browse files Browse the repository at this point in the history
- renamed `CreateOrUpdateCoupon` to `CouponRequest`
- renamed `CreateOrUpdatePercentageCouponPercentage` to `CouponPayloadPercentage`
- changed `CreateOrUpdateCouponCoupon` to `CouponPayload`
-  There're no longer 2 distinct models for Flat amount and Percentage coupon. They're merged into `CouponPayload`. Using it, specify either `amount_in_cents` or `percentage` property
- `code`, `name`, `description`, `amount_in_cents` and `percentage` are not required properties in `CouponPayload` model. It means they're not send as nulls if unset. It enables patching coupon with `updateCoupon` without specifying these properties values. Previous version enforced setting them.
- `CouponPayload` `endDate` changes type from `ZonedDateTime` to `LocalDate`. Response `Coupon` `endDate` is still `ZonedDateTime` (its calculated as end of the day)
- `updateCoupon` now throws `ErrorListResponseException`
- added `currencyPrices` for `Coupon` response. Note you need to specify suitable query parameters to access it
- added `currencyPrices` query parameter for `readCoupon` and `findCoupon`
- added some missing descriptions
  • Loading branch information
maciej-nedza authored Nov 15, 2024
1 parent 42b966b commit 0a98bfc
Show file tree
Hide file tree
Showing 20 changed files with 399 additions and 1,034 deletions.
77 changes: 42 additions & 35 deletions doc/controllers/coupons.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,23 @@ Additionally, for documentation on how to apply a coupon to a subscription withi

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 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 hashes of `restricted_products` and/or `restricted_components` in the format:
`{ "<product/component_id>": boolean_value }`
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 }`

```java
CouponResponse createCoupon(
final int productFamilyId,
final CreateOrUpdateCoupon body)
final CouponRequest body)
```

## Parameters

| Parameter | Type | Tags | Description |
| --- | --- | --- | --- |
| `productFamilyId` | `int` | Template, Required | The Advanced Billing id of the product family to which the coupon belongs |
| `body` | [`CreateOrUpdateCoupon`](../../doc/models/create-or-update-coupon.md) | Body, Optional | - |
| `body` | [`CouponRequest`](../../doc/models/coupon-request.md) | Body, Optional | - |

## Response Type

Expand All @@ -64,26 +64,23 @@ CouponResponse createCoupon(

```java
int productFamilyId = 140;
CreateOrUpdateCoupon body = new CreateOrUpdateCoupon.Builder()
.coupon(CreateOrUpdateCouponCoupon.fromCreateOrUpdatePercentageCoupon(
new CreateOrUpdatePercentageCoupon.Builder(
"15% off",
"15OFF",
CreateOrUpdatePercentageCouponPercentage.fromPrecision(
15D
)
)
CouponRequest body = new CouponRequest.Builder()
.coupon(new CouponPayload.Builder()
.name("15% off")
.code("15OFF")
.description("15% off for life")
.percentage(CouponPayloadPercentage.fromPrecision(
15D
))
.allowNegativeBalance(false)
.recurring(false)
.endDate(DateTimeHelper.fromRfc8601DateTime("2012-08-29T12:00:00-04:00"))
.endDate(DateTimeHelper.fromSimpleDate("2012-08-29"))
.productFamilyId("2")
.stackable(true)
.compoundingStrategy(CompoundingStrategy.COMPOUND)
.excludeMidPeriodAllocations(true)
.applyOnCancelAtEndOfPeriod(true)
.build()
))
.build())
.restrictedProducts(new LinkedHashMap<String, Boolean>() {{
put("1", true);
}})
Expand Down Expand Up @@ -272,7 +269,8 @@ If you have more than one product family and if the coupon you are trying to fin
```java
CouponResponse findCoupon(
final Integer productFamilyId,
final String code)
final String code,
final Boolean currencyPrices)
```

## Parameters
Expand All @@ -281,6 +279,7 @@ CouponResponse findCoupon(
| --- | --- | --- | --- |
| `productFamilyId` | `Integer` | Query, Optional | The Advanced Billing id of the product family to which the coupon belongs |
| `code` | `String` | Query, Optional | The code of the coupon |
| `currencyPrices` | `Boolean` | Query, Optional | When fetching coupons, if you have defined multiple currencies at the site level, you can optionally pass the `?currency_prices=true` query param to include an array of currency price data in the response. |

## Response Type

Expand All @@ -289,8 +288,10 @@ CouponResponse findCoupon(
## Example Usage

```java
Boolean currencyPrices = true;

try {
CouponResponse result = couponsController.findCoupon(null, null);
CouponResponse result = couponsController.findCoupon(null, null, currencyPrices);
System.out.println(result);
} catch (ApiException e) {
e.printStackTrace();
Expand All @@ -312,7 +313,8 @@ If the coupon is set to `use_site_exchange_rate: true`, it will return pricing b
```java
CouponResponse readCoupon(
final int productFamilyId,
final int couponId)
final int couponId,
final Boolean currencyPrices)
```

## Parameters
Expand All @@ -321,6 +323,7 @@ CouponResponse readCoupon(
| --- | --- | --- | --- |
| `productFamilyId` | `int` | Template, Required | The Advanced Billing id of the product family to which the coupon belongs |
| `couponId` | `int` | Template, Required | The Advanced Billing id of the coupon |
| `currencyPrices` | `Boolean` | Query, Optional | When fetching coupons, if you have defined multiple currencies at the site level, you can optionally pass the `?currency_prices=true` query param to include an array of currency price data in the response. |

## Response Type

Expand All @@ -331,9 +334,10 @@ CouponResponse readCoupon(
```java
int productFamilyId = 140;
int couponId = 162;
Boolean currencyPrices = true;

try {
CouponResponse result = couponsController.readCoupon(productFamilyId, couponId);
CouponResponse result = couponsController.readCoupon(productFamilyId, couponId, currencyPrices);
System.out.println(result);
} catch (ApiException e) {
e.printStackTrace();
Expand Down Expand Up @@ -385,7 +389,7 @@ You can restrict a coupon to only apply to specific products / components by opt
CouponResponse updateCoupon(
final int productFamilyId,
final int couponId,
final CreateOrUpdateCoupon body)
final CouponRequest body)
```

## Parameters
Expand All @@ -394,7 +398,7 @@ CouponResponse updateCoupon(
| --- | --- | --- | --- |
| `productFamilyId` | `int` | Template, Required | The Advanced Billing id of the product family to which the coupon belongs |
| `couponId` | `int` | Template, Required | The Advanced Billing id of the coupon |
| `body` | [`CreateOrUpdateCoupon`](../../doc/models/create-or-update-coupon.md) | Body, Optional | - |
| `body` | [`CouponRequest`](../../doc/models/coupon-request.md) | Body, Optional | - |

## Response Type

Expand All @@ -405,24 +409,21 @@ CouponResponse updateCoupon(
```java
int productFamilyId = 140;
int couponId = 162;
CreateOrUpdateCoupon body = new CreateOrUpdateCoupon.Builder()
.coupon(CreateOrUpdateCouponCoupon.fromCreateOrUpdatePercentageCoupon(
new CreateOrUpdatePercentageCoupon.Builder(
"15% off",
"15OFF",
CreateOrUpdatePercentageCouponPercentage.fromPrecision(
15D
)
)
CouponRequest body = new CouponRequest.Builder()
.coupon(new CouponPayload.Builder()
.name("15% off")
.code("15OFF")
.description("15% off for life")
.percentage(CouponPayloadPercentage.fromPrecision(
15D
))
.allowNegativeBalance(false)
.recurring(false)
.endDate(DateTimeHelper.fromRfc8601DateTime("2012-08-29T12:00:00-04:00"))
.endDate(DateTimeHelper.fromSimpleDate("2012-08-29"))
.productFamilyId("2")
.stackable(true)
.compoundingStrategy(CompoundingStrategy.COMPOUND)
.build()
))
.build())
.restrictedProducts(new LinkedHashMap<String, Boolean>() {{
put("1", true);
}})
Expand Down Expand Up @@ -471,6 +472,12 @@ try {
}
```

## Errors

| HTTP Status Code | Error Description | Exception Class |
| --- | --- | --- |
| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) |


# Archive Coupon

Expand Down
2 changes: 2 additions & 0 deletions doc/models/compounding-strategy.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

# Compounding Strategy

Applicable only to stackable coupons. For `compound`, Percentage-based discounts will be calculated against the remaining price, after prior discounts have been calculated. For `full-price`, Percentage-based discounts will always be calculated against the original item price, before other discounts are applied.

## Enumeration

`CompoundingStrategy`
Expand Down
14 changes: 14 additions & 0 deletions doc/models/containers/coupon-payload-percentage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

# Coupon Payload Percentage

## Class Name

`CouponPayloadPercentage`

## Cases

| Type | Factory Method |
| --- | --- |
| `String` | CouponPayloadPercentage.fromString(String string) |
| `double` | CouponPayloadPercentage.fromPrecision(double precision) |

14 changes: 0 additions & 14 deletions doc/models/containers/create-or-update-coupon-coupon.md

This file was deleted.

This file was deleted.

38 changes: 38 additions & 0 deletions doc/models/coupon-payload.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

# Coupon Payload

## Structure

`CouponPayload`

## Fields

| Name | Type | Tags | Description | Getter | Setter |
| --- | --- | --- | --- | --- | --- |
| `Name` | `String` | Optional | Required when creating a new coupon. This name is not displayed to customers and is limited to 255 characters. | String getName() | setName(String name) |
| `Code` | `String` | Optional | Required when creating a new coupon. The code is limited to 255 characters. May contain uppercase alphanumeric characters and these special characters (which allow for email addresses to be used): “%”, “@”, “+”, “-”, “_”, and “.” | String getCode() | setCode(String code) |
| `Description` | `String` | Optional | Required when creating a new coupon. A description of the coupon that can be displayed to customers in transactions and on statements. The description is limited to 255 characters. | String getDescription() | setDescription(String description) |
| `Percentage` | [`CouponPayloadPercentage`](../../doc/models/containers/coupon-payload-percentage.md) | Optional | This is a container for one-of cases. | CouponPayloadPercentage getPercentage() | setPercentage(CouponPayloadPercentage percentage) |
| `AmountInCents` | `Long` | Optional | Required when creating a new flat amount coupon. Can't be used together with percentage. Flat USD discount | Long getAmountInCents() | setAmountInCents(Long amountInCents) |
| `AllowNegativeBalance` | `Boolean` | Optional | If set to true, discount is not limited (credits will carry forward to next billing). Can't be used together with restrictions. | Boolean getAllowNegativeBalance() | setAllowNegativeBalance(Boolean allowNegativeBalance) |
| `Recurring` | `Boolean` | Optional | - | Boolean getRecurring() | setRecurring(Boolean recurring) |
| `EndDate` | `LocalDate` | Optional | After the end of the given day, this coupon code will be invalid for new signups. Recurring discounts started before this date will continue to recur even after this date. | LocalDate getEndDate() | setEndDate(LocalDate endDate) |
| `ProductFamilyId` | `String` | Optional | - | String getProductFamilyId() | setProductFamilyId(String productFamilyId) |
| `Stackable` | `Boolean` | Optional | A stackable coupon can be combined with other coupons on a Subscription. | Boolean getStackable() | setStackable(Boolean stackable) |
| `CompoundingStrategy` | [`CompoundingStrategy`](../../doc/models/compounding-strategy.md) | Optional | Applicable only to stackable coupons. For `compound`, Percentage-based discounts will be calculated against the remaining price, after prior discounts have been calculated. For `full-price`, Percentage-based discounts will always be calculated against the original item price, before other discounts are applied. | CompoundingStrategy getCompoundingStrategy() | setCompoundingStrategy(CompoundingStrategy compoundingStrategy) |
| `ExcludeMidPeriodAllocations` | `Boolean` | Optional | - | Boolean getExcludeMidPeriodAllocations() | setExcludeMidPeriodAllocations(Boolean excludeMidPeriodAllocations) |
| `ApplyOnCancelAtEndOfPeriod` | `Boolean` | Optional | - | Boolean getApplyOnCancelAtEndOfPeriod() | setApplyOnCancelAtEndOfPeriod(Boolean applyOnCancelAtEndOfPeriod) |
| `ApplyOnSubscriptionExpiration` | `Boolean` | Optional | - | Boolean getApplyOnSubscriptionExpiration() | setApplyOnSubscriptionExpiration(Boolean applyOnSubscriptionExpiration) |

## Example (as JSON)

```json
{
"name": "name8",
"code": "code6",
"description": "description8",
"percentage": "String7",
"amount_in_cents": 110
}
```

Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@

# Create or Update Coupon
# Coupon Request

## Structure

`CreateOrUpdateCoupon`
`CouponRequest`

## Fields

| Name | Type | Tags | Description | Getter | Setter |
| --- | --- | --- | --- | --- | --- |
| `Coupon` | [`CreateOrUpdateCouponCoupon`](../../doc/models/containers/create-or-update-coupon-coupon.md) | Optional | This is a container for one-of cases. | CreateOrUpdateCouponCoupon getCoupon() | setCoupon(CreateOrUpdateCouponCoupon coupon) |
| `Coupon` | [`CouponPayload`](../../doc/models/coupon-payload.md) | Optional | - | CouponPayload getCoupon() | setCoupon(CouponPayload coupon) |
| `RestrictedProducts` | `Map<String, Boolean>` | Optional | An object where the keys are product_ids and the values are booleans indicating if the coupon should be applicable to the product | Map<String, Boolean> getRestrictedProducts() | setRestrictedProducts(Map<String, Boolean> restrictedProducts) |
| `RestrictedComponents` | `Map<String, Boolean>` | Optional | An object where the keys are component_ids and the values are booleans indicating if the coupon should be applicable to the component | Map<String, Boolean> getRestrictedComponents() | setRestrictedComponents(Map<String, Boolean> restrictedComponents) |

Expand All @@ -18,14 +18,11 @@
```json
{
"coupon": {
"name": "name0",
"code": "code8",
"description": "description0",
"percentage": "String9",
"allow_negative_balance": false,
"recurring": false,
"end_date": "2016-03-13T12:52:32.123Z",
"product_family_id": "product_family_id6"
"name": "name4",
"code": "code2",
"description": "description6",
"percentage": "String3",
"amount_in_cents": 230
},
"restricted_products": {
"key0": true
Expand Down
9 changes: 5 additions & 4 deletions doc/models/coupon.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@
| `ProductFamilyId` | `Integer` | Optional | - | Integer getProductFamilyId() | setProductFamilyId(Integer productFamilyId) |
| `ProductFamilyName` | `String` | Optional | - | String getProductFamilyName() | setProductFamilyName(String productFamilyName) |
| `StartDate` | `ZonedDateTime` | Optional | - | ZonedDateTime getStartDate() | setStartDate(ZonedDateTime startDate) |
| `EndDate` | `ZonedDateTime` | Optional | - | ZonedDateTime getEndDate() | setEndDate(ZonedDateTime endDate) |
| `EndDate` | `ZonedDateTime` | Optional | After the given time, this coupon code will be invalid for new signups. Recurring discounts started before this date will continue to recur even after this date. | ZonedDateTime getEndDate() | setEndDate(ZonedDateTime endDate) |
| `Percentage` | `String` | Optional | - | String getPercentage() | setPercentage(String percentage) |
| `Recurring` | `Boolean` | Optional | - | Boolean getRecurring() | setRecurring(Boolean recurring) |
| `RecurringScheme` | [`RecurringScheme`](../../doc/models/recurring-scheme.md) | Optional | - | RecurringScheme getRecurringScheme() | setRecurringScheme(RecurringScheme recurringScheme) |
| `DurationPeriodCount` | `Integer` | Optional | - | Integer getDurationPeriodCount() | setDurationPeriodCount(Integer durationPeriodCount) |
| `DurationInterval` | `Integer` | Optional | - | Integer getDurationInterval() | setDurationInterval(Integer durationInterval) |
| `DurationIntervalUnit` | `String` | Optional | - | String getDurationIntervalUnit() | setDurationIntervalUnit(String durationIntervalUnit) |
| `DurationIntervalSpan` | `String` | Optional | - | String getDurationIntervalSpan() | setDurationIntervalSpan(String durationIntervalSpan) |
| `AllowNegativeBalance` | `Boolean` | Optional | - | Boolean getAllowNegativeBalance() | setAllowNegativeBalance(Boolean allowNegativeBalance) |
| `AllowNegativeBalance` | `Boolean` | Optional | If set to true, discount is not limited (credits will carry forward to next billing). | Boolean getAllowNegativeBalance() | setAllowNegativeBalance(Boolean allowNegativeBalance) |
| `ArchivedAt` | `ZonedDateTime` | Optional | - | ZonedDateTime getArchivedAt() | setArchivedAt(ZonedDateTime archivedAt) |
| `ConversionLimit` | `String` | Optional | - | String getConversionLimit() | setConversionLimit(String conversionLimit) |
| `Stackable` | `Boolean` | Optional | - | Boolean getStackable() | setStackable(Boolean stackable) |
| `CompoundingStrategy` | [`CompoundingStrategy`](../../doc/models/compounding-strategy.md) | Optional | - | CompoundingStrategy getCompoundingStrategy() | setCompoundingStrategy(CompoundingStrategy compoundingStrategy) |
| `Stackable` | `Boolean` | Optional | A stackable coupon can be combined with other coupons on a Subscription. | Boolean getStackable() | setStackable(Boolean stackable) |
| `CompoundingStrategy` | [`CompoundingStrategy`](../../doc/models/compounding-strategy.md) | Optional | Applicable only to stackable coupons. For `compound`, Percentage-based discounts will be calculated against the remaining price, after prior discounts have been calculated. For `full-price`, Percentage-based discounts will always be calculated against the original item price, before other discounts are applied. | CompoundingStrategy getCompoundingStrategy() | setCompoundingStrategy(CompoundingStrategy compoundingStrategy) |
| `UseSiteExchangeRate` | `Boolean` | Optional | - | Boolean getUseSiteExchangeRate() | setUseSiteExchangeRate(Boolean useSiteExchangeRate) |
| `CreatedAt` | `ZonedDateTime` | Optional | - | ZonedDateTime getCreatedAt() | setCreatedAt(ZonedDateTime createdAt) |
| `UpdatedAt` | `ZonedDateTime` | Optional | - | ZonedDateTime getUpdatedAt() | setUpdatedAt(ZonedDateTime updatedAt) |
Expand All @@ -39,6 +39,7 @@
| `ApplyOnCancelAtEndOfPeriod` | `Boolean` | Optional | - | Boolean getApplyOnCancelAtEndOfPeriod() | setApplyOnCancelAtEndOfPeriod(Boolean applyOnCancelAtEndOfPeriod) |
| `ApplyOnSubscriptionExpiration` | `Boolean` | Optional | - | Boolean getApplyOnSubscriptionExpiration() | setApplyOnSubscriptionExpiration(Boolean applyOnSubscriptionExpiration) |
| `CouponRestrictions` | [`List<CouponRestriction>`](../../doc/models/coupon-restriction.md) | Optional | - | List<CouponRestriction> getCouponRestrictions() | setCouponRestrictions(List<CouponRestriction> couponRestrictions) |
| `CurrencyPrices` | [`List<CouponCurrency>`](../../doc/models/coupon-currency.md) | Optional | Returned in read, find, and list endpoints if the query parameter is provided. | List<CouponCurrency> getCurrencyPrices() | setCurrencyPrices(List<CouponCurrency> currencyPrices) |

## Example (as JSON)

Expand Down
Loading

0 comments on commit 0a98bfc

Please sign in to comment.