Skip to content

Commit

Permalink
additions to stacked validations and stacked redemptions (#270)
Browse files Browse the repository at this point in the history
  • Loading branch information
p-zielinski authored Jul 9, 2024
1 parent f50a7f5 commit d532cc4
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 53 deletions.
5 changes: 5 additions & 0 deletions .changeset/witty-files-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@voucherify/sdk': patch
---

Type support for partial redemptions. General update to responses of /validations and /redemptions endpoints.
1 change: 1 addition & 0 deletions packages/sdk/src/types/Categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type Category = {
created_at: string
updated_at?: string
object: 'category'
stacking_rules_type?: 'JOINT' | 'EXCLUSIVE'
}

// 0-level types
Expand Down
9 changes: 8 additions & 1 deletion packages/sdk/src/types/Redemptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { CustomersCreateBody, SimpleCustomer } from './Customers'
import { VouchersResponse } from './Vouchers'
import { GiftRedemptionParams } from './Gift'
import { ValidationSessionParams, ValidationSessionReleaseParams } from './ValidateSession'
import { StackableOptions, StackableRedeemableParams } from './Stackable'
import {
StackableOptions,
StackableRedeemableInapplicableResponse,
StackableRedeemableParams,
StackableRedeemableSkippedResponse,
} from './Stackable'
import { PromotionTierRedeemDetailsSimple, PromotionTierRedeemDetails } from './PromotionTiers'

export interface RedemptionsRedeemBody {
Expand Down Expand Up @@ -199,6 +204,8 @@ export interface RedemptionsRedeemStackableResponse {
related_object_id: string
}
order?: RedemptionsRedeemStackableOrderResponse
skipped_redeemables?: StackableRedeemableSkippedResponse
inapplicable_redeemables?: StackableRedeemableInapplicableResponse
}

export interface RedemptionsRollbackStackableResponse {
Expand Down
35 changes: 35 additions & 0 deletions packages/sdk/src/types/Stackable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { DiscountVouchersTypes, DiscountVouchersEffectTypes, DiscountUnitVoucher
import { SimpleProduct, SimpleSku } from './Products'
import { LoyaltyPointsTransfer } from './Loyalties'
import { ValidationError } from './ValidationError'
import { Category } from './Categories'

type ExpandOption = 'order' | 'redeemable' | 'redemption'

Expand Down Expand Up @@ -64,6 +65,10 @@ export interface StackableRedeemableResultResponse {
gift?: StackableRedeemableResultGift
loyalty_card?: StackableRedeemableResultLoyaltyCard
error?: ValidationError
details?: {
key?: string
message?: string
}
}

export interface StackableRedeemableResponse {
Expand All @@ -75,4 +80,34 @@ export interface StackableRedeemableResponse {
inapplicable_to?: ApplicableToResultList
result?: StackableRedeemableResultResponse
metadata?: Record<string, any>
categories?: Category[]
}

export type StackableRedeemableInapplicableResponse = {
status: 'INAPPLICABLE'
id: string
object: 'voucher' | 'promotion_tier'
result: {
error?: ValidationError
details?: {
key?: string
message?: string
}
}
metadata?: Record<string, unknown>
categories?: Category[]
}

export type StackableRedeemableSkippedResponse = {
status: 'SKIPPED'
id: string
object: 'voucher' | 'promotion_tier'
result: {
details?: {
key?: string
message?: string
}
}
metadata?: Record<string, unknown>
categories?: Category[]
}
23 changes: 22 additions & 1 deletion packages/sdk/src/types/Validations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { DiscountAmount, DiscountPercent, DiscountUnit, DiscountFixed } from './DiscountVoucher'
import { CustomersCreateBody } from './Customers'
import { StackableOptions, StackableRedeemableParams, StackableRedeemableResponse } from './Stackable'
import {
StackableOptions,
StackableRedeemableInapplicableResponse,
StackableRedeemableParams,
StackableRedeemableResponse,
StackableRedeemableSkippedResponse,
} from './Stackable'
import { ValidationSessionParams, ValidationSessionResponse } from './ValidateSession'
import { ApplicableToResultList } from './ApplicableTo'
import { ValidationError } from './ValidationError'
Expand Down Expand Up @@ -84,6 +90,21 @@ export interface ValidationValidateStackableResponse {
session?: ValidationSessionResponse
order?: OrdersCreateResponse
redeemables?: StackableRedeemableResponse[]
skipped_redeemables?: StackableRedeemableSkippedResponse
inapplicable_redeemables?: StackableRedeemableInapplicableResponse
stacking_rules: ValidationsStackingRules
}

export type ValidationsStackingRules = {
redeemables_limit: number
applicable_redeemables_limit: number
applicable_redeemables_per_category_limit?: number
applicable_exclusive_redeemables_limit: number
applicable_exclusive_redeemables_per_category_limit?: number
exclusive_categories: string[]
joint_categories: string[]
redeemables_application_mode: 'ALL' | 'PARTIAL'
redeemables_sorting_rule: 'CATEGORY_HIERARCHY' | 'REQUESTED_ORDER'
}

export type ValidationsValidateCode = PromotionsValidateParams
Expand Down
98 changes: 47 additions & 51 deletions packages/sdk/test/redemptions.spec.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,56 @@
import { voucherifyClient as client } from './client'
import {DiscountVouchersTypesEnum} from "@voucherify/sdk";
import {generateRandomString} from "./utils/generateRandomString";
import { DiscountVouchersTypesEnum } from '@voucherify/sdk'
import { generateRandomString } from './utils/generateRandomString'

jest.setTimeout(15000)

describe('Redemptions API', () => {
it('redemption that failed due validation rule validate error should has .error.message element if defined in validation rule', async () => {
const errorMessage = 'CUSTOMER NOT IN SEGMENT'
it('redemption that failed due validation rule validate error should has .error.message element if defined in validation rule', async () => {
const errorMessage = 'CUSTOMER NOT IN SEGMENT'

const validationRule = await client.validationRules.create({
name: 'Customer must be in segment',
rules: {
1: {
name: 'customer_segment',
rules: {},
property: null,
conditions: {
"$is": [
"seg_" + generateRandomString()
]
}
},
logic: '1'
},
error: {
message: errorMessage,
}
})
const validationRule = await client.validationRules.create({
name: 'Customer must be in segment',
rules: {
1: {
name: 'customer_segment',
rules: {},
property: null,
conditions: {
$is: ['seg_' + generateRandomString()],
},
},
logic: '1',
},
error: {
message: errorMessage,
},
})

const voucher = await client.vouchers.create({
type: 'DISCOUNT_VOUCHER',
discount: {
amount_off: 2000,
type: DiscountVouchersTypesEnum.AMOUNT,
},
redemption: {
quantity: 1,
},
metadata: {},
validation_rules: [
validationRule.id
]
})
const voucher = await client.vouchers.create({
type: 'DISCOUNT_VOUCHER',
discount: {
amount_off: 2000,
type: DiscountVouchersTypesEnum.AMOUNT,
},
redemption: {
quantity: 1,
},
metadata: {},
validation_rules: [validationRule.id],
})

try {
await client.redemptions.redeem(voucher.code, {
customer: {
source_id: 'cust_' + generateRandomString(),
name: 'John Doe',
object: 'customer',
}
})
} catch (error) {
expect(error.message).toBeDefined()
expect(error.error.message).toBeDefined()
expect(error.error.message).toEqual(errorMessage)
}
})
try {
await client.redemptions.redeem(voucher.code, {
customer: {
source_id: 'cust_' + generateRandomString(),
name: 'John Doe',
object: 'customer',
},
})
} catch (error) {
expect(error.message).toBeDefined()
expect(error.error.message).toBeDefined()
expect(error.error.message).toEqual(errorMessage)
}
})
})

0 comments on commit d532cc4

Please sign in to comment.