From 7182b46f64cbdc95616566932bf8ab7be75a5332 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Fri, 27 Oct 2023 15:04:29 +0200 Subject: [PATCH 1/5] git ignore .envrc --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 56d1017..5d14875 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,7 @@ lemon_ex-*.tar /tmp/ # ElixirLS compile folder -.elixir_ls \ No newline at end of file +.elixir_ls + +# ENV vars +.envrc \ No newline at end of file From 05e36ee5af695ae9876fba9a6b9d3b5040e47ecd Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Fri, 27 Oct 2023 15:06:39 +0200 Subject: [PATCH 2/5] parse customer_portal url in subscription_created event --- lib/lemon_ex/subscriptions/subscription.ex | 3 ++- test/lemon_ex/webhooks/event_parser_test.exs | 7 +++++++ test/support/fixtures/subscription_created_event.json | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/lemon_ex/subscriptions/subscription.ex b/lib/lemon_ex/subscriptions/subscription.ex index e681ada..e10f9d0 100644 --- a/lib/lemon_ex/subscriptions/subscription.ex +++ b/lib/lemon_ex/subscriptions/subscription.ex @@ -50,7 +50,8 @@ defmodule LemonEx.Subscriptions.Subscription do billing_anchor: attributes["billing_anchor"], trial_ends_at: attributes["trial_ends_at"], urls: %{ - update_payment_method: urls["update_payment_method"] + update_payment_method: urls["update_payment_method"], + customer_portal: urls["customer_portal"] }, renews_at: attributes["renews_at"], ends_at: attributes["ends_at"], diff --git a/test/lemon_ex/webhooks/event_parser_test.exs b/test/lemon_ex/webhooks/event_parser_test.exs index e8bfd1a..7453068 100644 --- a/test/lemon_ex/webhooks/event_parser_test.exs +++ b/test/lemon_ex/webhooks/event_parser_test.exs @@ -56,6 +56,13 @@ defmodule LemonEx.Webhooks.EventParserTest do assert event.data.card_brand == "visa" assert event.data.card_last_four == "4242" assert event.data.renews_at == "2023-05-14T17:17:01.000000Z" + + assert event.data.urls == %{ + update_payment_method: + "https://my_store.lemonsqueezy.com/subscription/1/payment-details?expires=1681579025&signature=123", + customer_portal: + "https://my_store.lemonsqueezy.com/billing?&user=12345&expires=1698413545&signature=123" + } end end end diff --git a/test/support/fixtures/subscription_created_event.json b/test/support/fixtures/subscription_created_event.json index 7fe1443..a6b4ba3 100644 --- a/test/support/fixtures/subscription_created_event.json +++ b/test/support/fixtures/subscription_created_event.json @@ -14,6 +14,7 @@ }, "attributes": { "urls": { + "customer_portal": "https://my_store.lemonsqueezy.com/billing?&user=12345&expires=1698413545&signature=123", "update_payment_method": "https://my_store.lemonsqueezy.com/subscription/1/payment-details?expires=1681579025&signature=123" }, "pause": null, @@ -85,4 +86,4 @@ } } } -} +} \ No newline at end of file From 2880313d9ddb5c5c34b1862b0c0151f1248be09f Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Fri, 27 Oct 2023 18:39:01 +0200 Subject: [PATCH 3/5] add tests for Subscriptions list and get --- mix.exs | 3 +- mix.lock | 2 + .../subscriptions/subscriptions_test.exs | 147 ++++++++++++ .../fixtures/api/v1/subscriptions_get.json | 103 +++++++++ .../fixtures/api/v1/subscriptions_list.json | 211 ++++++++++++++++++ 5 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 test/lemon_ex/subscriptions/subscriptions_test.exs create mode 100644 test/support/fixtures/api/v1/subscriptions_get.json create mode 100644 test/support/fixtures/api/v1/subscriptions_list.json diff --git a/mix.exs b/mix.exs index e1b2dae..b7b0b1f 100644 --- a/mix.exs +++ b/mix.exs @@ -34,7 +34,8 @@ defmodule LemonEx.MixProject do {:jason, "~> 1.2"}, {:plug, "~> 1.14"}, {:plug_crypto, "~> 1.2"}, - {:ex_doc, ">= 0.0.0", only: :dev, runtime: false} + {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, + {:mock, "~> 0.3.8", only: :test} ] end diff --git a/mix.lock b/mix.lock index d865009..c75cf7b 100644 --- a/mix.lock +++ b/mix.lock @@ -9,9 +9,11 @@ "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"}, + "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, + "mock": {:hex, :mock, "0.3.8", "7046a306b71db2488ef54395eeb74df0a7f335a7caca4a3d3875d1fc81c884dd", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "7fa82364c97617d79bb7d15571193fc0c4fe5afd0c932cef09426b3ee6fe2022"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "plug": {:hex, :plug, "1.14.1", "3148623796853ae96c628960b833bf6b6a894d6bdc8c199ef7160c41149b71f2", [: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", "a0e789be21a576b11ec55a0983e4e8f7c7b07d88dfb3b8da9e97767132271d40"}, diff --git a/test/lemon_ex/subscriptions/subscriptions_test.exs b/test/lemon_ex/subscriptions/subscriptions_test.exs new file mode 100644 index 0000000..9f02349 --- /dev/null +++ b/test/lemon_ex/subscriptions/subscriptions_test.exs @@ -0,0 +1,147 @@ +defmodule LemonEx.SubscriptionsTest do + use ExUnit.Case, async: false + + import Mock + import Support.Fixtures, only: [load_json: 1] + + test "list" do + with_mock HTTPoison, get: succesful_response("api/v1/subscriptions_list") do + assert LemonEx.Subscriptions.list() == expected_subscription_list() + end + end + + test "get" do + with_mock HTTPoison, get: succesful_response("api/v1/subscriptions_get") do + assert LemonEx.Subscriptions.get(169_590) == expected_subscription() + end + end + + defp succesful_response(json_file) do + fn _url, _params, _headers -> + {:ok, + %HTTPoison.Response{ + status_code: 200, + body: load_json(json_file) + }} + end + end + + defp expected_subscription_list do + {:ok, + %LemonEx.PaginatedResponse{ + meta: %{ + page: %{current_page: nil, from: 1, last_page: nil, per_page: nil, to: 2, total: 2} + }, + links: %{ + first: + "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=-createdAt", + last: + "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=-createdAt", + next: nil, + prev: nil + }, + data: [ + %LemonEx.Subscriptions.Subscription{ + id: "169590", + store_id: 34567, + order_id: 1_487_261, + order_item_id: 1_450_500, + product_id: 121_004, + variant_id: 139_405, + product_name: "App Pro", + variant_name: "App Pro Monthly", + user_name: "Liza May", + user_email: "liza@example.com", + customer_id: 1_406_493, + status: "active", + status_formatted: "Active", + pause: nil, + cancelled: false, + trial_ends_at: nil, + billing_anchor: 27, + urls: %{ + customer_portal: + "https:\\/\\/mystore.lemonsqueezy.com\\/billing?expires=1698434430&user=1461055&signature=27b0921cc4b6a37bc5caed624bc5dbaa44d374e26e892544421668561b8ff0f5", + update_payment_method: + "https:\\/\\/mystore.lemonsqueezy.com\\/subscription\\/169590\\/payment-details?expires=1698499230&signature=18cbb5bfc703292df67d0f3528e533e396115096a404bb1876c895805956a959" + }, + renews_at: "2023-11-27T07:32:22.000000Z", + ends_at: nil, + created_at: "2023-10-27T07:32:24.000000Z", + updated_at: "2023-10-27T07:32:25.000000Z", + test_mode: true, + card_brand: "visa", + card_last_four: "4242" + }, + %LemonEx.Subscriptions.Subscription{ + id: "169586", + store_id: 34567, + order_id: 1_487_247, + order_item_id: 1_450_485, + product_id: 121_004, + variant_id: 139_405, + product_name: "App Pro", + variant_name: "App Pro Monthly", + user_name: "Liza May", + user_email: "liza@example.com", + customer_id: 1_406_493, + status: "active", + status_formatted: "Active", + pause: nil, + cancelled: false, + trial_ends_at: nil, + billing_anchor: 27, + urls: %{ + customer_portal: + "https:\\/\\/mystore.lemonsqueezy.com\\/billing?expires=1698434430&user=1461055&signature=27b0921cc4b6a37bc5caed624bc5dbaa44d374e26e892544421668561b8ff0f5", + update_payment_method: + "https:\\/\\/mystore.lemonsqueezy.com\\/subscription\\/169586\\/payment-details?expires=1698499230&signature=56a13a38f81e8d6592c2d28f379183add6b00f0034188437b919f97752f96ef8" + }, + renews_at: "2023-11-27T07:27:27.000000Z", + ends_at: nil, + created_at: "2023-10-27T07:27:29.000000Z", + updated_at: "2023-10-27T07:27:31.000000Z", + test_mode: true, + card_brand: "visa", + card_last_four: "4242" + } + ] + }} + end + + defp expected_subscription() do + {:ok, + %LemonEx.Subscriptions.Subscription{ + id: "169590", + store_id: 34567, + order_id: 1_487_261, + order_item_id: 1_450_500, + product_id: 121_004, + variant_id: 139_405, + product_name: "App Pro", + variant_name: "App Pro Monthly", + user_name: "Liza May", + user_email: "liza@example.com", + customer_id: 1_406_493, + status: "active", + status_formatted: "Active", + pause: nil, + cancelled: false, + trial_ends_at: nil, + billing_anchor: 27, + urls: %{ + customer_portal: + "https://mystore.lemonsqueezy.com/billing?expires=1698445809&user=1461055&signature=d0accab17db6cd5fbd9243dd5b57afd131972d61ad81284d26b0dbfcc5e91119", + update_payment_method: + "https://mystore.lemonsqueezy.com/subscription/169590/payment-details?expires=1698510609&signature=09c4d3759f6e0c5124e3ab9714e0c87ba0a9ca3f19d73d30c8f81622ac15d9f2" + }, + renews_at: "2023-11-27T07:32:22.000000Z", + ends_at: nil, + created_at: "2023-10-27T07:32:24.000000Z", + updated_at: "2023-10-27T07:32:25.000000Z", + test_mode: true, + card_brand: "visa", + card_last_four: "4242" + }} + end +end diff --git a/test/support/fixtures/api/v1/subscriptions_get.json b/test/support/fixtures/api/v1/subscriptions_get.json new file mode 100644 index 0000000..c9d95a9 --- /dev/null +++ b/test/support/fixtures/api/v1/subscriptions_get.json @@ -0,0 +1,103 @@ +{ + "jsonapi": { + "version": "1.0" + }, + "links": { + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590" + }, + "data": { + "type": "subscriptions", + "id": "169590", + "attributes": { + "store_id": 34567, + "customer_id": 1406493, + "order_id": 1487261, + "order_item_id": 1450500, + "product_id": 121004, + "variant_id": 139405, + "product_name": "App Pro", + "variant_name": "App Pro Monthly", + "user_name": "Liza May", + "user_email": "liza@example.com", + "status": "active", + "status_formatted": "Active", + "card_brand": "visa", + "card_last_four": "4242", + "pause": null, + "cancelled": false, + "trial_ends_at": null, + "billing_anchor": 27, + "first_subscription_item": { + "id": 132215, + "subscription_id": 169590, + "price_id": 127630, + "quantity": 1, + "is_usage_based": false, + "created_at": "2023-10-27T07:32:24.000000Z", + "updated_at": "2023-10-27T07:32:24.000000Z" + }, + "urls": { + "update_payment_method": "https:\/\/mystore.lemonsqueezy.com\/subscription\/169590\/payment-details?expires=1698510609&signature=09c4d3759f6e0c5124e3ab9714e0c87ba0a9ca3f19d73d30c8f81622ac15d9f2", + "customer_portal": "https:\/\/mystore.lemonsqueezy.com\/billing?expires=1698445809&user=1461055&signature=d0accab17db6cd5fbd9243dd5b57afd131972d61ad81284d26b0dbfcc5e91119" + }, + "renews_at": "2023-11-27T07:32:22.000000Z", + "ends_at": null, + "created_at": "2023-10-27T07:32:24.000000Z", + "updated_at": "2023-10-27T07:32:25.000000Z", + "test_mode": true + }, + "relationships": { + "store": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/store", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/relationships\/store" + } + }, + "customer": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/customer", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/relationships\/customer" + } + }, + "order": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/order", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/relationships\/order" + } + }, + "order-item": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/order-item", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/relationships\/order-item" + } + }, + "product": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/product", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/relationships\/product" + } + }, + "variant": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/variant", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/relationships\/variant" + } + }, + "subscription-items": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/subscription-items", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/relationships\/subscription-items" + } + }, + "subscription-invoices": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/subscription-invoices", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590\/relationships\/subscription-invoices" + } + } + }, + "links": { + "self": "https:\/\/api.lemonsqueezy.com\/v1\/subscriptions\/169590" + } + } +} \ No newline at end of file diff --git a/test/support/fixtures/api/v1/subscriptions_list.json b/test/support/fixtures/api/v1/subscriptions_list.json new file mode 100644 index 0000000..4d2ba47 --- /dev/null +++ b/test/support/fixtures/api/v1/subscriptions_list.json @@ -0,0 +1,211 @@ +{ + "meta": { + "page": { + "currentPage": 1, + "from": 1, + "lastPage": 1, + "perPage": 10, + "to": 2, + "total": 2 + } + }, + "jsonapi": { + "version": "1.0" + }, + "links": { + "first": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=-createdAt", + "last": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=-createdAt" + }, + "data": [ + { + "type": "subscriptions", + "id": "169590", + "attributes": { + "store_id": 34567, + "customer_id": 1406493, + "order_id": 1487261, + "order_item_id": 1450500, + "product_id": 121004, + "variant_id": 139405, + "product_name": "App Pro", + "variant_name": "App Pro Monthly", + "user_name": "Liza May", + "user_email": "liza@example.com", + "status": "active", + "status_formatted": "Active", + "card_brand": "visa", + "card_last_four": "4242", + "pause": null, + "cancelled": false, + "trial_ends_at": null, + "billing_anchor": 27, + "first_subscription_item": { + "id": 132215, + "subscription_id": 169590, + "price_id": 127630, + "quantity": 1, + "is_usage_based": false, + "created_at": "2023-10-27T07:32:24.000000Z", + "updated_at": "2023-10-27T07:32:24.000000Z" + }, + "urls": { + "update_payment_method": "https:\\/\\/mystore.lemonsqueezy.com\\/subscription\\/169590\\/payment-details?expires=1698499230&signature=18cbb5bfc703292df67d0f3528e533e396115096a404bb1876c895805956a959", + "customer_portal": "https:\\/\\/mystore.lemonsqueezy.com\\/billing?expires=1698434430&user=1461055&signature=27b0921cc4b6a37bc5caed624bc5dbaa44d374e26e892544421668561b8ff0f5" + }, + "renews_at": "2023-11-27T07:32:22.000000Z", + "ends_at": null, + "created_at": "2023-10-27T07:32:24.000000Z", + "updated_at": "2023-10-27T07:32:25.000000Z", + "test_mode": true + }, + "relationships": { + "store": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/store", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/relationships\\/store" + } + }, + "customer": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/customer", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/relationships\\/customer" + } + }, + "order": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/order", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/relationships\\/order" + } + }, + "order-item": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/order-item", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/relationships\\/order-item" + } + }, + "product": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/product", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/relationships\\/product" + } + }, + "variant": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/variant", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/relationships\\/variant" + } + }, + "subscription-items": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/subscription-items", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/relationships\\/subscription-items" + } + }, + "subscription-invoices": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/subscription-invoices", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590\\/relationships\\/subscription-invoices" + } + } + }, + "links": { + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169590" + } + }, + { + "type": "subscriptions", + "id": "169586", + "attributes": { + "store_id": 34567, + "customer_id": 1406493, + "order_id": 1487247, + "order_item_id": 1450485, + "product_id": 121004, + "variant_id": 139405, + "product_name": "App Pro", + "variant_name": "App Pro Monthly", + "user_name": "Liza May", + "user_email": "liza@example.com", + "status": "active", + "status_formatted": "Active", + "card_brand": "visa", + "card_last_four": "4242", + "pause": null, + "cancelled": false, + "trial_ends_at": null, + "billing_anchor": 27, + "first_subscription_item": { + "id": 132211, + "subscription_id": 169586, + "price_id": 127630, + "quantity": 1, + "is_usage_based": false, + "created_at": "2023-10-27T07:27:30.000000Z", + "updated_at": "2023-10-27T07:27:30.000000Z" + }, + "urls": { + "update_payment_method": "https:\\/\\/mystore.lemonsqueezy.com\\/subscription\\/169586\\/payment-details?expires=1698499230&signature=56a13a38f81e8d6592c2d28f379183add6b00f0034188437b919f97752f96ef8", + "customer_portal": "https:\\/\\/mystore.lemonsqueezy.com\\/billing?expires=1698434430&user=1461055&signature=27b0921cc4b6a37bc5caed624bc5dbaa44d374e26e892544421668561b8ff0f5" + }, + "renews_at": "2023-11-27T07:27:27.000000Z", + "ends_at": null, + "created_at": "2023-10-27T07:27:29.000000Z", + "updated_at": "2023-10-27T07:27:31.000000Z", + "test_mode": true + }, + "relationships": { + "store": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/store", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/relationships\\/store" + } + }, + "customer": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/customer", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/relationships\\/customer" + } + }, + "order": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/order", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/relationships\\/order" + } + }, + "order-item": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/order-item", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/relationships\\/order-item" + } + }, + "product": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/product", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/relationships\\/product" + } + }, + "variant": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/variant", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/relationships\\/variant" + } + }, + "subscription-items": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/subscription-items", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/relationships\\/subscription-items" + } + }, + "subscription-invoices": { + "links": { + "related": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/subscription-invoices", + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586\\/relationships\\/subscription-invoices" + } + } + }, + "links": { + "self": "https:\\/\\/api.lemonsqueezy.com\\/v1\\/subscriptions\\/169586" + } + } + ] +} \ No newline at end of file From f8b71f5b570cd83f18525ca142e2a2d5c289819b Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Fri, 27 Oct 2023 18:46:40 +0200 Subject: [PATCH 4/5] adds tests for current implementation of Customers --- test/lemon_ex/customers/customers_test.exs | 112 +++++++++++++++ .../fixtures/api/v1/customers_get.json | 62 +++++++++ .../fixtures/api/v1/customers_list.json | 129 ++++++++++++++++++ 3 files changed, 303 insertions(+) create mode 100644 test/lemon_ex/customers/customers_test.exs create mode 100644 test/support/fixtures/api/v1/customers_get.json create mode 100644 test/support/fixtures/api/v1/customers_list.json diff --git a/test/lemon_ex/customers/customers_test.exs b/test/lemon_ex/customers/customers_test.exs new file mode 100644 index 0000000..b863a7a --- /dev/null +++ b/test/lemon_ex/customers/customers_test.exs @@ -0,0 +1,112 @@ +defmodule LemonEx.CustomersTest do + use ExUnit.Case, async: false + + import Mock + import Support.Fixtures, only: [load_json: 1] + + test "list" do + with_mock HTTPoison, get: succesful_response("api/v1/customers_list") do + assert LemonEx.Customers.list() == expected_customers_list() + end + end + + test "get" do + with_mock HTTPoison, get: succesful_response("api/v1/customers_get") do + assert LemonEx.Customers.get(1_406_556) == expected_customer() + end + end + + defp succesful_response(json_file) do + fn _url, _params, _headers -> + {:ok, + %HTTPoison.Response{ + status_code: 200, + body: load_json(json_file) + }} + end + end + + defp expected_customers_list do + { + :ok, + %LemonEx.PaginatedResponse{ + data: [ + %LemonEx.Customers.Customer{ + created_at: "2023-10-14T17:52:43.000000Z", + id: "1406556", + status: "subscribed", + status_formatted: "Subscribed", + store_id: 48264, + test_mode: true, + updated_at: "2023-10-14T17:52:44.000000Z", + city: nil, + country: "ES", + country_formatted: "Spain", + email: "liza@example.com", + mrr: 3600, + mrr_formatted: "$36.00", + name: "Liza May", + region: nil, + total_revenue_currency: 0, + total_revenue_currency_formatted: "$0.00" + }, + %LemonEx.Customers.Customer{ + created_at: "2023-10-14T17:35:40.000000Z", + id: "1406493", + status: "subscribed", + status_formatted: "Subscribed", + store_id: 48264, + test_mode: true, + updated_at: "2023-10-27T07:32:25.000000Z", + city: nil, + country: nil, + country_formatted: nil, + email: "joe@example.com", + mrr: 14400, + mrr_formatted: "$144.00", + name: "Joe Burns", + region: nil, + total_revenue_currency: 0, + total_revenue_currency_formatted: "$0.00" + } + ], + links: %{ + first: + "https://api.lemonsqueezy.com/v1/customers?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=-createdAt", + last: + "https://api.lemonsqueezy.com/v1/customers?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=-createdAt", + next: nil, + prev: nil + }, + meta: %{ + page: %{current_page: nil, from: 1, last_page: nil, per_page: nil, to: 2, total: 2} + } + } + } + end + + defp expected_customer() do + { + :ok, + %LemonEx.Customers.Customer{ + created_at: "2023-10-14T17:52:43.000000Z", + id: "1406556", + status: "subscribed", + status_formatted: "Subscribed", + store_id: 48264, + test_mode: true, + updated_at: "2023-10-14T17:52:44.000000Z", + city: nil, + country: "ES", + country_formatted: "Spain", + email: "liza@example.com", + mrr: 3600, + mrr_formatted: "$36.00", + name: "Liza May", + region: nil, + total_revenue_currency: 0, + total_revenue_currency_formatted: "$0.00" + } + } + end +end diff --git a/test/support/fixtures/api/v1/customers_get.json b/test/support/fixtures/api/v1/customers_get.json new file mode 100644 index 0000000..7549290 --- /dev/null +++ b/test/support/fixtures/api/v1/customers_get.json @@ -0,0 +1,62 @@ +{ + "jsonapi": { + "version": "1.0" + }, + "links": { + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556" + }, + "data": { + "type": "customers", + "id": "1406556", + "attributes": { + "store_id": 48264, + "name": "Liza May", + "email": "liza@example.com", + "status": "subscribed", + "city": null, + "region": null, + "country": "ES", + "total_revenue_currency": 0, + "mrr": 3600, + "status_formatted": "Subscribed", + "country_formatted": "Spain", + "total_revenue_currency_formatted": "$0.00", + "mrr_formatted": "$36.00", + "urls": { + "customer_portal": "https:\/\/mystore.lemonsqueezy.com\/billing?expires=1698446663&user=1412358&signature=cb8dfe5c40dbec4af7082d8a1b082c07cc12d4ba0a91000d6280d2d5b9c2fdc3" + }, + "created_at": "2023-10-14T17:52:43.000000Z", + "updated_at": "2023-10-14T17:52:44.000000Z", + "test_mode": true + }, + "relationships": { + "store": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/store", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/relationships\/store" + } + }, + "orders": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/orders", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/relationships\/orders" + } + }, + "subscriptions": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/subscriptions", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/relationships\/subscriptions" + } + }, + "license-keys": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/license-keys", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/relationships\/license-keys" + } + } + }, + "links": { + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556" + } + } +} \ No newline at end of file diff --git a/test/support/fixtures/api/v1/customers_list.json b/test/support/fixtures/api/v1/customers_list.json new file mode 100644 index 0000000..ba31f44 --- /dev/null +++ b/test/support/fixtures/api/v1/customers_list.json @@ -0,0 +1,129 @@ +{ + "meta": { + "page": { + "currentPage": 1, + "from": 1, + "lastPage": 1, + "perPage": 10, + "to": 2, + "total": 2 + } + }, + "jsonapi": { + "version": "1.0" + }, + "links": { + "first": "https:\/\/api.lemonsqueezy.com\/v1\/customers?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=-createdAt", + "last": "https:\/\/api.lemonsqueezy.com\/v1\/customers?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=-createdAt" + }, + "data": [ + { + "type": "customers", + "id": "1406556", + "attributes": { + "store_id": 48264, + "name": "Liza May", + "email": "liza@example.com", + "status": "subscribed", + "city": null, + "region": null, + "country": "ES", + "total_revenue_currency": 0, + "mrr": 3600, + "status_formatted": "Subscribed", + "country_formatted": "Spain", + "total_revenue_currency_formatted": "$0.00", + "mrr_formatted": "$36.00", + "urls": { + "customer_portal": "https:\/\/mystore.lemonsqueezy.com\/billing?expires=1698446369&user=1412358&signature=fed8b8bea09639c923353eeec8a5295471803f15a3bebc703b7b66bd8ebab862" + }, + "created_at": "2023-10-14T17:52:43.000000Z", + "updated_at": "2023-10-14T17:52:44.000000Z", + "test_mode": true + }, + "relationships": { + "store": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/store", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/relationships\/store" + } + }, + "orders": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/orders", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/relationships\/orders" + } + }, + "subscriptions": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/subscriptions", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/relationships\/subscriptions" + } + }, + "license-keys": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/license-keys", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556\/relationships\/license-keys" + } + } + }, + "links": { + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406556" + } + }, + { + "type": "customers", + "id": "1406493", + "attributes": { + "store_id": 48264, + "name": "Joe Burns", + "email": "joe@example.com", + "status": "subscribed", + "city": null, + "region": null, + "country": null, + "total_revenue_currency": 0, + "mrr": 14400, + "status_formatted": "Subscribed", + "country_formatted": null, + "total_revenue_currency_formatted": "$0.00", + "mrr_formatted": "$144.00", + "urls": { + "customer_portal": "https:\/\/mystore.lemonsqueezy.com\/billing?expires=1698446369&user=1461055&signature=2b699e59adcf00238f503e722a6e8efbbba35849b47b71e6d94fcf7cce05b5f4" + }, + "created_at": "2023-10-14T17:35:40.000000Z", + "updated_at": "2023-10-27T07:32:25.000000Z", + "test_mode": true + }, + "relationships": { + "store": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406493\/store", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406493\/relationships\/store" + } + }, + "orders": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406493\/orders", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406493\/relationships\/orders" + } + }, + "subscriptions": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406493\/subscriptions", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406493\/relationships\/subscriptions" + } + }, + "license-keys": { + "links": { + "related": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406493\/license-keys", + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406493\/relationships\/license-keys" + } + } + }, + "links": { + "self": "https:\/\/api.lemonsqueezy.com\/v1\/customers\/1406493" + } + } + ] +} \ No newline at end of file From 50ba9d638e64396433956ac730db39998cd94391 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Fri, 27 Oct 2023 18:50:35 +0200 Subject: [PATCH 5/5] adds customer_portal url to Customers --- lib/lemon_ex/customers/customer.ex | 5 ++ test/lemon_ex/customers/customers_test.exs | 58 +++++++++++++--------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/lib/lemon_ex/customers/customer.ex b/lib/lemon_ex/customers/customer.ex index 88f2ad9..153d3d2 100644 --- a/lib/lemon_ex/customers/customer.ex +++ b/lib/lemon_ex/customers/customer.ex @@ -14,6 +14,7 @@ defmodule LemonEx.Customers.Customer do :country_formatted, :total_revenue_currency_formatted, :mrr_formatted, + :urls, :created_at, :updated_at, :test_mode @@ -21,6 +22,7 @@ defmodule LemonEx.Customers.Customer do def from_json(map) do attributes = map["attributes"] + urls = attributes["urls"] %__MODULE__{ id: map["id"], @@ -37,6 +39,9 @@ defmodule LemonEx.Customers.Customer do country_formatted: attributes["country_formatted"], total_revenue_currency_formatted: attributes["total_revenue_currency_formatted"], mrr_formatted: attributes["mrr_formatted"], + urls: %{ + customer_portal: urls["customer_portal"] + }, created_at: attributes["created_at"], updated_at: attributes["updated_at"], test_mode: attributes["test_mode"] diff --git a/test/lemon_ex/customers/customers_test.exs b/test/lemon_ex/customers/customers_test.exs index b863a7a..55ff5fb 100644 --- a/test/lemon_ex/customers/customers_test.exs +++ b/test/lemon_ex/customers/customers_test.exs @@ -32,42 +32,50 @@ defmodule LemonEx.CustomersTest do %LemonEx.PaginatedResponse{ data: [ %LemonEx.Customers.Customer{ - created_at: "2023-10-14T17:52:43.000000Z", - id: "1406556", - status: "subscribed", - status_formatted: "Subscribed", - store_id: 48264, - test_mode: true, - updated_at: "2023-10-14T17:52:44.000000Z", city: nil, country: "ES", country_formatted: "Spain", + created_at: "2023-10-14T17:52:43.000000Z", email: "liza@example.com", + id: "1406556", mrr: 3600, mrr_formatted: "$36.00", name: "Liza May", region: nil, - total_revenue_currency: 0, - total_revenue_currency_formatted: "$0.00" - }, - %LemonEx.Customers.Customer{ - created_at: "2023-10-14T17:35:40.000000Z", - id: "1406493", status: "subscribed", status_formatted: "Subscribed", store_id: 48264, test_mode: true, - updated_at: "2023-10-27T07:32:25.000000Z", + total_revenue_currency: 0, + total_revenue_currency_formatted: "$0.00", + updated_at: "2023-10-14T17:52:44.000000Z", + urls: %{ + customer_portal: + "https://mystore.lemonsqueezy.com/billing?expires=1698446369&user=1412358&signature=fed8b8bea09639c923353eeec8a5295471803f15a3bebc703b7b66bd8ebab862" + } + }, + %LemonEx.Customers.Customer{ city: nil, country: nil, country_formatted: nil, + created_at: "2023-10-14T17:35:40.000000Z", email: "joe@example.com", + id: "1406493", mrr: 14400, mrr_formatted: "$144.00", name: "Joe Burns", region: nil, + status: "subscribed", + status_formatted: "Subscribed", + store_id: 48264, + test_mode: true, total_revenue_currency: 0, - total_revenue_currency_formatted: "$0.00" + total_revenue_currency_formatted: "$0.00", + updated_at: "2023-10-27T07:32:25.000000Z", + urls: %{ + customer_portal: + "https://mystore.lemonsqueezy.com/billing?expires=1698446369&user=1461055&signature=2b699e59adcf00238f503e722a6e8efbbba35849b47b71e6d94fcf7cce05b5f4" + } } ], links: %{ @@ -89,23 +97,27 @@ defmodule LemonEx.CustomersTest do { :ok, %LemonEx.Customers.Customer{ - created_at: "2023-10-14T17:52:43.000000Z", - id: "1406556", - status: "subscribed", - status_formatted: "Subscribed", - store_id: 48264, - test_mode: true, - updated_at: "2023-10-14T17:52:44.000000Z", city: nil, country: "ES", country_formatted: "Spain", + created_at: "2023-10-14T17:52:43.000000Z", email: "liza@example.com", + id: "1406556", mrr: 3600, mrr_formatted: "$36.00", name: "Liza May", region: nil, + status: "subscribed", + status_formatted: "Subscribed", + store_id: 48264, + test_mode: true, total_revenue_currency: 0, - total_revenue_currency_formatted: "$0.00" + total_revenue_currency_formatted: "$0.00", + updated_at: "2023-10-14T17:52:44.000000Z", + urls: %{ + customer_portal: + "https://mystore.lemonsqueezy.com/billing?expires=1698446663&user=1412358&signature=cb8dfe5c40dbec4af7082d8a1b082c07cc12d4ba0a91000d6280d2d5b9c2fdc3" + } } } end