Skip to content

Commit 1c6b051

Browse files
Merge pull request #96 from shore-gmbh/FEAT-subscription-create-with-items
feat: add `create_with_items/3` to `Subscription`
2 parents f4ee631 + 76b976d commit 1c6b051

3 files changed

Lines changed: 213 additions & 1 deletion

File tree

lib/chargebeex/action.ex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ defmodule Chargebeex.Action do
7373
Path.join([resource_base_path(resource), action])
7474
end
7575

76+
def nested_resource_path_generic_without_id(nested_to, action) do
77+
path = Enum.map(nested_to, fn {resource, id} -> resource_path(resource, id) end)
78+
Path.join(path ++ [action])
79+
end
80+
7681
def delete_path(resource, id) do
7782
Path.join([resource_path(resource, id), "delete"])
7883
end

lib/chargebeex/subscription/subscription.ex

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
defmodule Chargebeex.Subscription do
22
use TypedStruct
3-
use Chargebeex.Resource, resource: "subscription", only: [:list, :retrieve, :update]
3+
4+
@resource "subscription"
5+
use Chargebeex.Resource, resource: @resource, only: [:list, :retrieve, :update]
6+
7+
alias Chargebeex.Builder
8+
alias Chargebeex.Client
49

510
@typedoc """
611
"future" | "in_trial" | "active" | "non_renewing" | "paused" | "cancelled"
@@ -99,4 +104,105 @@ defmodule Chargebeex.Subscription do
99104
|> super()
100105
|> Chargebeex.Resource.add_custom_fields(raw_data)
101106
end
107+
108+
@doc """
109+
Creates a Subcription with items for a Customer
110+
111+
## Examples
112+
113+
iex> Chargebeex.Subscription.create_with_items("169ljDT1Op0yuxET", %{
114+
subscription_items: [
115+
%{
116+
item_price_id: "DEF789LMN012",
117+
quantity: 1
118+
}
119+
]
120+
})
121+
{:ok, %Chargebeex.Subscription{
122+
id: "GHI456OPQ789",
123+
contract_term: %{},
124+
referral_info: %{},
125+
shipping_address: %{},
126+
coupons: nil,
127+
charged_items: nil,
128+
item_tiers: nil,
129+
subscription_items: [
130+
%{
131+
"amount" => 100,
132+
"free_quantity" => 0,
133+
"item_price_id" => "DEF789LMN012",
134+
"item_type" => "plan",
135+
"object" => "subscription_item",
136+
"quantity" => 1,
137+
"trial_end" => 1705877999,
138+
"unit_price" => 100
139+
}
140+
],
141+
business_entity_id: "ABC123XYZ456",
142+
auto_close_invoices: true,
143+
custom_fields: %{},
144+
metadata: %{},
145+
create_pending_invoices: false,
146+
free_period_unit: nil,
147+
free_period: nil,
148+
cancel_reason_code: nil,
149+
changes_scheduled_at: nil,
150+
deleted: false,
151+
invoice_notes: nil,
152+
base_currency_code: nil,
153+
exchange_rate: nil,
154+
mrr: nil,
155+
total_dues: nil,
156+
due_since: nil,
157+
due_invoices_count: 0,
158+
net_term_days: nil,
159+
channel: "web",
160+
cancel_schedule_created_at: nil,
161+
plan_amount_in_decimal: nil,
162+
plan_free_quantity_in_decimal: nil,
163+
payment_source_id: nil,
164+
has_scheduled_changes: false,
165+
has_scheduled_advance_invoices: false,
166+
updated_at: 1705785896,
167+
resource_version: 1705785896428,
168+
created_from_ip: nil,
169+
cancel_reason: nil,
170+
cancelled_at: nil,
171+
resume_date: nil,
172+
pause_date: nil,
173+
override_relationship: false,
174+
contract_term_billing_cycle_on_renewal: nil,
175+
activated_at: nil,
176+
started_at: 1705705200,
177+
created_at: 1705785896,
178+
next_billing_at: 1705878000,
179+
current_term_end: nil,
180+
current_term_start: nil,
181+
trial_end_action: nil,
182+
currency_code: nil,
183+
start_date: nil,
184+
trial_end: nil,
185+
billing_period: nil,
186+
billing_period_unit: nil,
187+
object: nil,
188+
remaining_billing_cycles: nil,
189+
po_number: nil,
190+
plan_quantity_in_decimal: nil,
191+
plan_unit_price_in_decimal: nil,
192+
customer_id: nil,
193+
status: nil,
194+
trial_start: nil
195+
}}
196+
"""
197+
def create_with_items(customer_id, params, opts \\ []) do
198+
with path <-
199+
Chargebeex.Action.nested_resource_path_generic_without_id(
200+
[customer: customer_id],
201+
"subscription_for_items"
202+
),
203+
{:ok, _status_code, _headers, content} <- Client.post(path, params, opts),
204+
builded <- Builder.build(content) do
205+
{:ok, Map.get(builded, @resource)}
206+
end
207+
end
102208
end
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
defmodule Chargebeex.SubscriptionTest do
2+
use ExUnit.Case, async: true
3+
4+
import Hammox
5+
6+
alias Chargebeex.Fixtures.Common
7+
alias Chargebeex.Subscription
8+
9+
setup :verify_on_exit!
10+
11+
describe "create_with_items" do
12+
test "with bad authentication should fail" do
13+
unauthorized = Common.unauthorized()
14+
15+
expect(
16+
Chargebeex.HTTPClientMock,
17+
:post,
18+
fn url, data, headers ->
19+
assert url ==
20+
"https://test-namespace.chargebee.com/api/v2/customers/foobar/subscription_for_items"
21+
22+
assert headers == [
23+
{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"},
24+
{"Content-Type", "application/x-www-form-urlencoded"}
25+
]
26+
27+
assert data == ""
28+
29+
{:ok, 401, [], Jason.encode!(unauthorized)}
30+
end
31+
)
32+
33+
assert {:error, 401, [], ^unauthorized} =
34+
Chargebeex.Subscription.create_with_items("foobar", %{})
35+
end
36+
37+
test "with invalid data should fail" do
38+
bad_request = Common.bad_request()
39+
40+
expect(
41+
Chargebeex.HTTPClientMock,
42+
:post,
43+
fn url, data, headers ->
44+
assert url ==
45+
"https://test-namespace.chargebee.com/api/v2/customers/foobar/subscription_for_items"
46+
47+
assert headers == [
48+
{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"},
49+
{"Content-Type", "application/x-www-form-urlencoded"}
50+
]
51+
52+
assert data ==
53+
"subscription_items[item_price_id][0]=invalid_item_price_id&subscription_items[quantity][0]=1"
54+
55+
{:ok, 400, [], Jason.encode!(bad_request)}
56+
end
57+
)
58+
59+
assert {:error, 400, [], ^bad_request} =
60+
Chargebeex.Subscription.create_with_items("foobar", %{
61+
subscription_items: [
62+
%{
63+
item_price_id: "invalid_item_price_id",
64+
quantity: 1
65+
}
66+
]
67+
})
68+
end
69+
70+
test "with valid data should succeed" do
71+
expect(
72+
Chargebeex.HTTPClientMock,
73+
:post,
74+
fn url, data, headers ->
75+
assert url ==
76+
"https://test-namespace.chargebee.com/api/v2/customers/foobar/subscription_for_items"
77+
78+
assert headers == [
79+
{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"},
80+
{"Content-Type", "application/x-www-form-urlencoded"}
81+
]
82+
83+
assert data ==
84+
"subscription_items[item_price_id][0]=item_price_id&subscription_items[quantity][0]=1"
85+
86+
{:ok, 200, [], Jason.encode!(%{customer: %{}, subscription: %{}})}
87+
end
88+
)
89+
90+
assert {:ok, %Subscription{}} =
91+
Chargebeex.Subscription.create_with_items("foobar", %{
92+
subscription_items: [
93+
%{
94+
item_price_id: "item_price_id",
95+
quantity: 1
96+
}
97+
]
98+
})
99+
end
100+
end
101+
end

0 commit comments

Comments
 (0)