Skip to content

Commit 6655c04

Browse files
authored
feat: add payment method and refund functions (#235)
- Add "add_payment_method", "refund_by_amount" and "refund_by_payment_log" functions to beta Referral class - Add unit tests for new methods - Add authentication helper function to use referral customer's API key for API calls in unit tests - Change "Referral User" to "Referral Customer" app-wide, including environmental variables - Rename old "referral_user" cassettes to "referral_customer" - Add missing entries to map "bank_"/"card_" prefixes and "BankAccount"/"CreditCard" object types to PaymentMethod class when deserializing JSON - Add (disabled) unit tests for PaymentMethod deserialization
1 parent 478c5cd commit 6655c04

25 files changed

+428
-60
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# CHANGELOG
22

3+
## [Unreleased]
4+
5+
- Added new beta billing functionality for referral customer users, accessible via `EasyPost::Beta::Referral`.
6+
- `add_payment_method` to add an existing Stripe bank account or credit card to your EasyPost account.
7+
- `refund_by_amount` refunds you wallet balance by a specified amount.
8+
- `refund_by_payment_log` refunds you wallet balance by a specified payment log.
9+
- Fix bug where bank account and credit card payment methods were not deserializing to the `EasyPost::PaymentMethod` class.
10+
311
## v4.9.0 (2022-12-07)
412

513
- Routes requests for creating a carrier account with a custom workflow (eg: FedEx, UPS) to the correct endpoint when using the `create` function

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,5 +159,5 @@ The following are required on every test run:
159159
Some tests may require an EasyPost user with a particular set of enabled features such as a `Partner` user when creating referrals. We have attempted to call out these functions in their respective docstrings. The following are required when you need to re-record cassettes for applicable tests:
160160

161161
- `USPS_CARRIER_ACCOUNT_ID` (eg: one-call buying a shipment for non-EasyPost employees)
162-
- `PARTNER_USER_PROD_API_KEY` (eg: creating a referral user)
163-
- `REFERRAL_USER_PROD_API_KEY` (eg: adding a credit card to a referral user)
162+
- `PARTNER_USER_PROD_API_KEY` (eg: creating a referral customer)
163+
- `REFERRAL_CUSTOMER_PROD_API_KEY` (eg: adding a credit card to a referral customer)

docs/EasyPost/Beta/Referral.html

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/EasyPost/Referral.html

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/js/search_index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/easypost/beta/payment_refund.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# frozen_string_literal: true
2+
3+
# PaymentRefund objects represent a refund of a payment.
4+
class EasyPost::Beta::PaymentRefund < EasyPost::Resource
5+
end

lib/easypost/beta/referral.rb

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,15 @@ def create_easypost_credit_card(referral_api_key, stripe_object_id, priority = '
5555
end
5656
end
5757

58-
# Create a referral user. This function requires the Partner User's API key.
58+
# Create a referral customer. This function requires the Partner User's API key.
5959
# <b>DEPRECATED:</b> Please use <tt>Referral</tt> in the main namespace instead.
6060
def self.create(params = {}, api_key = nil)
6161
warn '[DEPRECATION] Please use `Referral.create` in the main namespace instead.'
6262
response = EasyPost.make_request(:post, '/beta/referral_customers', api_key, { user: params })
6363
EasyPost::Util.convert_to_easypost_object(response, api_key)
6464
end
6565

66-
# Update a referral user. This function requires the Partner User's API key.
66+
# Update a referral customer. This function requires the Partner User's API key.
6767
# <b>DEPRECATED:</b> Please use <tt>Referral</tt> in the main namespace instead.
6868
def self.update_email(email, user_id, api_key = nil)
6969
warn '[DEPRECATION] Please use `Referral.update_email` in the main namespace instead.'
@@ -78,15 +78,15 @@ def self.update_email(email, user_id, api_key = nil)
7878
true
7979
end
8080

81-
# Retrieve a list of referral users. This function requires the Partner User's API key.
81+
# Retrieve a list of referral customers. This function requires the Partner User's API key.
8282
# <b>DEPRECATED:</b> Please use <tt>Referral</tt> in the main namespace instead.
8383
def self.all(params = {}, api_key = nil)
8484
warn '[DEPRECATION] Please use `Referral.all` in the main namespace instead.'
8585
response = EasyPost.make_request(:get, '/beta/referral_customers', api_key, params)
8686
EasyPost::Util.convert_to_easypost_object(response, api_key)
8787
end
8888

89-
# Add credit card to a referral user. This function requires the Referral User's API key.
89+
# Add credit card to a referral customer. This function requires the Referral Customer's API key.
9090
# <b>DEPRECATED:</b> Please use <tt>Referral</tt> in the main namespace instead.
9191
def self.add_credit_card(referral_api_key, number, expiration_month, expiration_year, cvc, priority = 'primary')
9292
warn '[DEPRECATION] Please use `Referral.add_credit_card` in the main namespace instead.'
@@ -107,4 +107,52 @@ def self.add_credit_card(referral_api_key, number, expiration_month, expiration_
107107
response = create_easypost_credit_card(referral_api_key, stripe_credit_card_token, priority)
108108
EasyPost::Util.convert_to_easypost_object(response, referral_api_key)
109109
end
110+
111+
# Add a Stripe payment method to a Referral Customer. This function requires the Referral Customer's API key.
112+
# @param [String] stripe_customer_id Unique customer ID provided by Stripe.
113+
# @param [String] payment_method_reference ID of the card or bank account provided by Stripe.
114+
# @param [String] payment_method_type Which priority to save this payment method as on EasyPost, either 'primary' or 'secondary'.
115+
# @param [String] api_key Override the API key used for this request.
116+
# @return [EasyPost::PaymentMethod] The newly-added payment method.
117+
# noinspection RubyParameterNamingConvention
118+
def self.add_payment_method(stripe_customer_id, payment_method_reference, priority = 'primary', api_key = nil)
119+
wrapped_params = {
120+
payment_method: {
121+
stripe_customer_id: stripe_customer_id,
122+
payment_method_reference: payment_method_reference,
123+
priority: priority.downcase,
124+
},
125+
}
126+
response = EasyPost.make_request(:post, '/beta/referral_customers/payment_method', api_key, wrapped_params)
127+
# noinspection RubyMismatchedReturnType
128+
EasyPost::Util.convert_to_easypost_object(response, api_key)
129+
end
130+
131+
# Refund a Referral Customer's wallet by a specified amount. Refund will be issued to the user's original payment method.
132+
# This function requires the Referral Customer's API key.
133+
# @param [Integer] amount The amount to refund, in cents.
134+
# @param [String] api_key Override the API key used for this request.
135+
# @return [EasyPost::Beta::PaymentRefund] The newly-created refund.
136+
def self.refund_by_amount(amount, api_key = nil)
137+
params = {
138+
refund_amount: amount,
139+
}
140+
response = EasyPost.make_request(:post, '/beta/referral_customers/refunds', api_key, params)
141+
# noinspection RubyMismatchedReturnType
142+
EasyPost::Util.convert_to_easypost_object(response, api_key) # TODO: Needs "object" or ID prefix to determine object class.
143+
end
144+
145+
# Refund a Referral Customer's wallet for a specified payment log entry. Refund will be issued to the user's original payment method.
146+
# This function requires the Referral Customer's API key.
147+
# @param [String] payment_log_id Payment log ID to refund.
148+
# @param [String] api_key Override the API key used for this request.
149+
# @return [EasyPost::Beta::PaymentRefund] The newly-created refund.
150+
def self.refund_by_payment_log(payment_log_id, api_key = nil)
151+
params = {
152+
payment_log_id: payment_log_id,
153+
}
154+
response = EasyPost.make_request(:post, '/beta/referral_customers/refunds', api_key, params)
155+
# noinspection RubyMismatchedReturnType
156+
EasyPost::Util.convert_to_easypost_object(response, api_key) # TODO: Needs "object" or ID prefix to determine object class.
157+
end
110158
end

lib/easypost/payment_method.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
# PaymentMethod objects represent a payment method of a user.
44
class EasyPost::PaymentMethod < EasyPost::Resource
5-
# <b>DEPRECATED:</b> Please use <tt>Billing class</tt> instead.
5+
# List all payment methods associated with the current user.
6+
# <b>DEPRECATED:</b> Please use <tt>Billing.retrieve_payment_methods</tt> instead.
67
# Deprecated: v4.5.0 - v6.0.0
78
def self.all(_filters = {}, api_key = nil)
89
warn '[DEPRECATION] `all` is deprecated. Please use `Billing.retrieve_payment_methods` instead.'

lib/easypost/referral.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@ def create_easypost_credit_card(referral_api_key, stripe_object_id, priority = '
5555
end
5656
end
5757

58-
# Create a referral user. This function requires the Partner User's API key.
58+
# Create a referral customer. This function requires the Partner User's API key.
5959
def self.create(params = {}, api_key = nil)
6060
response = EasyPost.make_request(:post, '/v2/referral_customers', api_key, { user: params })
6161
EasyPost::Util.convert_to_easypost_object(response, api_key)
6262
end
6363

64-
# Update a referral user. This function requires the Partner User's API key.
64+
# Update a referral customer. This function requires the Partner User's API key.
6565
def self.update_email(email, user_id, api_key = nil)
6666
wrapped_params = {
6767
user: {
@@ -74,13 +74,13 @@ def self.update_email(email, user_id, api_key = nil)
7474
true
7575
end
7676

77-
# Retrieve a list of referral users. This function requires the Partner User's API key.
77+
# Retrieve a list of referral customers. This function requires the Partner User's API key.
7878
def self.all(params = {}, api_key = nil)
7979
response = EasyPost.make_request(:get, '/v2/referral_customers', api_key, params)
8080
EasyPost::Util.convert_to_easypost_object(response, api_key)
8181
end
8282

83-
# Add credit card to a referral user. This function requires the Referral User's API key.
83+
# Add credit card to a referral customer. This function requires the Referral Customer's API key.
8484
def self.add_credit_card(referral_api_key, number, expiration_month, expiration_year, cvc, priority = 'primary')
8585
easypost_stripe_api_key = retrieve_easypost_stripe_api_key
8686

lib/easypost/util.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ module EasyPost::Util
77
BY_PREFIX = {
88
'ak' => EasyPost::ApiKey,
99
'adr' => EasyPost::Address,
10+
'bank' => EasyPost::PaymentMethod,
1011
'batch' => EasyPost::Batch,
1112
'brd' => EasyPost::Brand,
1213
'ca' => EasyPost::CarrierAccount,
14+
'card' => EasyPost::PaymentMethod,
1315
'cstinfo' => EasyPost::CustomsInfo,
1416
'cstitem' => EasyPost::CustomsItem,
1517
'es' => EasyPost::EndShipper,
@@ -37,10 +39,12 @@ module EasyPost::Util
3739
BY_TYPE = {
3840
'Address' => EasyPost::Address,
3941
'ApiKey' => EasyPost::ApiKey,
42+
'BankAccount' => EasyPost::PaymentMethod,
4043
'Batch' => EasyPost::Batch,
4144
'Brand' => EasyPost::Brand,
4245
'CarbonOffset' => EasyPost::CarbonOffset,
4346
'CarrierAccount' => EasyPost::CarrierAccount,
47+
'CreditCard' => EasyPost::PaymentMethod,
4448
'CustomsInfo' => EasyPost::CustomsInfo,
4549
'CustomsItem' => EasyPost::CustomsItem,
4650
'EndShipper' => EasyPost::EndShipper,
@@ -147,6 +151,7 @@ def self.convert_to_easypost_object(response, api_key, parent = nil, name = nil)
147151
response.map { |i| convert_to_easypost_object(i, api_key, parent) }
148152
when Hash
149153
if (cls_name = response[:object])
154+
# TODO: This line was never hit when debugging all unit tests, suggesting it's broken
150155
cls = BY_TYPE[cls_name]
151156
elsif response[:id]
152157
if response[:id].index('_').nil?

spec/beta/referral_spec.rb

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,34 @@
22

33
require 'spec_helper'
44

5-
REFERRAL_USER_PROD_API_KEY = ENV['REFERRAL_USER_PROD_API_KEY'] || '123'
5+
REFERRAL_CUSTOMER_PROD_API_KEY = ENV['REFERRAL_CUSTOMER_PROD_API_KEY'] || '123'
66

77
describe EasyPost::Beta::Referral, :authenticate_partner do
88
describe '.create' do
9-
it 'creates a referral user' do
9+
it 'creates a referral customer' do
1010
# This test requires a partner user's production API key via PARTNER_USER_PROD_API_KEY.
11-
created_referral_user = described_class.create(
11+
created_referral_customer = described_class.create(
1212
name: 'test user',
1313
1414
phone: '8888888888',
1515
)
1616

17-
expect(created_referral_user).to be_an_instance_of(EasyPost::User)
18-
expect(created_referral_user.id).to match('user_')
19-
expect(created_referral_user.name).to eq('test user')
17+
expect(created_referral_customer).to be_an_instance_of(EasyPost::User)
18+
expect(created_referral_customer.id).to match('user_')
19+
expect(created_referral_customer.name).to eq('test user')
2020
end
2121
end
2222

2323
describe '.update_email' do
24-
it 'updates a referral user' do
24+
it 'updates a referral customer' do
2525
# This test requires a partner user's production API key via PARTNER_USER_PROD_API_KEY.
26-
referral_users = described_class.all(
26+
referral_customers = described_class.all(
2727
page_size: Fixture.page_size,
2828
)
2929

3030
updated_user = described_class.update_email(
3131
32-
referral_users.referral_customers[0].id,
32+
referral_customers.referral_customers[0].id,
3333
)
3434

3535
expect(updated_user).to eq(true)
@@ -38,25 +38,25 @@
3838

3939
describe '.all' do
4040
# This test requires a partner user's production API key via PARTNER_USER_PROD_API_KEY.
41-
it 'retrieve all referral users' do
42-
referral_users = described_class.all(
41+
it 'retrieve all referral customers' do
42+
referral_customers = described_class.all(
4343
page_size: Fixture.page_size,
4444
)
4545

46-
referral_users_array = referral_users.referral_customers
46+
referral_customers_array = referral_customers.referral_customers
4747

48-
expect(referral_users_array.count).to be <= Fixture.page_size
49-
expect(referral_users.has_more).not_to be_nil
50-
expect(referral_users_array).to all(be_an_instance_of(EasyPost::User))
48+
expect(referral_customers_array.count).to be <= Fixture.page_size
49+
expect(referral_customers.has_more).not_to be_nil
50+
expect(referral_customers_array).to all(be_an_instance_of(EasyPost::User))
5151
end
5252
end
5353

5454
describe '.add_credit_card' do
55-
it 'adds a credit card to a referral user account' do
55+
it 'adds a credit card to a referral customer account' do
5656
# This test requires a partner user's production API key via PARTNER_USER_PROD_API_KEY
57-
# as well as one of that user's referral's production API keys via REFERRAL_USER_PROD_API_KEY.
57+
# as well as one of that user's referral's production API keys via REFERRAL_CUSTOMER_PROD_API_KEY.
5858
credit_card = described_class.add_credit_card(
59-
REFERRAL_USER_PROD_API_KEY,
59+
REFERRAL_CUSTOMER_PROD_API_KEY,
6060
Fixture.credit_card_details['number'],
6161
Fixture.credit_card_details['expiration_month'],
6262
Fixture.credit_card_details['expiration_year'],
@@ -73,7 +73,7 @@
7373

7474
expect {
7575
described_class.add_credit_card(
76-
REFERRAL_USER_PROD_API_KEY,
76+
REFERRAL_CUSTOMER_PROD_API_KEY,
7777
Fixture.credit_card_details['number'],
7878
Fixture.credit_card_details['expiration_month'],
7979
Fixture.credit_card_details['expiration_year'],
@@ -82,4 +82,42 @@
8282
}.to raise_error(StandardError).with_message('Could not send card details to Stripe, please try again later.')
8383
end
8484
end
85+
86+
describe '.add_payment_method', :authenticate_referral do
87+
it 'adds a Stripe card or bank account to a referral customer account' do
88+
# This test requires a referral customer's production API key via REFERRAL_CUSTOMER_PROD_API_KEY.
89+
expect {
90+
described_class.add_payment_method(
91+
'cus_123',
92+
'ba_123',
93+
)
94+
}.to raise_error(EasyPost::Error).with_message('Invalid Payment Gateway Reference.')
95+
end
96+
end
97+
98+
describe '.refund_by_amount', :authenticate_referral do
99+
it 'refunds a referral user by a specific amount' do
100+
# This test requires a referral customer's production API key via REFERRAL_CUSTOMER_PROD_API_KEY.
101+
expect {
102+
described_class.refund_by_amount(
103+
2000,
104+
)
105+
}.to raise_error(EasyPost::Error).with_message(
106+
'Refund amount is invalid. Please use a valid amount or escalate to finance.',
107+
)
108+
end
109+
end
110+
111+
describe '.refund_by_payment_log', :authenticate_referral do
112+
it 'refunds a referral user by a specific payment log entry' do
113+
# This test requires a referral customer's production API key via REFERRAL_CUSTOMER_PROD_API_KEY.
114+
expect {
115+
described_class.refund_by_payment_log(
116+
'paylog_123',
117+
)
118+
}.to raise_error(EasyPost::Error).with_message(
119+
'We could not find a transaction with that id.',
120+
)
121+
end
122+
end
85123
end

0 commit comments

Comments
 (0)