From b7bf18ebd916264c378675e6f686b3fe8d5b8c66 Mon Sep 17 00:00:00 2001 From: Matt Francois Date: Thu, 18 Feb 2021 06:06:03 +0000 Subject: [PATCH 01/25] added payment intent resource --- lib/chargebee_elixir/payment_intent.ex | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 lib/chargebee_elixir/payment_intent.ex diff --git a/lib/chargebee_elixir/payment_intent.ex b/lib/chargebee_elixir/payment_intent.ex new file mode 100644 index 0000000..b3a5e4e --- /dev/null +++ b/lib/chargebee_elixir/payment_intent.ex @@ -0,0 +1,3 @@ +defmodule ChargebeeElixir.PaymentIntent do + use ChargebeeElixir.Resource, "payment_intent" +end From a253baa1386b4ad449e90ec2c055830bd0482a30 Mon Sep 17 00:00:00 2001 From: Matt Francois Date: Tue, 9 Mar 2021 07:57:40 +0000 Subject: [PATCH 02/25] added update request. added payment source resource. --- lib/chargebee_elixir/payment_source.ex | 3 +++ lib/chargebee_elixir/resource.ex | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 lib/chargebee_elixir/payment_source.ex diff --git a/lib/chargebee_elixir/payment_source.ex b/lib/chargebee_elixir/payment_source.ex new file mode 100644 index 0000000..593aac8 --- /dev/null +++ b/lib/chargebee_elixir/payment_source.ex @@ -0,0 +1,3 @@ +defmodule ChargebeeElixir.PaymentSource do + use ChargebeeElixir.Resource, "payment_source" +end diff --git a/lib/chargebee_elixir/resource.ex b/lib/chargebee_elixir/resource.ex index 599bc4f..a52571b 100644 --- a/lib/chargebee_elixir/resource.ex +++ b/lib/chargebee_elixir/resource.ex @@ -35,6 +35,10 @@ defmodule ChargebeeElixir.Resource do )[@resource] end + def update(id, params, path \\ "") do + Interface.post("#{resource_path(id)}#{path}", params)[@resource] + end + def resource_base_path() do "/#{@resource}s" end From 57125293f607923f15505f263faef13f4852b943 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Thu, 9 Dec 2021 12:09:10 -0600 Subject: [PATCH 03/25] `mix format` --- test/chargebee_elixir/addon_test.exs | 64 ++++-- test/chargebee_elixir/hosted_page_test.exs | 71 +++--- test/chargebee_elixir/interface_test.exs | 211 +++++++++--------- test/chargebee_elixir/invoice_test.exs | 56 +++-- test/chargebee_elixir/portal_session_test.exs | 40 ++-- test/chargebee_elixir/subscription_test.exs | 58 +++-- 6 files changed, 284 insertions(+), 216 deletions(-) diff --git a/test/chargebee_elixir/addon_test.exs b/test/chargebee_elixir/addon_test.exs index 95d0955..a5aceb6 100644 --- a/test/chargebee_elixir/addon_test.exs +++ b/test/chargebee_elixir/addon_test.exs @@ -9,9 +9,10 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :get!, - fn (url, headers) -> + fn url, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/addons/1234" assert headers == [{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}] + %{ status_code: 401 } @@ -27,9 +28,10 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :get!, - fn (url, headers) -> + fn url, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/addons/1234" assert headers == [{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}] + %{ status_code: 404 } @@ -43,9 +45,10 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :get!, - fn (url, headers) -> + fn url, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/addons/1234" assert headers == [{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}] + %{ status_code: 200, body: '{"addon": {"id": 1234}}' @@ -62,9 +65,10 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :get!, - fn (url, headers) -> + fn url, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/addons" assert headers == [{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}] + %{ status_code: 401 } @@ -80,9 +84,10 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :get!, - fn (url, headers) -> + fn url, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/addons" assert headers == [{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}] + %{ status_code: 200, body: '{"list": [{"addon": {"id": 1234}}]}' @@ -97,9 +102,12 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :get!, - fn (url, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/addons?id%5Bin%5D=%5B1234%2C1235%5D" + fn url, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/addons?id%5Bin%5D=%5B1234%2C1235%5D" + assert headers == [{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}] + %{ status_code: 200, body: '{ @@ -113,9 +121,12 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :get!, - fn (url, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/addons?id%5Bin%5D=%5B1234%2C1235%5D&offset=1235" + fn url, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/addons?id%5Bin%5D=%5B1234%2C1235%5D&offset=1235" + assert headers == [{"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}] + %{ status_code: 200, body: '{ @@ -125,7 +136,10 @@ defmodule ChargebeeElixir.AddonTest do end ) - assert ChargebeeElixir.Addon.list(%{"id[in]": "[1234,1235]"}) == [%{"id" => 1234}, %{"id" => 1235}] + assert ChargebeeElixir.Addon.list(%{"id[in]": "[1234,1235]"}) == [ + %{"id" => 1234}, + %{"id" => 1235} + ] end end @@ -134,13 +148,15 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> + fn url, data, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/addons" assert data == "id=addon-a" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 401 } @@ -156,13 +172,15 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> + fn url, data, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/addons" assert data == "id=addon-a" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 400, body: '{"message": "Unknown"}' @@ -179,13 +197,15 @@ defmodule ChargebeeElixir.AddonTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> + fn url, data, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/addons" assert data == "id=addon-a" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 200, body: '{"addon": {"id": "addon-a"}}' diff --git a/test/chargebee_elixir/hosted_page_test.exs b/test/chargebee_elixir/hosted_page_test.exs index 440278b..f42c6e1 100644 --- a/test/chargebee_elixir/hosted_page_test.exs +++ b/test/chargebee_elixir/hosted_page_test.exs @@ -9,13 +9,17 @@ defmodule ChargebeeElixir.HostedPageTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> + fn url, data, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/hosted_pages/checkout_new" - assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&subscription[plan_id]=plan-a" + + assert data == + "addons[id][0]=addon-a&addons[id][1]=addon-b&subscription[plan_id]=plan-a" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 200, body: '{"hosted_page": {"url": "https://doe.com"}}' @@ -24,14 +28,14 @@ defmodule ChargebeeElixir.HostedPageTest do ) assert ChargebeeElixir.HostedPage.checkout_new(%{ - subscription: %{ - plan_id: "plan-a", - }, - addons: [ - %{ id: "addon-a"}, - %{ id: "addon-b"} - ] - }) == %{"url" => "https://doe.com"} + subscription: %{ + plan_id: "plan-a" + }, + addons: [ + %{id: "addon-a"}, + %{id: "addon-b"} + ] + }) == %{"url" => "https://doe.com"} end end @@ -40,13 +44,18 @@ defmodule ChargebeeElixir.HostedPageTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/hosted_pages/checkout_existing" - assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&customer[id]=cus-a&subscription[id]=subscription-a&subscription[plan_id]=plan-a" + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/hosted_pages/checkout_existing" + + assert data == + "addons[id][0]=addon-a&addons[id][1]=addon-b&customer[id]=cus-a&subscription[id]=subscription-a&subscription[plan_id]=plan-a" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 200, body: '{"hosted_page": {"url": "https://doe.com"}}' @@ -55,18 +64,18 @@ defmodule ChargebeeElixir.HostedPageTest do ) assert ChargebeeElixir.HostedPage.checkout_existing(%{ - subscription: %{ - id: "subscription-a", - plan_id: "plan-a", - }, - customer: %{ - id: "cus-a" - }, - addons: [ - %{ id: "addon-a"}, - %{ id: "addon-b"} - ] - }) == %{"url" => "https://doe.com"} + subscription: %{ + id: "subscription-a", + plan_id: "plan-a" + }, + customer: %{ + id: "cus-a" + }, + addons: [ + %{id: "addon-a"}, + %{id: "addon-b"} + ] + }) == %{"url" => "https://doe.com"} end end end diff --git a/test/chargebee_elixir/interface_test.exs b/test/chargebee_elixir/interface_test.exs index 30c755a..149c982 100644 --- a/test/chargebee_elixir/interface_test.exs +++ b/test/chargebee_elixir/interface_test.exs @@ -4,127 +4,128 @@ defmodule ChargebeeElixir.InterfaceTest do describe "transform_arrays_for_chargebee" do test "simple list" do assert ChargebeeElixir.Interface.transform_arrays_for_chargebee([ - %{id: "object-a"}, - %{id: "object-b"} - ]) == %{ - id: %{ - 0 => "object-a", - 1 => "object-b" - } - } + %{id: "object-a"}, + %{id: "object-b"} + ]) == %{ + id: %{ + 0 => "object-a", + 1 => "object-b" + } + } end test "deep nesting, no lists" do assert ChargebeeElixir.Interface.transform_arrays_for_chargebee(%{ - addon: %{ - id: "addon-a", - nested: %{ - object: %{ - id: "object-a" - } - } - } - }) == %{ - addon: %{ - id: "addon-a", - nested: %{ - object: %{ - id: "object-a" - } - } - } - } + addon: %{ + id: "addon-a", + nested: %{ + object: %{ + id: "object-a" + } + } + } + }) == %{ + addon: %{ + id: "addon-a", + nested: %{ + object: %{ + id: "object-a" + } + } + } + } end test "simple nesting" do assert ChargebeeElixir.Interface.transform_arrays_for_chargebee(%{ - addons: [ - %{ - id: "addon-a", - price: 10 - }, - %{ - id: "addon-b", - quantity: 2 - } - ] - }) == %{ - addons: %{ - id: %{ - 0 => "addon-a", - 1 => "addon-b" - }, - price: %{ - 0 => 10 - }, - quantity: %{ - 1 => 2 - } - } - } + addons: [ + %{ + id: "addon-a", + price: 10 + }, + %{ + id: "addon-b", + quantity: 2 + } + ] + }) == %{ + addons: %{ + id: %{ + 0 => "addon-a", + 1 => "addon-b" + }, + price: %{ + 0 => 10 + }, + quantity: %{ + 1 => 2 + } + } + } end test "incorrect nesting" do assert_raise ChargebeeElixir.IncorrectDataFormatError, - "Unsupported data: lists should contains objects only", fn -> - ChargebeeElixir.Interface.transform_arrays_for_chargebee(%{ - addons: [ - %{ - id: "addon-a", - price: 10 - }, - %{ - id: "addon-b", - quantity: 2 - }, - "a" - ] - }) - end + "Unsupported data: lists should contains objects only", + fn -> + ChargebeeElixir.Interface.transform_arrays_for_chargebee(%{ + addons: [ + %{ + id: "addon-a", + price: 10 + }, + %{ + id: "addon-b", + quantity: 2 + }, + "a" + ] + }) + end end test "complex nesting" do assert ChargebeeElixir.Interface.transform_arrays_for_chargebee(%{ - addons: [ - %{ - id: "addon-a", - price: 10, - nested_objects: [ - %{ - id: "object-a" - }, - %{ - id: "object-b" - } - ] - }, - %{ - id: "addon-b", - quantity: 2 - } - ] - }) == %{ - addons: %{ - id: %{ - 0 => "addon-a", - 1 => "addon-b" - }, - price: %{ - 0 => 10 - }, - quantity: %{ - 1 => 2 - }, - nested_objects: %{ - 0 => %{ - id: %{ - 0 => "object-a", - 1 => "object-b" - } - } - } - } - } + addons: [ + %{ + id: "addon-a", + price: 10, + nested_objects: [ + %{ + id: "object-a" + }, + %{ + id: "object-b" + } + ] + }, + %{ + id: "addon-b", + quantity: 2 + } + ] + }) == %{ + addons: %{ + id: %{ + 0 => "addon-a", + 1 => "addon-b" + }, + price: %{ + 0 => 10 + }, + quantity: %{ + 1 => 2 + }, + nested_objects: %{ + 0 => %{ + id: %{ + 0 => "object-a", + 1 => "object-b" + } + } + } + } + } end end end diff --git a/test/chargebee_elixir/invoice_test.exs b/test/chargebee_elixir/invoice_test.exs index d9b078b..0429da6 100644 --- a/test/chargebee_elixir/invoice_test.exs +++ b/test/chargebee_elixir/invoice_test.exs @@ -18,13 +18,17 @@ defmodule ChargebeeElixir.InvoiceTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/invoices/draft_inv_abcde/close" + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/invoices/draft_inv_abcde/close" + assert data == "invoice_note=This+is+a+note" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 401 } @@ -40,13 +44,17 @@ defmodule ChargebeeElixir.InvoiceTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/invoices/draft_inv_abcde/close" + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/invoices/draft_inv_abcde/close" + assert data == "invoice_note=This+is+a+note" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 404 } @@ -62,13 +70,17 @@ defmodule ChargebeeElixir.InvoiceTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/invoices/draft_inv_abcde/close" + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/invoices/draft_inv_abcde/close" + assert data == "invoice_note=This+is+a+note" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 400, body: '{"message": "Unknown"}' @@ -85,13 +97,17 @@ defmodule ChargebeeElixir.InvoiceTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/invoices/draft_inv_abcde/close" + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/invoices/draft_inv_abcde/close" + assert data == "invoice_note=This+is+a+note" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 200, body: '{"invoice": {"id": "abcde"}}' diff --git a/test/chargebee_elixir/portal_session_test.exs b/test/chargebee_elixir/portal_session_test.exs index 6cb08e7..ee8b948 100644 --- a/test/chargebee_elixir/portal_session_test.exs +++ b/test/chargebee_elixir/portal_session_test.exs @@ -9,13 +9,15 @@ defmodule ChargebeeElixir.PortalSessionTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> + fn url, data, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/portal_sessions" assert data == "" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 401 } @@ -31,13 +33,15 @@ defmodule ChargebeeElixir.PortalSessionTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> + fn url, data, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/portal_sessions" assert data == "" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 400, body: '{"message": "Unknown"}' @@ -54,13 +58,15 @@ defmodule ChargebeeElixir.PortalSessionTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> + fn url, data, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/portal_sessions" assert data == "customer[id]=cus_1234&redirect_url=https%3A%2F%2Fredirect.com" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 200, body: '{"portal_session": {"url": "https://doe.com"}}' @@ -69,11 +75,11 @@ defmodule ChargebeeElixir.PortalSessionTest do ) assert ChargebeeElixir.PortalSession.create(%{ - redirect_url: "https://redirect.com", - customer: %{ - id: "cus_1234" - } - }) == %{"url" => "https://doe.com"} + redirect_url: "https://redirect.com", + customer: %{ + id: "cus_1234" + } + }) == %{"url" => "https://doe.com"} end end end diff --git a/test/chargebee_elixir/subscription_test.exs b/test/chargebee_elixir/subscription_test.exs index 170ec50..439e36e 100644 --- a/test/chargebee_elixir/subscription_test.exs +++ b/test/chargebee_elixir/subscription_test.exs @@ -11,7 +11,7 @@ defmodule ChargebeeElixir.SubscriptionTest do plan_id: "plan-a", addons: [ %{id: "addon-a"}, - %{id: "addon-b"}, + %{id: "addon-b"} ] } ) @@ -22,13 +22,17 @@ defmodule ChargebeeElixir.SubscriptionTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" + assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 401 } @@ -44,13 +48,17 @@ defmodule ChargebeeElixir.SubscriptionTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" + assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 404 } @@ -66,13 +74,17 @@ defmodule ChargebeeElixir.SubscriptionTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" + assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 400, body: '{"message": "Unknown"}' @@ -89,13 +101,17 @@ defmodule ChargebeeElixir.SubscriptionTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn (url, data, headers) -> - assert url == "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" + assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" + assert headers == [ - {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, - {"Content-Type", "application/x-www-form-urlencoded"} - ] + {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, + {"Content-Type", "application/x-www-form-urlencoded"} + ] + %{ status_code: 200, body: '{"subscription": {"id": "sub-a"}}' From 3a2396c3e35323ad6141a36287f5db89a1205a54 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Thu, 9 Dec 2021 12:09:29 -0600 Subject: [PATCH 04/25] feature: Add Item Interface --- lib/chargebee_elixir/item.ex | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 lib/chargebee_elixir/item.ex diff --git a/lib/chargebee_elixir/item.ex b/lib/chargebee_elixir/item.ex new file mode 100644 index 0000000..f7b6cf3 --- /dev/null +++ b/lib/chargebee_elixir/item.ex @@ -0,0 +1,6 @@ +defmodule ChargebeeElixir.Item do + @moduledoc """ + an interface for interacting with Items + """ + use ChargebeeElixir.Resource, "item" +end From 1e085da927a42b8b4c7561f7fca757b61ab32dc1 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Thu, 9 Dec 2021 12:10:53 -0600 Subject: [PATCH 05/25] Refactor for readability --- lib/chargebee_elixir/hosted_page.ex | 9 ++- lib/chargebee_elixir/interface.ex | 115 +++++++++++++++------------ lib/chargebee_elixir/invoice.ex | 7 +- lib/chargebee_elixir/resource.ex | 50 +++++++----- lib/chargebee_elixir/subscription.ex | 7 +- 5 files changed, 111 insertions(+), 77 deletions(-) diff --git a/lib/chargebee_elixir/hosted_page.ex b/lib/chargebee_elixir/hosted_page.ex index cd3d937..ac5a3c3 100644 --- a/lib/chargebee_elixir/hosted_page.ex +++ b/lib/chargebee_elixir/hosted_page.ex @@ -1,6 +1,11 @@ defmodule ChargebeeElixir.HostedPage do use ChargebeeElixir.Resource, "hosted_page" - def checkout_new(params) do create(params, "/checkout_new") end - def checkout_existing(params) do create(params, "/checkout_existing") end + def checkout_new(params) do + create(params, "/checkout_new") + end + + def checkout_existing(params) do + create(params, "/checkout_existing") + end end diff --git a/lib/chargebee_elixir/interface.ex b/lib/chargebee_elixir/interface.ex index 6715fe6..4984b80 100644 --- a/lib/chargebee_elixir/interface.ex +++ b/lib/chargebee_elixir/interface.ex @@ -5,38 +5,41 @@ defmodule ChargebeeElixir.Interface do end def get(path, params) do - params_string = params - |> URI.encode_query() + params_string = URI.encode_query(params) - url = [fullpath(path), params_string] - |> Enum.filter(fn(s) -> String.length(s) > 0 end) + url = + [fullpath(path), params_string] + |> Enum.filter(fn s -> String.length(s) > 0 end) |> Enum.join("?") - http_client().get!(url,headers()) - |> handle_response() + http_client().get!(url, headers()) + |> handle_response() end def post(path, data) do - body = data + body = + data |> transform_arrays_for_chargebee - |> Plug.Conn.Query.encode() + |> Query.encode() + http_client().post!( fullpath(path), body, headers() ++ [{"Content-Type", "application/x-www-form-urlencoded"}] ) - |> handle_response() + |> handle_response() end defp handle_response(%{body: body, status_code: 200}) do - body - |> Jason.decode! + Jason.decode!(body) end defp handle_response(%{body: body, status_code: 400}) do - message = body - |> Jason.decode! + message = + body + |> Jason.decode!() |> Map.get("message") + raise ChargebeeElixir.InvalidRequestError, message: message end @@ -52,54 +55,68 @@ defmodule ChargebeeElixir.Interface do raise ChargebeeElixir.UnknownError end - defp http_client() do + defp http_client do Application.get_env(:chargebee_elixir, :http_client, HTTPoison) end defp fullpath(path) do + # TODO someday: Allow multiple Chargebee Interfaces with multiple namespaces namespace = Application.get_env(:chargebee_elixir, :namespace) "https://#{namespace}.chargebee.com/api/v2#{path}" end - defp headers() do - api_key = Application.get_env(:chargebee_elixir, :api_key) + defp headers do + api_key = + :chargebee_elixir + |> Application.get_env(:api_key) + |> Kernel.<>(":") + |> Base.encode64() + [ - {"Authorization", "Basic #{"#{api_key}:" |> Base.encode64}"} + {"Authorization", "Basic " <> api_key} ] end - def transform_arrays_for_chargebee(data) do - case data do - map_data when is_map(map_data) -> - map_data - |> Enum.map(fn {k, v} -> - {k, transform_arrays_for_chargebee(v)} - end) - |> Enum.into(%{}) - list_data when is_list(list_data) -> - transformed_list_data = list_data - |> Enum.map(fn item -> transform_arrays_for_chargebee(item) end) + def transform_arrays_for_chargebee(map_data) when is_map(map_data) do + map_data + |> Enum.map(fn {k, v} -> + {k, transform_arrays_for_chargebee(v)} + end) + |> Enum.into(%{}) + end + + def transform_arrays_for_chargebee(list_data) when is_list(list_data) do + transformed_list_data = + list_data + |> Enum.map(fn item -> transform_arrays_for_chargebee(item) end) + + transformed_list_data + |> Enum.map(fn item -> + case item do + map_item when is_map(map_item) -> + Map.keys(map_item) + + _ -> + raise ChargebeeElixir.IncorrectDataFormatError, + message: "Unsupported data: lists should contains objects only" + end + end) + |> List.flatten() + |> Enum.uniq() + |> Enum.map(fn key -> + { + key, transformed_list_data - |> Enum.map(fn (item) -> case item do - map_item when is_map(map_item) -> Map.keys(map_item) - _ -> raise ChargebeeElixir.IncorrectDataFormatError, - message: "Unsupported data: lists should contains objects only" - end - end) - |> List.flatten - |> Enum.uniq - |> Enum.map(fn (key) -> - { - key, - transformed_list_data - |> Enum.with_index - |> Enum.map(fn {item, index} -> {index, item[key]} end) - |> Enum.filter(fn {_index, item} -> !is_nil(item) end) - |> Enum.into(%{}) - } - end) - |> Enum.into(%{}) - other_data -> other_data - end + |> Enum.with_index() + |> Enum.map(fn {item, index} -> {index, item[key]} end) + |> Enum.filter(fn {_index, item} -> !is_nil(item) end) + |> Enum.into(%{}) + } + end) + |> Enum.into(%{}) + end + + def transform_arrays_for_chargebee(other_data) do + other_data end end diff --git a/lib/chargebee_elixir/invoice.ex b/lib/chargebee_elixir/invoice.ex index 0da2230..ea4f4ed 100644 --- a/lib/chargebee_elixir/invoice.ex +++ b/lib/chargebee_elixir/invoice.ex @@ -1,6 +1,7 @@ defmodule ChargebeeElixir.Invoice do use ChargebeeElixir.Resource, "invoice" - def close(id, params \\ %{}) do post_endpoint(id, "/close", params) end -end - + def close(id, params \\ %{}) do + post_resource(id, "/close", params) + end +end diff --git a/lib/chargebee_elixir/resource.ex b/lib/chargebee_elixir/resource.ex index fad16cb..88f1465 100644 --- a/lib/chargebee_elixir/resource.ex +++ b/lib/chargebee_elixir/resource.ex @@ -1,4 +1,5 @@ defmodule ChargebeeElixir.Resource do + @moduledoc false defmacro __using__(resource) do quote do alias ChargebeeElixir.Interface @@ -6,44 +7,55 @@ defmodule ChargebeeElixir.Resource do @resource unquote(resource) def retrieve(id) do - Interface.get(resource_path(id))[@resource] + id |> resource_path() |> Interface.get() |> Map.get(@resource) rescue - e in ChargebeeElixir.NotFoundError -> nil + ChargebeeElixir.NotFoundError -> nil end - def list do - __MODULE__.list(%{}) - end - - def list(params) do + def list(params \\ %{}) do + # Should pagination be by default? case Interface.get(resource_base_path(), params) do %{"list" => current_list, "next_offset" => next_offset} -> - Enum.map(current_list, fn(hash) -> hash[@resource] end) ++ __MODULE__.list(Map.merge(params, %{"offset" => next_offset})) + Enum.map(current_list, &Map.get(&1, @resource)) ++ + __MODULE__.list(Map.merge(params, %{"offset" => next_offset})) + %{"list" => current_list} -> - Enum.map(current_list, fn(hash) -> hash[@resource] end) + Enum.map(current_list, &Map.get(&1, @resource)) end end def create(params, path \\ "") do - Interface.post("#{resource_base_path()}#{path}", params)[@resource] + resource_base_path() + |> Kernel.<>(path) + |> Interface.post(params) + |> Map.get(@resource) end - def post_endpoint(id, endpoint, params) do - Interface.post("#{resource_path(id)}#{endpoint}", params)[@resource] + def post_resource(resource_id, endpoint, params) do + resource_id + |> resource_path() + |> Kernel.<>(endpoint) + |> Interface.post(params) + |> Map.get(@resource) end def create_for_parent(parent_path, params, path \\ "") do - Interface.post( - "#{parent_path}#{resource_base_path()}#{path}", - params - )[@resource] + parent_path + |> Kernel.<>(resource_base_path()) + |> Kernel.<>(path) + |> Interface.post(params) + |> Map.get(@resource) end - def update(id, params, path \\ "") do - Interface.post("#{resource_path(id)}#{path}", params)[@resource] + def update(resource_id, params, path \\ "") do + resource_id + |> resource_path() + |> Kernel.<>(path) + |> Interface.post(params) + |> Map.get(@resource) end - def resource_base_path() do + def resource_base_path do "/#{@resource}s" end diff --git a/lib/chargebee_elixir/subscription.ex b/lib/chargebee_elixir/subscription.ex index ae3407d..56d0b5f 100644 --- a/lib/chargebee_elixir/subscription.ex +++ b/lib/chargebee_elixir/subscription.ex @@ -2,9 +2,8 @@ defmodule ChargebeeElixir.Subscription do use ChargebeeElixir.Resource, "subscription" def create_for_customer(customer_id, params) do - create_for_parent( - ChargebeeElixir.Customer.resource_path(customer_id), - params - ) + customer_id + |> ChargebeeElixir.Customer.resource_path() + |> create_for_parent(params) end end From 3ee5d97c18fd04d8e1f0f24e1a315da86188918a Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Thu, 9 Dec 2021 12:11:21 -0600 Subject: [PATCH 06/25] docs: Add basic docs of resources --- lib/chargebee_elixir.ex | 4 +++- lib/chargebee_elixir/addon.ex | 3 +++ lib/chargebee_elixir/customer.ex | 3 +++ lib/chargebee_elixir/event.ex | 33 ++++++++++++++++++++++++++ lib/chargebee_elixir/hosted_page.ex | 3 +++ lib/chargebee_elixir/interface.ex | 9 +++++++ lib/chargebee_elixir/invoice.ex | 3 +++ lib/chargebee_elixir/payment_intent.ex | 3 +++ lib/chargebee_elixir/payment_source.ex | 3 +++ lib/chargebee_elixir/plan.ex | 3 +++ lib/chargebee_elixir/portal_session.ex | 3 +++ lib/chargebee_elixir/subscription.ex | 3 +++ 12 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 lib/chargebee_elixir/event.ex diff --git a/lib/chargebee_elixir.ex b/lib/chargebee_elixir.ex index 94d97e2..279c569 100644 --- a/lib/chargebee_elixir.ex +++ b/lib/chargebee_elixir.ex @@ -1,3 +1,5 @@ defmodule ChargebeeElixir do - + @moduledoc """ + Resources for interacting with Chargebee API Resources + """ end diff --git a/lib/chargebee_elixir/addon.ex b/lib/chargebee_elixir/addon.ex index eece7f7..afe20b0 100644 --- a/lib/chargebee_elixir/addon.ex +++ b/lib/chargebee_elixir/addon.ex @@ -1,3 +1,6 @@ defmodule ChargebeeElixir.Addon do + @moduledoc """ + an interface for interacting with Addons + """ use ChargebeeElixir.Resource, "addon" end diff --git a/lib/chargebee_elixir/customer.ex b/lib/chargebee_elixir/customer.ex index 7bf7548..1755a43 100644 --- a/lib/chargebee_elixir/customer.ex +++ b/lib/chargebee_elixir/customer.ex @@ -1,3 +1,6 @@ defmodule ChargebeeElixir.Customer do + @moduledoc """ + an interface for interacting with Customers + """ use ChargebeeElixir.Resource, "customer" end diff --git a/lib/chargebee_elixir/event.ex b/lib/chargebee_elixir/event.ex new file mode 100644 index 0000000..18169bd --- /dev/null +++ b/lib/chargebee_elixir/event.ex @@ -0,0 +1,33 @@ +defmodule ChargebeeElixir.Event do + @moduledoc """ + an interface for interacting with Events + """ + @resource "event" + alias ChargebeeElixir.Interface + + def retrieve(id) do + id |> resource_path() |> Interface.get() |> Map.get(@resource) + rescue + ChargebeeElixir.NotFoundError -> nil + end + + def list(params \\ %{}) do + # Should pagination be by default? + case Interface.get(resource_base_path(), params) do + %{"list" => current_list, "next_offset" => next_offset} -> + Enum.map(current_list, &Map.get(&1, @resource)) ++ + __MODULE__.list(Map.merge(params, %{"offset" => next_offset})) + + %{"list" => current_list} -> + Enum.map(current_list, &Map.get(&1, @resource)) + end + end + + defp resource_base_path do + "/#{@resource}s" + end + + defp resource_path(id) do + "#{resource_base_path()}/#{id}" + end +end diff --git a/lib/chargebee_elixir/hosted_page.ex b/lib/chargebee_elixir/hosted_page.ex index ac5a3c3..e988291 100644 --- a/lib/chargebee_elixir/hosted_page.ex +++ b/lib/chargebee_elixir/hosted_page.ex @@ -1,4 +1,7 @@ defmodule ChargebeeElixir.HostedPage do + @moduledoc """ + an interface for interacting with HostedPages + """ use ChargebeeElixir.Resource, "hosted_page" def checkout_new(params) do diff --git a/lib/chargebee_elixir/interface.ex b/lib/chargebee_elixir/interface.ex index 4984b80..1c43038 100644 --- a/lib/chargebee_elixir/interface.ex +++ b/lib/chargebee_elixir/interface.ex @@ -1,4 +1,13 @@ defmodule ChargebeeElixir.Interface do + @moduledoc """ + A low level http interface for interacting with Chargebee V2 HTTP Endpoints + + Configuration: + - Authorization loaded from `:chargebee_elixir, :api_key` + - Chargebee namespace scoping loaded from `:chargebee_elixir, :namespace` + - Alternative HTTP Clients configured from `:chargebee_elixir, :http_client` (i.e. in testing) + """ + alias Plug.Conn.Query def get(path) do get(path, %{}) diff --git a/lib/chargebee_elixir/invoice.ex b/lib/chargebee_elixir/invoice.ex index ea4f4ed..f0ba184 100644 --- a/lib/chargebee_elixir/invoice.ex +++ b/lib/chargebee_elixir/invoice.ex @@ -1,4 +1,7 @@ defmodule ChargebeeElixir.Invoice do + @moduledoc """ + an interface for interacting with Invoices + """ use ChargebeeElixir.Resource, "invoice" def close(id, params \\ %{}) do diff --git a/lib/chargebee_elixir/payment_intent.ex b/lib/chargebee_elixir/payment_intent.ex index b3a5e4e..1f5a8b1 100644 --- a/lib/chargebee_elixir/payment_intent.ex +++ b/lib/chargebee_elixir/payment_intent.ex @@ -1,3 +1,6 @@ defmodule ChargebeeElixir.PaymentIntent do + @moduledoc """ + an interface for interacting with PaymentIntents + """ use ChargebeeElixir.Resource, "payment_intent" end diff --git a/lib/chargebee_elixir/payment_source.ex b/lib/chargebee_elixir/payment_source.ex index 593aac8..d884735 100644 --- a/lib/chargebee_elixir/payment_source.ex +++ b/lib/chargebee_elixir/payment_source.ex @@ -1,3 +1,6 @@ defmodule ChargebeeElixir.PaymentSource do + @moduledoc """ + an interface for interacting with PaymentSources + """ use ChargebeeElixir.Resource, "payment_source" end diff --git a/lib/chargebee_elixir/plan.ex b/lib/chargebee_elixir/plan.ex index 79feb34..62b2f8a 100644 --- a/lib/chargebee_elixir/plan.ex +++ b/lib/chargebee_elixir/plan.ex @@ -1,3 +1,6 @@ defmodule ChargebeeElixir.Plan do + @moduledoc """ + an interface for interacting with Plans + """ use ChargebeeElixir.Resource, "plan" end diff --git a/lib/chargebee_elixir/portal_session.ex b/lib/chargebee_elixir/portal_session.ex index ab467e2..b9c1b98 100644 --- a/lib/chargebee_elixir/portal_session.ex +++ b/lib/chargebee_elixir/portal_session.ex @@ -1,3 +1,6 @@ defmodule ChargebeeElixir.PortalSession do + @moduledoc """ + an interface for interacting with PortalSessions + """ use ChargebeeElixir.Resource, "portal_session" end diff --git a/lib/chargebee_elixir/subscription.ex b/lib/chargebee_elixir/subscription.ex index 56d0b5f..54ed281 100644 --- a/lib/chargebee_elixir/subscription.ex +++ b/lib/chargebee_elixir/subscription.ex @@ -1,4 +1,7 @@ defmodule ChargebeeElixir.Subscription do + @moduledoc """ + an interface for interacting with Subscriptions + """ use ChargebeeElixir.Resource, "subscription" def create_for_customer(customer_id, params) do From eb72551d5d1f2b812111c5110d87c5cba0223d0a Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Thu, 9 Dec 2021 12:12:15 -0600 Subject: [PATCH 07/25] Add Mix Check --- mix.exs | 5 ++++- mix.lock | 37 ++++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/mix.exs b/mix.exs index cec0698..50ff51e 100644 --- a/mix.exs +++ b/mix.exs @@ -35,7 +35,10 @@ defmodule ChargebeeElixir.MixProject do {:httpoison, "~> 1.7"}, {:plug, "~>1.11"}, {:ex_doc, "~> 0.23", only: :dev, runtime: false}, - {:mox, "~>1.0", only: [:test]} + {:mox, "~>1.0", only: [:test]}, + {:credo, "~> 1.6", only: [:dev, :test], runtime: false}, + {:dialyxir, ">= 0.0.0", only: [:dev], runtime: false}, + {:ex_check, "~> 0.14.0", only: [:dev], runtime: false} ] end end diff --git a/mix.lock b/mix.lock index 5a778c1..dfccd36 100644 --- a/mix.lock +++ b/mix.lock @@ -1,22 +1,29 @@ %{ - "certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"}, - "ex_doc": {:hex, :ex_doc, "0.23.0", "a069bc9b0bf8efe323ecde8c0d62afc13d308b1fa3d228b65bca5cf8703a529d", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "f5e2c4702468b2fd11b10d39416ddadd2fcdd173ba2a0285ebd92c39827a5a16"}, - "hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"}, - "httpoison": {:hex, :httpoison, "1.7.0", "abba7d086233c2d8574726227b6c2c4f6e53c4deae7fe5f6de531162ce9929a0", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "975cc87c845a103d3d1ea1ccfd68a2700c211a434d8428b10c323dc95dc5b980"}, - "idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"}, + "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, + "certifi": {:hex, :certifi, "2.8.0", "d4fb0a6bb20b7c9c3643e22507e42f356ac090a1dcea9ab99e27e0376d695eba", [:rebar3], [], "hexpm", "6ac7efc1c6f8600b08d625292d4bbf584e14847ce1b6b5c44d983d273e1097ea"}, + "credo": {:hex, :credo, "1.6.1", "7dc76dcdb764a4316c1596804c48eada9fff44bd4b733a91ccbf0c0f368be61e", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "698607fb5993720c7e93d2d8e76f2175bba024de964e160e2f7151ef3ab82ac5"}, + "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.18", "e1b2be73eb08a49fb032a0208bf647380682374a725dfb5b9e510def8397f6f2", [:mix], [], "hexpm", "114a0e85ec3cf9e04b811009e73c206394ffecfcc313e0b346de0d557774ee97"}, + "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "ex_check": {:hex, :ex_check, "0.14.0", "d6fbe0bcc51cf38fea276f5bc2af0c9ae0a2bb059f602f8de88709421dae4f0e", [:mix], [], "hexpm", "8a602e98c66e6a4be3a639321f1f545292042f290f91fa942a285888c6868af0"}, + "ex_doc": {:hex, :ex_doc, "0.26.0", "1922164bac0b18b02f84d6f69cab1b93bc3e870e2ad18d5dacb50a9e06b542a3", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2775d66e494a9a48355db7867478ffd997864c61c65a47d31c4949459281c78d"}, + "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "hackney": {:hex, :hackney, "1.18.0", "c4443d960bb9fba6d01161d01cd81173089686717d9490e5d3606644c48d121f", [:rebar3], [{:certifi, "~>2.8.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "9afcda620704d720db8c6a3123e9848d09c87586dc1c10479c42627b905b5c5e"}, + "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.15.0", "98312c9f0d3730fde4049985a1105da5155bfe5c11e47bdc7406d88e01e4219b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "75ffa34ab1056b7e24844c90bfc62aaf6f3a37a15faa76b07bc5eba27e4a8b4a"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.15.2", "dc72dfe17eb240552857465cc00cce390960d9a0c055c4ccd38b70629227e97c", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fd23ae48d09b32eff49d4ced2b43c9f086d402ee4fd4fcb2d7fad97fa8823e75"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mime": {:hex, :mime, "1.5.0", "203ef35ef3389aae6d361918bf3f952fa17a09e8e43b5aa592b93eba05d0fb8d", [:mix], [], "hexpm", "55a94c0f552249fc1a3dd9cd2d3ab9de9d3c89b559c2bd01121f824834f24746"}, + "mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, - "mox": {:hex, :mox, "1.0.0", "4b3c7005173f47ff30641ba044eb0fe67287743eec9bd9545e37f3002b0a9f8b", [:mix], [], "hexpm", "201b0a20b7abdaaab083e9cf97884950f8a30a1350a1da403b3145e213c6f4df"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, - "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, - "plug": {:hex, :plug, "1.11.0", "f17217525597628298998bc3baed9f8ea1fa3f1160aa9871aee6df47a6e4d38e", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2d9c633f0499f9dc5c2fd069161af4e2e7756890b81adcbb2ceaa074e8308876"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.0", "1cb20793aa63a6c619dd18bb33d7a3aa94818e5fd39ad357051a67f26dfa2df6", [:mix], [], "hexpm", "a48b538ae8bf381ffac344520755f3007cc10bd8e90b240af98ea29b69683fc2"}, + "mox": {:hex, :mox, "1.0.1", "b651bf0113265cda0ba3a827fcb691f848b683c373b77e7d7439910a8d754d6e", [:mix], [], "hexpm", "35bc0dea5499d18db4ef7fe4360067a59b06c74376eb6ab3bd67e6295b133469"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.2.0", "b44d75e2a6542dcb6acf5d71c32c74ca88960421b6874777f79153bbbbd7dccc", [:mix], [], "hexpm", "52b2871a7515a5ac49b00f214e4165a40724cf99798d8e4a65e4fd64ebd002c1"}, + "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, + "plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"}, + "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, - "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.5.0", "8516502659002cec19e244ebd90d312183064be95025a319a6c7e89f4bccd65b", [:rebar3], [], "hexpm", "d48d002e15f5cc105a696cf2f1bbb3fc72b4b770a184d8420c8db20da2674b38"}, + "telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, } From 56f323d1d7ed3cb1999bc7e0b8399656b31950d2 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Thu, 9 Dec 2021 12:20:15 -0600 Subject: [PATCH 08/25] feature: Add ItemPrice --- lib/chargebee_elixir/item_price.ex | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 lib/chargebee_elixir/item_price.ex diff --git a/lib/chargebee_elixir/item_price.ex b/lib/chargebee_elixir/item_price.ex new file mode 100644 index 0000000..9255f97 --- /dev/null +++ b/lib/chargebee_elixir/item_price.ex @@ -0,0 +1,6 @@ +defmodule ChargebeeElixir.ItemPrice do + @moduledoc """ + an interface for interacting with Items + """ + use ChargebeeElixir.Resource, "item_price" +end From eaadd0179e68ea9e03c82518f55cc965b515c0af Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Wed, 12 Jan 2022 11:43:30 -0600 Subject: [PATCH 09/25] Update config imports --- config/config.exs | 2 +- config/dev.exs | 2 +- mix.exs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config/config.exs b/config/config.exs index c82c5f9..6570450 100644 --- a/config/config.exs +++ b/config/config.exs @@ -5,7 +5,7 @@ # is restricted to this project. # General application configuration -use Mix.Config +import Config # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. diff --git a/config/dev.exs b/config/dev.exs index d2d855e..becde76 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -1 +1 @@ -use Mix.Config +import Config diff --git a/mix.exs b/mix.exs index 50ff51e..c33b078 100644 --- a/mix.exs +++ b/mix.exs @@ -33,6 +33,7 @@ defmodule ChargebeeElixir.MixProject do [ {:jason, "~> 1.0"}, {:httpoison, "~> 1.7"}, + # ! Plug should not be required for this library {:plug, "~>1.11"}, {:ex_doc, "~> 0.23", only: :dev, runtime: false}, {:mox, "~>1.0", only: [:test]}, From de1317e9e2192767fe099cd0f88d64b6dd37784b Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Wed, 12 Jan 2022 11:43:42 -0600 Subject: [PATCH 10/25] =?UTF-8?q?=E2=9C=A8=20Add=20Coupon=20Resource?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/chargebee_elixir/coupon.ex | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/chargebee_elixir/coupon.ex diff --git a/lib/chargebee_elixir/coupon.ex b/lib/chargebee_elixir/coupon.ex new file mode 100644 index 0000000..4b960f0 --- /dev/null +++ b/lib/chargebee_elixir/coupon.ex @@ -0,0 +1,26 @@ +defmodule ChargebeeElixir.Coupon do + @moduledoc """ + an interface for interacting with Coupons + """ + use ChargebeeElixir.Resource, "coupon" + + def create_for_items(params) do + create(params, "create_for_items") + end + + def update_for_items(coupon_id, params) do + post_resource(coupon_id, "update_for_items", params) + end + + def delete(coupon_id) do + post_resource(coupon_id, "delete", %{}) + end + + def copy(coupon_id, params) do + post_resource(coupon_id, "copy", params) + end + + def unarchive(coupon_id) do + post_resource(coupon_id, "unarchive", %{}) + end +end From 497dbed0918255569b212eb37c4f983294f42cac Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Wed, 12 Jan 2022 13:09:42 -0600 Subject: [PATCH 11/25] Fix coupon paths --- lib/chargebee_elixir/coupon.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/chargebee_elixir/coupon.ex b/lib/chargebee_elixir/coupon.ex index 4b960f0..afb66f4 100644 --- a/lib/chargebee_elixir/coupon.ex +++ b/lib/chargebee_elixir/coupon.ex @@ -5,22 +5,22 @@ defmodule ChargebeeElixir.Coupon do use ChargebeeElixir.Resource, "coupon" def create_for_items(params) do - create(params, "create_for_items") + create(params, "/create_for_items") end def update_for_items(coupon_id, params) do - post_resource(coupon_id, "update_for_items", params) + post_resource(coupon_id, "/update_for_items", params) end def delete(coupon_id) do - post_resource(coupon_id, "delete", %{}) + post_resource(coupon_id, "/delete", %{}) end def copy(coupon_id, params) do - post_resource(coupon_id, "copy", params) + post_resource(coupon_id, "/copy", params) end def unarchive(coupon_id) do - post_resource(coupon_id, "unarchive", %{}) + post_resource(coupon_id, "/unarchive", %{}) end end From 07153010d88e53737e0a560e76b13f0c320e7068 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Wed, 12 Jan 2022 14:29:55 -0600 Subject: [PATCH 12/25] =?UTF-8?q?=F0=9F=94=A7=20rewrite=20query=20body=20s?= =?UTF-8?q?erialization=20to=20match=20Chargebee's=20expected=20behavior?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/chargebee_elixir/interface.ex | 67 +++++++------- test/chargebee_elixir/coupon_test.exs | 77 ++++++++++++++++ test/chargebee_elixir/hosted_page_test.exs | 4 +- test/chargebee_elixir/interface_test.exs | 90 ++++--------------- test/chargebee_elixir/portal_session_test.exs | 4 +- test/chargebee_elixir/subscription_test.exs | 8 +- 6 files changed, 133 insertions(+), 117 deletions(-) create mode 100644 test/chargebee_elixir/coupon_test.exs diff --git a/lib/chargebee_elixir/interface.ex b/lib/chargebee_elixir/interface.ex index 1c43038..3f8e7b7 100644 --- a/lib/chargebee_elixir/interface.ex +++ b/lib/chargebee_elixir/interface.ex @@ -28,7 +28,7 @@ defmodule ChargebeeElixir.Interface do def post(path, data) do body = data - |> transform_arrays_for_chargebee + |> serialize() |> Query.encode() http_client().post!( @@ -86,46 +86,39 @@ defmodule ChargebeeElixir.Interface do ] end - def transform_arrays_for_chargebee(map_data) when is_map(map_data) do - map_data - |> Enum.map(fn {k, v} -> - {k, transform_arrays_for_chargebee(v)} + # serialize/3 is a 1:1 adaptation of Chargebee-Ruby `Chargebee::Util.serialize/3` + # from https://github.com/chargebee/chargebee-ruby/blob/42f4aa5e58d5760d9f66d3aff02f8389faa6e68f/lib/chargebee/util.rb#L5 + def serialize(value, prefix \\ nil, index \\ nil) + + def serialize(value, prefix, index) when is_map(value) do + Enum.flat_map(value, fn + {k, v} when is_map(v) or is_list(v) -> + serialize(v, k) + + {k, v} -> + pt1 = if is_nil(prefix), do: to_string(k), else: "#{prefix}[#{k}]" + pt3 = if is_nil(index), do: "", else: "[#{index}]" + + key = pt1 <> pt3 + [{key, to_string(v)}] end) - |> Enum.into(%{}) + |> Map.new() end - def transform_arrays_for_chargebee(list_data) when is_list(list_data) do - transformed_list_data = - list_data - |> Enum.map(fn item -> transform_arrays_for_chargebee(item) end) - - transformed_list_data - |> Enum.map(fn item -> - case item do - map_item when is_map(map_item) -> - Map.keys(map_item) - - _ -> - raise ChargebeeElixir.IncorrectDataFormatError, - message: "Unsupported data: lists should contains objects only" - end - end) - |> List.flatten() - |> Enum.uniq() - |> Enum.map(fn key -> - { - key, - transformed_list_data - |> Enum.with_index() - |> Enum.map(fn {item, index} -> {index, item[key]} end) - |> Enum.filter(fn {_index, item} -> !is_nil(item) end) - |> Enum.into(%{}) - } - end) - |> Enum.into(%{}) + def serialize(value, prefix, _index) when is_list(value) do + value + |> Enum.with_index() + |> Enum.flat_map(fn {item, i} -> serialize(item, prefix, i) end) + |> Map.new() + end + + def serialize(_value, nil, nil) do + raise ArgumentError, "Only hash or arrays are allowed as value" end - def transform_arrays_for_chargebee(other_data) do - other_data + def serialize(value, prefix, index) do + key = "#{prefix}[#{index}]" + + [{key, value}] end end diff --git a/test/chargebee_elixir/coupon_test.exs b/test/chargebee_elixir/coupon_test.exs new file mode 100644 index 0000000..0f84b9c --- /dev/null +++ b/test/chargebee_elixir/coupon_test.exs @@ -0,0 +1,77 @@ +defmodule ChargebeeElixir.CouponTest do + use ExUnit.Case + doctest ChargebeeElixir.Coupon + alias ChargebeeElixir.Coupon + import Mox + + setup :verify_on_exit! + + def subject do + end + + describe "create_for_items" do + test "works with exmaple data from chargebee" do + expect( + ChargebeeElixir.HTTPoisonMock, + :post!, + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/coupons/create_for_items" + + assert URI.decode(data) == + "apply_on=each_specified_item&discount_percentage=10.0&discount_type=percentage&duration_type=forever&id=summer_offer&item_constraints[constraint][0]=all&item_constraints[item_type][0]=plan&name=Summer+Offer" + + %{ + status_code: 200, + body: '{"coupon": {"id": "summer_offer"}}' + } + end + ) + + assert ChargebeeElixir.Coupon.create_for_items(%{ + id: "summer_offer", + name: "Summer Offer", + discount_percentage: 10.0, + discount_type: "percentage", + duration_type: "forever", + apply_on: "each_specified_item", + item_constraints: [%{constraint: "all", item_type: "plan"}] + }) == %{"id" => "summer_offer"} + end + + test "works with list of item_price_ids" do + expect( + ChargebeeElixir.HTTPoisonMock, + :post!, + fn url, data, headers -> + assert url == + "https://test-namespace.chargebee.com/api/v2/coupons/create_for_items" + + assert URI.decode(data) == + "apply_on=each_specified_item&discount_percentage=10.0&discount_type=percentage&duration_type=forever&id=summer_offer&item_constraints[constraint][0]=specific&item_constraints[item_type][0]=plan&item_price_ids[0]=item_1&name=Summer+Offer" + + %{ + status_code: 200, + body: '{"coupon": {"id": "summer_offer"}}' + } + end + ) + + assert ChargebeeElixir.Coupon.create_for_items(%{ + id: "summer_offer", + name: "Summer Offer", + discount_percentage: 10.0, + discount_type: "percentage", + duration_type: "forever", + apply_on: "each_specified_item", + item_constraints: [ + %{ + constraint: "specific", + item_type: "plan", + item_price_ids: ["item_1"] + } + ] + }) == %{"id" => "summer_offer"} + end + end +end diff --git a/test/chargebee_elixir/hosted_page_test.exs b/test/chargebee_elixir/hosted_page_test.exs index f42c6e1..eb79ca3 100644 --- a/test/chargebee_elixir/hosted_page_test.exs +++ b/test/chargebee_elixir/hosted_page_test.exs @@ -12,7 +12,7 @@ defmodule ChargebeeElixir.HostedPageTest do fn url, data, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/hosted_pages/checkout_new" - assert data == + assert URI.decode(data) == "addons[id][0]=addon-a&addons[id][1]=addon-b&subscription[plan_id]=plan-a" assert headers == [ @@ -48,7 +48,7 @@ defmodule ChargebeeElixir.HostedPageTest do assert url == "https://test-namespace.chargebee.com/api/v2/hosted_pages/checkout_existing" - assert data == + assert URI.decode(data) == "addons[id][0]=addon-a&addons[id][1]=addon-b&customer[id]=cus-a&subscription[id]=subscription-a&subscription[plan_id]=plan-a" assert headers == [ diff --git a/test/chargebee_elixir/interface_test.exs b/test/chargebee_elixir/interface_test.exs index 149c982..37521e6 100644 --- a/test/chargebee_elixir/interface_test.exs +++ b/test/chargebee_elixir/interface_test.exs @@ -1,21 +1,16 @@ defmodule ChargebeeElixir.InterfaceTest do use ExUnit.Case - describe "transform_arrays_for_chargebee" do + describe "serialize" do test "simple list" do - assert ChargebeeElixir.Interface.transform_arrays_for_chargebee([ + assert ChargebeeElixir.Interface.serialize([ %{id: "object-a"}, %{id: "object-b"} - ]) == %{ - id: %{ - 0 => "object-a", - 1 => "object-b" - } - } + ]) == %{"id[0]" => "object-a", "id[1]" => "object-b"} end test "deep nesting, no lists" do - assert ChargebeeElixir.Interface.transform_arrays_for_chargebee(%{ + assert ChargebeeElixir.Interface.serialize(%{ addon: %{ id: "addon-a", nested: %{ @@ -24,20 +19,11 @@ defmodule ChargebeeElixir.InterfaceTest do } } } - }) == %{ - addon: %{ - id: "addon-a", - nested: %{ - object: %{ - id: "object-a" - } - } - } - } + }) == %{"addon[id]" => "addon-a", "object[id]" => "object-a"} end test "simple nesting" do - assert ChargebeeElixir.Interface.transform_arrays_for_chargebee(%{ + assert ChargebeeElixir.Interface.serialize(%{ addons: [ %{ id: "addon-a", @@ -49,43 +35,15 @@ defmodule ChargebeeElixir.InterfaceTest do } ] }) == %{ - addons: %{ - id: %{ - 0 => "addon-a", - 1 => "addon-b" - }, - price: %{ - 0 => 10 - }, - quantity: %{ - 1 => 2 - } - } + "addons[id][0]" => "addon-a", + "addons[id][1]" => "addon-b", + "addons[price][0]" => "10", + "addons[quantity][1]" => "2" } end - test "incorrect nesting" do - assert_raise ChargebeeElixir.IncorrectDataFormatError, - "Unsupported data: lists should contains objects only", - fn -> - ChargebeeElixir.Interface.transform_arrays_for_chargebee(%{ - addons: [ - %{ - id: "addon-a", - price: 10 - }, - %{ - id: "addon-b", - quantity: 2 - }, - "a" - ] - }) - end - end - test "complex nesting" do - assert ChargebeeElixir.Interface.transform_arrays_for_chargebee(%{ + assert ChargebeeElixir.Interface.serialize(%{ addons: [ %{ id: "addon-a", @@ -105,26 +63,12 @@ defmodule ChargebeeElixir.InterfaceTest do } ] }) == %{ - addons: %{ - id: %{ - 0 => "addon-a", - 1 => "addon-b" - }, - price: %{ - 0 => 10 - }, - quantity: %{ - 1 => 2 - }, - nested_objects: %{ - 0 => %{ - id: %{ - 0 => "object-a", - 1 => "object-b" - } - } - } - } + "addons[id][0]" => "addon-a", + "addons[id][1]" => "addon-b", + "addons[price][0]" => "10", + "addons[quantity][1]" => "2", + "nested_objects[id][0]" => "object-a", + "nested_objects[id][1]" => "object-b" } end end diff --git a/test/chargebee_elixir/portal_session_test.exs b/test/chargebee_elixir/portal_session_test.exs index ee8b948..4e31944 100644 --- a/test/chargebee_elixir/portal_session_test.exs +++ b/test/chargebee_elixir/portal_session_test.exs @@ -60,7 +60,9 @@ defmodule ChargebeeElixir.PortalSessionTest do :post!, fn url, data, headers -> assert url == "https://test-namespace.chargebee.com/api/v2/portal_sessions" - assert data == "customer[id]=cus_1234&redirect_url=https%3A%2F%2Fredirect.com" + + assert URI.decode(data) == + "customer[id]=cus_1234&redirect_url=https://redirect.com" assert headers == [ {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, diff --git a/test/chargebee_elixir/subscription_test.exs b/test/chargebee_elixir/subscription_test.exs index 439e36e..0b96c90 100644 --- a/test/chargebee_elixir/subscription_test.exs +++ b/test/chargebee_elixir/subscription_test.exs @@ -26,7 +26,7 @@ defmodule ChargebeeElixir.SubscriptionTest do assert url == "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" - assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" + assert URI.decode(data) == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" assert headers == [ {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, @@ -52,7 +52,7 @@ defmodule ChargebeeElixir.SubscriptionTest do assert url == "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" - assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" + assert URI.decode(data) == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" assert headers == [ {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, @@ -78,7 +78,7 @@ defmodule ChargebeeElixir.SubscriptionTest do assert url == "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" - assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" + assert URI.decode(data) == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" assert headers == [ {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, @@ -105,7 +105,7 @@ defmodule ChargebeeElixir.SubscriptionTest do assert url == "https://test-namespace.chargebee.com/api/v2/customers/cus_1/subscriptions" - assert data == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" + assert URI.decode(data) == "addons[id][0]=addon-a&addons[id][1]=addon-b&plan_id=plan-a" assert headers == [ {"Authorization", "Basic dGVzdF9jaGFyZ2VlYmVlX2FwaV9rZXk6"}, From a0101a01d6a3543f86a04d0ba2ed097352d21332 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Wed, 12 Jan 2022 15:49:04 -0600 Subject: [PATCH 13/25] =?UTF-8?q?=E2=9C=A8=20=5Fcorrectly=5F=20compute=20n?= =?UTF-8?q?ested=20parameters=20in=20Chargebee's=20preferred=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/test.exs | 2 +- lib/chargebee_elixir/interface.ex | 3 ++- test/chargebee_elixir/coupon_test.exs | 10 +++++----- test/chargebee_elixir/interface_test.exs | 22 +++++++++++++++++++--- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/config/test.exs b/config/test.exs index a13f4a0..b632b79 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :chargebee_elixir, namespace: "test-namespace", diff --git a/lib/chargebee_elixir/interface.ex b/lib/chargebee_elixir/interface.ex index 3f8e7b7..aadd6ca 100644 --- a/lib/chargebee_elixir/interface.ex +++ b/lib/chargebee_elixir/interface.ex @@ -93,7 +93,8 @@ defmodule ChargebeeElixir.Interface do def serialize(value, prefix, index) when is_map(value) do Enum.flat_map(value, fn {k, v} when is_map(v) or is_list(v) -> - serialize(v, k) + pre = if is_nil(prefix), do: to_string(k), else: "#{prefix}[#{k}]" + serialize(v, pre) {k, v} -> pt1 = if is_nil(prefix), do: to_string(k), else: "#{prefix}[#{k}]" diff --git a/test/chargebee_elixir/coupon_test.exs b/test/chargebee_elixir/coupon_test.exs index 0f84b9c..7b9b7c0 100644 --- a/test/chargebee_elixir/coupon_test.exs +++ b/test/chargebee_elixir/coupon_test.exs @@ -14,7 +14,7 @@ defmodule ChargebeeElixir.CouponTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn url, data, headers -> + fn url, data, _headers -> assert url == "https://test-namespace.chargebee.com/api/v2/coupons/create_for_items" @@ -28,7 +28,7 @@ defmodule ChargebeeElixir.CouponTest do end ) - assert ChargebeeElixir.Coupon.create_for_items(%{ + assert Coupon.create_for_items(%{ id: "summer_offer", name: "Summer Offer", discount_percentage: 10.0, @@ -43,12 +43,12 @@ defmodule ChargebeeElixir.CouponTest do expect( ChargebeeElixir.HTTPoisonMock, :post!, - fn url, data, headers -> + fn url, data, _headers -> assert url == "https://test-namespace.chargebee.com/api/v2/coupons/create_for_items" assert URI.decode(data) == - "apply_on=each_specified_item&discount_percentage=10.0&discount_type=percentage&duration_type=forever&id=summer_offer&item_constraints[constraint][0]=specific&item_constraints[item_type][0]=plan&item_price_ids[0]=item_1&name=Summer+Offer" + "apply_on=each_specified_item&discount_percentage=10.0&discount_type=percentage&duration_type=forever&id=summer_offer&item_constraints[constraint][0]=specific&item_constraints[item_price_ids][0]=item_1&item_constraints[item_type][0]=plan&name=Summer+Offer" %{ status_code: 200, @@ -57,7 +57,7 @@ defmodule ChargebeeElixir.CouponTest do end ) - assert ChargebeeElixir.Coupon.create_for_items(%{ + assert Coupon.create_for_items(%{ id: "summer_offer", name: "Summer Offer", discount_percentage: 10.0, diff --git a/test/chargebee_elixir/interface_test.exs b/test/chargebee_elixir/interface_test.exs index 37521e6..80df623 100644 --- a/test/chargebee_elixir/interface_test.exs +++ b/test/chargebee_elixir/interface_test.exs @@ -19,7 +19,7 @@ defmodule ChargebeeElixir.InterfaceTest do } } } - }) == %{"addon[id]" => "addon-a", "object[id]" => "object-a"} + }) == %{"addon[id]" => "addon-a", "addon[nested][object][id]" => "object-a"} end test "simple nesting" do @@ -67,8 +67,24 @@ defmodule ChargebeeElixir.InterfaceTest do "addons[id][1]" => "addon-b", "addons[price][0]" => "10", "addons[quantity][1]" => "2", - "nested_objects[id][0]" => "object-a", - "nested_objects[id][1]" => "object-b" + "addons[nested_objects][id][0]" => "object-a", + "addons[nested_objects][id][1]" => "object-b" + } + end + + test "failing complex nesting case" do + assert ChargebeeElixir.Interface.serialize(%{ + item_constraints: [ + %{ + constraint: "specific", + item_type: "plan", + item_price_ids: ["item_a"] + } + ] + }) == %{ + "item_constraints[constraint][0]" => "specific", + "item_constraints[item_type][0]" => "plan", + "item_constraints[item_price_ids][0]" => "item_a" } end end From ededae3a99f93baf120aaa7132e0338f68b156ba Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Fri, 14 Jan 2022 13:15:35 -0600 Subject: [PATCH 14/25] Fix POST body serialization of nested arrays --- lib/chargebee_elixir/interface.ex | 24 +++-- test/chargebee_elixir/coupon_test.exs | 2 +- test/chargebee_elixir/interface_test.exs | 132 +++++++++++++++++------ 3 files changed, 118 insertions(+), 40 deletions(-) diff --git a/lib/chargebee_elixir/interface.ex b/lib/chargebee_elixir/interface.ex index aadd6ca..774c1a2 100644 --- a/lib/chargebee_elixir/interface.ex +++ b/lib/chargebee_elixir/interface.ex @@ -7,7 +7,6 @@ defmodule ChargebeeElixir.Interface do - Chargebee namespace scoping loaded from `:chargebee_elixir, :namespace` - Alternative HTTP Clients configured from `:chargebee_elixir, :http_client` (i.e. in testing) """ - alias Plug.Conn.Query def get(path) do get(path, %{}) @@ -29,7 +28,7 @@ defmodule ChargebeeElixir.Interface do body = data |> serialize() - |> Query.encode() + |> URI.encode_query() http_client().post!( fullpath(path), @@ -94,25 +93,36 @@ defmodule ChargebeeElixir.Interface do Enum.flat_map(value, fn {k, v} when is_map(v) or is_list(v) -> pre = if is_nil(prefix), do: to_string(k), else: "#{prefix}[#{k}]" - serialize(v, pre) + # fix = if is_nil(index), do: "", else: "[#{index}]" + + serialize(v, pre, index) {k, v} -> - pt1 = if is_nil(prefix), do: to_string(k), else: "#{prefix}[#{k}]" - pt3 = if is_nil(index), do: "", else: "[#{index}]" + pre = if is_nil(prefix), do: to_string(k), else: "#{prefix}[#{k}]" + fix = if is_nil(index), do: "", else: "[#{index}]" - key = pt1 <> pt3 + key = pre <> fix [{key, to_string(v)}] end) |> Map.new() end - def serialize(value, prefix, _index) when is_list(value) do + def serialize(value, prefix, nil) when is_list(value) do value |> Enum.with_index() |> Enum.flat_map(fn {item, i} -> serialize(item, prefix, i) end) |> Map.new() end + # Apparently Second Degree nested arrays are just encoded as json values + def serialize(value, prefix, index) when is_list(value) do + value = Jason.encode!(value) + + key = "#{prefix}[#{index}]" + + [{key, value}] + end + def serialize(_value, nil, nil) do raise ArgumentError, "Only hash or arrays are allowed as value" end diff --git a/test/chargebee_elixir/coupon_test.exs b/test/chargebee_elixir/coupon_test.exs index 7b9b7c0..c466cbc 100644 --- a/test/chargebee_elixir/coupon_test.exs +++ b/test/chargebee_elixir/coupon_test.exs @@ -48,7 +48,7 @@ defmodule ChargebeeElixir.CouponTest do "https://test-namespace.chargebee.com/api/v2/coupons/create_for_items" assert URI.decode(data) == - "apply_on=each_specified_item&discount_percentage=10.0&discount_type=percentage&duration_type=forever&id=summer_offer&item_constraints[constraint][0]=specific&item_constraints[item_price_ids][0]=item_1&item_constraints[item_type][0]=plan&name=Summer+Offer" + "apply_on=each_specified_item&discount_percentage=10.0&discount_type=percentage&duration_type=forever&id=summer_offer&item_constraints[constraint][0]=specific&item_constraints[item_price_ids][0]=[\"item_1\"]&item_constraints[item_type][0]=plan&name=Summer+Offer" %{ status_code: 200, diff --git a/test/chargebee_elixir/interface_test.exs b/test/chargebee_elixir/interface_test.exs index 80df623..3544bcb 100644 --- a/test/chargebee_elixir/interface_test.exs +++ b/test/chargebee_elixir/interface_test.exs @@ -2,6 +2,83 @@ defmodule ChargebeeElixir.InterfaceTest do use ExUnit.Case describe "serialize" do + test "chargebee example" do + # from chargebee-ruby test case + input = %{ + :id => "sub_KyVq7DNSNM7CSD", + :plan_id => "free", + :addons => [%{:id => "monitor", :quantity => 2}, %{:id => "ssl"}], + :addon_ids => ["addon_one", "addon_two"], + :card => %{ + :first_name => "Rajaraman", + :last_name => "Santhanam", + :number => "4111111111111111", + :expiry_month => "1", + :expiry_year => "2024", + :cvv => "007" + } + } + + output = %{ + "id" => "sub_KyVq7DNSNM7CSD", + "plan_id" => "free", + "addons[id][0]" => "monitor", + "addons[quantity][0]" => "2", + "addons[id][1]" => "ssl", + "addon_ids[0]" => "addon_one", + "addon_ids[1]" => "addon_two", + "card[first_name]" => "Rajaraman", + "card[last_name]" => "Santhanam", + "card[number]" => "4111111111111111", + "card[expiry_month]" => "1", + "card[expiry_year]" => "2024", + "card[cvv]" => "007" + } + + assert ChargebeeElixir.Interface.serialize(input) == output + end + + test "chargebeee example 2" do + # From the chargebee-go Test case + input = %{ + plan_id: "cbdemo_grow", + customer: %{ + email: "john@user.com", + first_name: "John", + last_name: "Doe", + locale: "frCA", + phone: "+19499999999", + auto_collection: "on" + }, + addons: [ + %{ + id: "cbdemo_conciergesupport" + }, + %{ + id: "cbdemo_additionaluser", + quantity: 2 + } + ], + coupon_ids: ["cbdemo_earlybird"] + } + + output = %{ + "coupon_ids[0]" => "cbdemo_earlybird", + "customer[phone]" => "+19499999999", + "plan_id" => "cbdemo_grow", + "customer[last_name]" => "Doe", + "customer[locale]" => "frCA", + "addons[id][0]" => "cbdemo_conciergesupport", + "addons[id][1]" => "cbdemo_additionaluser", + "addons[quantity][1]" => "2", + "customer[email]" => "john@user.com", + "customer[auto_collection]" => "on", + "customer[first_name]" => "John" + } + + assert ChargebeeElixir.Interface.serialize(input) == output + end + test "simple list" do assert ChargebeeElixir.Interface.serialize([ %{id: "object-a"}, @@ -42,37 +119,7 @@ defmodule ChargebeeElixir.InterfaceTest do } end - test "complex nesting" do - assert ChargebeeElixir.Interface.serialize(%{ - addons: [ - %{ - id: "addon-a", - price: 10, - nested_objects: [ - %{ - id: "object-a" - }, - %{ - id: "object-b" - } - ] - }, - %{ - id: "addon-b", - quantity: 2 - } - ] - }) == %{ - "addons[id][0]" => "addon-a", - "addons[id][1]" => "addon-b", - "addons[price][0]" => "10", - "addons[quantity][1]" => "2", - "addons[nested_objects][id][0]" => "object-a", - "addons[nested_objects][id][1]" => "object-b" - } - end - - test "failing complex nesting case" do + test "Example of complex nested list field" do assert ChargebeeElixir.Interface.serialize(%{ item_constraints: [ %{ @@ -84,8 +131,29 @@ defmodule ChargebeeElixir.InterfaceTest do }) == %{ "item_constraints[constraint][0]" => "specific", "item_constraints[item_type][0]" => "plan", - "item_constraints[item_price_ids][0]" => "item_a" + "item_constraints[item_price_ids][0]" => "[\"item_a\"]" } end + + test "when query encoded" do + input = %{ + item_constraints: [ + %{ + constraint: "specific", + item_type: "plan", + item_price_ids: "[\"item_a\"]" + } + ] + } + + as_encoded_params = + ~s + + assert as_encoded_params == + input + |> ChargebeeElixir.Interface.serialize() + |> URI.encode_query() + |> URI.decode() + end end end From 695c850e37a7ccad78b8201c50f0dd745a1fffa1 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Fri, 14 Jan 2022 13:54:07 -0600 Subject: [PATCH 15/25] Remove unused dependencies --- mix.exs | 2 -- mix.lock | 4 ---- 2 files changed, 6 deletions(-) diff --git a/mix.exs b/mix.exs index c33b078..be2a18b 100644 --- a/mix.exs +++ b/mix.exs @@ -33,8 +33,6 @@ defmodule ChargebeeElixir.MixProject do [ {:jason, "~> 1.0"}, {:httpoison, "~> 1.7"}, - # ! Plug should not be required for this library - {:plug, "~>1.11"}, {:ex_doc, "~> 0.23", only: :dev, runtime: false}, {:mox, "~>1.0", only: [:test]}, {:credo, "~> 1.6", only: [:dev, :test], runtime: false}, diff --git a/mix.lock b/mix.lock index dfccd36..b9f69ca 100644 --- a/mix.lock +++ b/mix.lock @@ -16,14 +16,10 @@ "makeup_elixir": {:hex, :makeup_elixir, "0.15.2", "dc72dfe17eb240552857465cc00cce390960d9a0c055c4ccd38b70629227e97c", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fd23ae48d09b32eff49d4ced2b43c9f086d402ee4fd4fcb2d7fad97fa8823e75"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mox": {:hex, :mox, "1.0.1", "b651bf0113265cda0ba3a827fcb691f848b683c373b77e7d7439910a8d754d6e", [:mix], [], "hexpm", "35bc0dea5499d18db4ef7fe4360067a59b06c74376eb6ab3bd67e6295b133469"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.0", "b44d75e2a6542dcb6acf5d71c32c74ca88960421b6874777f79153bbbbd7dccc", [:mix], [], "hexpm", "52b2871a7515a5ac49b00f214e4165a40724cf99798d8e4a65e4fd64ebd002c1"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, - "plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, - "telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, } From 74f6e9d8864e17aca4bdbf3f060df5fe179bb69d Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Mon, 17 Jan 2022 07:45:14 -0600 Subject: [PATCH 16/25] Add Coupon Codes and Coupon Sets resources --- lib/chargebee_elixir/coupon_code.ex | 14 ++++++++++++++ lib/chargebee_elixir/coupon_set.ex | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 lib/chargebee_elixir/coupon_code.ex create mode 100644 lib/chargebee_elixir/coupon_set.ex diff --git a/lib/chargebee_elixir/coupon_code.ex b/lib/chargebee_elixir/coupon_code.ex new file mode 100644 index 0000000..3494908 --- /dev/null +++ b/lib/chargebee_elixir/coupon_code.ex @@ -0,0 +1,14 @@ +defmodule ChargebeeElixir.CouponCode do + @moduledoc """ + an interface for interacting with Coupon Codes + + Supports: + - List + - Retrieve + """ + use ChargebeeElixir.Resource, "coupon_code" + + def archive(coupon_code) do + post_resource(coupon_code, "/archive", %{}) + end +end diff --git a/lib/chargebee_elixir/coupon_set.ex b/lib/chargebee_elixir/coupon_set.ex new file mode 100644 index 0000000..08cf49c --- /dev/null +++ b/lib/chargebee_elixir/coupon_set.ex @@ -0,0 +1,24 @@ +defmodule ChargebeeElixir.CouponSet do + @moduledoc """ + an interface for interacting with Coupon Sets + + Supports + - List + - Retrieve + - Create + - Update + """ + use ChargebeeElixir.Resource, "coupon_set" + + def add_coupon_codes(coupon_id, params) do + post_resource(coupon_id, "/add_coupon_codes", params) + end + + def delete(coupon_id) do + post_resource(coupon_id, "/delete", %{}) + end + + def delete_unused_coupon_codes(coupon_id) do + post_resource(coupon_id, "/delete_unused_coupon_codes", %{}) + end +end From e31c8ed4a598eb91956841f610a56cd9a680d176 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Tue, 29 Mar 2022 11:25:49 -0500 Subject: [PATCH 17/25] Add ItemFamily Resource --- lib/chargebee_elixir/interface.ex | 6 +++--- lib/chargebee_elixir/item_family.ex | 6 ++++++ lib/chargebee_elixir/resource.ex | 3 ++- mix.exs | 1 + mix.lock | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 lib/chargebee_elixir/item_family.ex diff --git a/lib/chargebee_elixir/interface.ex b/lib/chargebee_elixir/interface.ex index 774c1a2..54d4ebe 100644 --- a/lib/chargebee_elixir/interface.ex +++ b/lib/chargebee_elixir/interface.ex @@ -3,9 +3,9 @@ defmodule ChargebeeElixir.Interface do A low level http interface for interacting with Chargebee V2 HTTP Endpoints Configuration: - - Authorization loaded from `:chargebee_elixir, :api_key` - - Chargebee namespace scoping loaded from `:chargebee_elixir, :namespace` - - Alternative HTTP Clients configured from `:chargebee_elixir, :http_client` (i.e. in testing) + - Authorization loaded from Application env `:chargebee_elixir, :api_key` + - Chargebee namespace scoping loaded from Application env `:chargebee_elixir, :namespace` + - Alternative HTTP Clients configured from Application env `:chargebee_elixir, :http_client` (i.e. in testing) """ def get(path) do diff --git a/lib/chargebee_elixir/item_family.ex b/lib/chargebee_elixir/item_family.ex new file mode 100644 index 0000000..b8530fd --- /dev/null +++ b/lib/chargebee_elixir/item_family.ex @@ -0,0 +1,6 @@ +defmodule ChargebeeElixir.ItemFamily do + @moduledoc """ + an interface for interacting with Items + """ + use ChargebeeElixir.Resource, "item_family" +end diff --git a/lib/chargebee_elixir/resource.ex b/lib/chargebee_elixir/resource.ex index 88f1465..ac06c39 100644 --- a/lib/chargebee_elixir/resource.ex +++ b/lib/chargebee_elixir/resource.ex @@ -5,6 +5,7 @@ defmodule ChargebeeElixir.Resource do alias ChargebeeElixir.Interface @resource unquote(resource) + @resource_plural Inflex.pluralize(@resource) def retrieve(id) do id |> resource_path() |> Interface.get() |> Map.get(@resource) @@ -56,7 +57,7 @@ defmodule ChargebeeElixir.Resource do end def resource_base_path do - "/#{@resource}s" + "/#{@resource_plural}" end def resource_path(id) do diff --git a/mix.exs b/mix.exs index be2a18b..8ee3c0f 100644 --- a/mix.exs +++ b/mix.exs @@ -31,6 +31,7 @@ defmodule ChargebeeElixir.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ + {:inflex, "~> 2.0.0"}, {:jason, "~> 1.0"}, {:httpoison, "~> 1.7"}, {:ex_doc, "~> 0.23", only: :dev, runtime: false}, diff --git a/mix.lock b/mix.lock index b9f69ca..1b8e416 100644 --- a/mix.lock +++ b/mix.lock @@ -11,6 +11,7 @@ "hackney": {:hex, :hackney, "1.18.0", "c4443d960bb9fba6d01161d01cd81173089686717d9490e5d3606644c48d121f", [:rebar3], [{:certifi, "~>2.8.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "9afcda620704d720db8c6a3123e9848d09c87586dc1c10479c42627b905b5c5e"}, "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "inflex": {:hex, :inflex, "2.0.0", "db69d542b8fdb23ac667f9bc0c2395a3983fa2da6ae2efa7ab5dc541928f7a75", [:mix], [], "hexpm", "c018852409bd48b03ad96ed53594186bc074bdd1519043a0ad1fa5697aac4399"}, "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, "makeup_elixir": {:hex, :makeup_elixir, "0.15.2", "dc72dfe17eb240552857465cc00cce390960d9a0c055c4ccd38b70629227e97c", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fd23ae48d09b32eff49d4ced2b43c9f086d402ee4fd4fcb2d7fad97fa8823e75"}, From 76bd60fd98f431a0d3736ff826344faad9e0c6a2 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Tue, 29 Mar 2022 11:29:29 -0500 Subject: [PATCH 18/25] interface.ex - Drop fields with nil value when serializing --- lib/chargebee_elixir/interface.ex | 3 +++ test/chargebee_elixir/interface_test.exs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/chargebee_elixir/interface.ex b/lib/chargebee_elixir/interface.ex index 54d4ebe..2c83689 100644 --- a/lib/chargebee_elixir/interface.ex +++ b/lib/chargebee_elixir/interface.ex @@ -91,6 +91,9 @@ defmodule ChargebeeElixir.Interface do def serialize(value, prefix, index) when is_map(value) do Enum.flat_map(value, fn + {_k, nil} -> + [] + {k, v} when is_map(v) or is_list(v) -> pre = if is_nil(prefix), do: to_string(k), else: "#{prefix}[#{k}]" # fix = if is_nil(index), do: "", else: "[#{index}]" diff --git a/test/chargebee_elixir/interface_test.exs b/test/chargebee_elixir/interface_test.exs index 3544bcb..a6aa15f 100644 --- a/test/chargebee_elixir/interface_test.exs +++ b/test/chargebee_elixir/interface_test.exs @@ -155,5 +155,21 @@ defmodule ChargebeeElixir.InterfaceTest do |> URI.encode_query() |> URI.decode() end + + test "drops nil fields" do + # from chargebee-ruby test case + input = %{ + :id => "sub_KyVq7DNSNM7CSD", + :plan_id => "free", + :item_family_id => nil + } + + output = %{ + "id" => "sub_KyVq7DNSNM7CSD", + "plan_id" => "free" + } + + assert ChargebeeElixir.Interface.serialize(input) == output + end end end From b498a8ba198f8cb1d33db36aa9ee12eb455d4dac Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Tue, 29 Mar 2022 11:30:52 -0500 Subject: [PATCH 19/25] mix.exs - remove minor version constraint on inflex --- mix.exs | 2 +- mix.lock | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mix.exs b/mix.exs index 8ee3c0f..3178a63 100644 --- a/mix.exs +++ b/mix.exs @@ -31,7 +31,7 @@ defmodule ChargebeeElixir.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:inflex, "~> 2.0.0"}, + {:inflex, "~> 2.0"}, {:jason, "~> 1.0"}, {:httpoison, "~> 1.7"}, {:ex_doc, "~> 0.23", only: :dev, runtime: false}, diff --git a/mix.lock b/mix.lock index 1b8e416..6de337a 100644 --- a/mix.lock +++ b/mix.lock @@ -1,25 +1,25 @@ %{ "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, - "certifi": {:hex, :certifi, "2.8.0", "d4fb0a6bb20b7c9c3643e22507e42f356ac090a1dcea9ab99e27e0376d695eba", [:rebar3], [], "hexpm", "6ac7efc1c6f8600b08d625292d4bbf584e14847ce1b6b5c44d983d273e1097ea"}, - "credo": {:hex, :credo, "1.6.1", "7dc76dcdb764a4316c1596804c48eada9fff44bd4b733a91ccbf0c0f368be61e", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "698607fb5993720c7e93d2d8e76f2175bba024de964e160e2f7151ef3ab82ac5"}, + "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, + "credo": {:hex, :credo, "1.6.4", "ddd474afb6e8c240313f3a7b0d025cc3213f0d171879429bf8535d7021d9ad78", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "c28f910b61e1ff829bffa056ef7293a8db50e87f2c57a9b5c3f57eee124536b7"}, "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.18", "e1b2be73eb08a49fb032a0208bf647380682374a725dfb5b9e510def8397f6f2", [:mix], [], "hexpm", "114a0e85ec3cf9e04b811009e73c206394ffecfcc313e0b346de0d557774ee97"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.25", "2024618731c55ebfcc5439d756852ec4e85978a39d0d58593763924d9a15916f", [:mix], [], "hexpm", "56749c5e1c59447f7b7a23ddb235e4b3defe276afc220a6227237f3efe83f51e"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "ex_check": {:hex, :ex_check, "0.14.0", "d6fbe0bcc51cf38fea276f5bc2af0c9ae0a2bb059f602f8de88709421dae4f0e", [:mix], [], "hexpm", "8a602e98c66e6a4be3a639321f1f545292042f290f91fa942a285888c6868af0"}, - "ex_doc": {:hex, :ex_doc, "0.26.0", "1922164bac0b18b02f84d6f69cab1b93bc3e870e2ad18d5dacb50a9e06b542a3", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2775d66e494a9a48355db7867478ffd997864c61c65a47d31c4949459281c78d"}, + "ex_doc": {:hex, :ex_doc, "0.28.3", "6eea2f69995f5fba94cd6dd398df369fe4e777a47cd887714a0976930615c9e6", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "05387a6a2655b5f9820f3f627450ed20b4325c25977b2ee69bed90af6688e718"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "hackney": {:hex, :hackney, "1.18.0", "c4443d960bb9fba6d01161d01cd81173089686717d9490e5d3606644c48d121f", [:rebar3], [{:certifi, "~>2.8.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "9afcda620704d720db8c6a3123e9848d09c87586dc1c10479c42627b905b5c5e"}, + "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, - "inflex": {:hex, :inflex, "2.0.0", "db69d542b8fdb23ac667f9bc0c2395a3983fa2da6ae2efa7ab5dc541928f7a75", [:mix], [], "hexpm", "c018852409bd48b03ad96ed53594186bc074bdd1519043a0ad1fa5697aac4399"}, - "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, - "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.15.2", "dc72dfe17eb240552857465cc00cce390960d9a0c055c4ccd38b70629227e97c", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fd23ae48d09b32eff49d4ced2b43c9f086d402ee4fd4fcb2d7fad97fa8823e75"}, + "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, + "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, + "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mox": {:hex, :mox, "1.0.1", "b651bf0113265cda0ba3a827fcb691f848b683c373b77e7d7439910a8d754d6e", [:mix], [], "hexpm", "35bc0dea5499d18db4ef7fe4360067a59b06c74376eb6ab3bd67e6295b133469"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.2.0", "b44d75e2a6542dcb6acf5d71c32c74ca88960421b6874777f79153bbbbd7dccc", [:mix], [], "hexpm", "52b2871a7515a5ac49b00f214e4165a40724cf99798d8e4a65e4fd64ebd002c1"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, From 737d9255315527739eb91e887109830a6617577b Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Wed, 30 Mar 2022 11:33:43 -0500 Subject: [PATCH 20/25] Fix: ensure metadata is always json-encoded if present --- lib/chargebee_elixir/interface.ex | 3 +++ test/chargebee_elixir/interface_test.exs | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/chargebee_elixir/interface.ex b/lib/chargebee_elixir/interface.ex index 2c83689..82ef5be 100644 --- a/lib/chargebee_elixir/interface.ex +++ b/lib/chargebee_elixir/interface.ex @@ -94,6 +94,9 @@ defmodule ChargebeeElixir.Interface do {_k, nil} -> [] + {k, v} when k in ["metadata", :metadata] and is_map(v) -> + [{to_string(k), Jason.encode!(v)}] + {k, v} when is_map(v) or is_list(v) -> pre = if is_nil(prefix), do: to_string(k), else: "#{prefix}[#{k}]" # fix = if is_nil(index), do: "", else: "[#{index}]" diff --git a/test/chargebee_elixir/interface_test.exs b/test/chargebee_elixir/interface_test.exs index a6aa15f..f7b246e 100644 --- a/test/chargebee_elixir/interface_test.exs +++ b/test/chargebee_elixir/interface_test.exs @@ -171,5 +171,13 @@ defmodule ChargebeeElixir.InterfaceTest do assert ChargebeeElixir.Interface.serialize(input) == output end + + test "serializes metadata as encoded json" do + input = %{metadata: %{some: "value"}} + + output = %{"metadata" => ~S({"some":"value"})} + + assert ChargebeeElixir.Interface.serialize(input) == output + end end end From c3547fce78ab30a79382006e811129a8909d10f0 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Thu, 31 Mar 2022 14:16:50 -0500 Subject: [PATCH 21/25] :bug: resouce.ex - escape resource ids in uris --- lib/chargebee_elixir/resource.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/chargebee_elixir/resource.ex b/lib/chargebee_elixir/resource.ex index ac06c39..1e915ab 100644 --- a/lib/chargebee_elixir/resource.ex +++ b/lib/chargebee_elixir/resource.ex @@ -61,7 +61,7 @@ defmodule ChargebeeElixir.Resource do end def resource_path(id) do - "#{resource_base_path()}/#{id}" + "#{resource_base_path()}/#{URI.encode(id)}" end end end From 546d716ebd52dd09f3793cad43272261100ddb5e Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Wed, 20 Apr 2022 17:33:07 +0200 Subject: [PATCH 22/25] Add gift resource --- lib/chargebee_elixir/gift.ex | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 lib/chargebee_elixir/gift.ex diff --git a/lib/chargebee_elixir/gift.ex b/lib/chargebee_elixir/gift.ex new file mode 100644 index 0000000..8f1a66f --- /dev/null +++ b/lib/chargebee_elixir/gift.ex @@ -0,0 +1,15 @@ +defmodule ChargebeeElixir.Gift do + use ChargebeeElixir.Resource, "gift" + + def create_for_items(params) do + create(params, "/create_for_items") + end + + def cancel(coupon_id) do + post_resource(coupon_id, "/cancel", %{}) + end + + def claim(coupon_id) do + post_resource(coupon_id, "/claim", %{}) + end +end From f73a21be6ea67adbaedcf6c7a20b23ef96519c69 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Wed, 20 Apr 2022 17:37:02 +0200 Subject: [PATCH 23/25] =?UTF-8?q?=F0=9F=93=9D=20Udpate=20Readme.=20I=20gue?= =?UTF-8?q?ss=20we're=20v0.2.0=20now?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 18 +++++++++++------- mix.exs | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 802d2f2..59001aa 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Elixir implementation of [Chargebee API](https://apidocs.chargebee.com/docs/api). -## v0.1.1 +## v0.2.0 This is a work in progress: right now, we only implement those methods: - list - retrieve @@ -11,17 +11,21 @@ This is a work in progress: right now, we only implement those methods: on those resources: - addon +- coupon_code +- coupon_set - customer +- event +- gift - hosted_page - - also checkout_new - - also checkout_existing -- subscription - - also create_for_customer +- invoice +- item_family +- item_price +- item +- payment_intent +- payment_source - plan - portal_session - subscription -- invoice - - also close ## Installation The package can be installed by adding `chargebee_elixir` to your list of dependencies in `mix.exs`: diff --git a/mix.exs b/mix.exs index 3178a63..e9c763e 100644 --- a/mix.exs +++ b/mix.exs @@ -14,7 +14,7 @@ defmodule ChargebeeElixir.MixProject do }, source_url: "https://github.com/NicolasMarlier/chargebee-elixir", homepage_url: "https://github.com/NicolasMarlier/chargebee-elixir", - version: "0.1.3", + version: "0.2.0", elixir: "~> 1.11", start_permanent: Mix.env() == :prod, deps: deps() From 18d23001698b7f8eedc30aa0ec322d758854d209 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Wed, 20 Apr 2022 17:49:32 +0200 Subject: [PATCH 24/25] Fix regressions in Chargebee Resoruce --- lib/chargebee_elixir/gift.ex | 3 +++ lib/chargebee_elixir/resource.ex | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/chargebee_elixir/gift.ex b/lib/chargebee_elixir/gift.ex index 8f1a66f..6e41d3d 100644 --- a/lib/chargebee_elixir/gift.ex +++ b/lib/chargebee_elixir/gift.ex @@ -1,4 +1,7 @@ defmodule ChargebeeElixir.Gift do + @moduledoc """ + An interface for interacting with Chargebee Gifts + """ use ChargebeeElixir.Resource, "gift" def create_for_items(params) do diff --git a/lib/chargebee_elixir/resource.ex b/lib/chargebee_elixir/resource.ex index 1e915ab..04cad28 100644 --- a/lib/chargebee_elixir/resource.ex +++ b/lib/chargebee_elixir/resource.ex @@ -1,7 +1,7 @@ defmodule ChargebeeElixir.Resource do @moduledoc false defmacro __using__(resource) do - quote do + quote location: :keep do alias ChargebeeElixir.Interface @resource unquote(resource) @@ -61,7 +61,9 @@ defmodule ChargebeeElixir.Resource do end def resource_path(id) do - "#{resource_base_path()}/#{URI.encode(id)}" + encoded_id = id |> to_string |> URI.encode() + + "#{resource_base_path()}/#{encoded_id}" end end end From ff1ba211cff785f357ab00857265d95d045991fe Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Thu, 21 Apr 2022 13:16:11 +0200 Subject: [PATCH 25/25] v0.2.1 - Add Customer Merge --- lib/chargebee_elixir/customer.ex | 4 ++++ mix.exs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/chargebee_elixir/customer.ex b/lib/chargebee_elixir/customer.ex index 1755a43..53d15a2 100644 --- a/lib/chargebee_elixir/customer.ex +++ b/lib/chargebee_elixir/customer.ex @@ -3,4 +3,8 @@ defmodule ChargebeeElixir.Customer do an interface for interacting with Customers """ use ChargebeeElixir.Resource, "customer" + + def merge(args) do + create(args, "/merge") + end end diff --git a/mix.exs b/mix.exs index e9c763e..8ae5232 100644 --- a/mix.exs +++ b/mix.exs @@ -14,7 +14,7 @@ defmodule ChargebeeElixir.MixProject do }, source_url: "https://github.com/NicolasMarlier/chargebee-elixir", homepage_url: "https://github.com/NicolasMarlier/chargebee-elixir", - version: "0.2.0", + version: "0.2.1", elixir: "~> 1.11", start_permanent: Mix.env() == :prod, deps: deps()