analytics/lib/mix/tasks/pull_sandbox_subscription.ex
Adrian Gruntkowski 17b12ddaeb
Implement basics of Teams (#4658)
* Extend schemas with new fields and relationships for teams

* Implement listing sites and sites with invitations with teams

* Implement creating invitations with teams

* Implement accepting invites with teams

* Add `Teams.SiteTransfer` schema

* Implement creating ownership transfers

* Implement accepting site transfer between teams

* Make results shapes from `Teams.Memberships` role functions more consistent

* Remove :team relation from ApiKey schema

* Pass and provision team on subscription creation

* Pass and provision team on enterprise plan creation

* Implement creating site for a team

* Keep team in sync during legacy ownership transfer and invitations

* Resolve conflict in `Teams.get_or_create` without transaction

* Abstract `GracePeriod` manipulation behind `Plausible.Users`

* Put `User.start_trial` behind `Plausible.Users` API

* Sync team fields on user update, if team exists

* Sync cleaning invitations, updating and removing members

* Transfer invitations too

* Implement backfill script

* Allow separate pg repo for backfill script

* Rollback purposefully at the end

* Update backfill script with parallel processing

* Use `IS DISTINCT FROM` when comparing nullable fields

* Handle no teams to backfill case gracefully when reporting

* Parallelize guest memberships backfill

* Remove transaction wrapping and query timeouts

* Make team sync check more granular and fix formatting

* Wrap single team backfill in a transatction for consistent restarts

* Make invitation and site transfer backfills preserve invitation ID

* Update migration repo config for easier dev access

* Backfill teams for users with subscriptions without sites

* Log timestamps

* Put teams sync behind a compile-time flag

* Keep timestamps in sync and fix subscriptions backfill

* Fix formatting

* Make credo happy

* Don't `use Plausible.Migration` to avoid dialyzer complaining

None of the tooling from there is used anywhere and `@repo` can
be defined directly in the migration script.

* Drop SSL workarounds in the backfill script

---------

Co-authored-by: Adam Rutkowski <hq@mtod.org>
2024-10-21 07:35:23 +00:00

73 lines
2.3 KiB
Elixir

defmodule Mix.Tasks.PullSandboxSubscription do
use Mix.Task
use Plausible.Repo
alias Plausible.{Repo, Auth.User, Billing.Subscription}
require Logger
# Steps to create a subscription in dev environment
#
# 1) Subscribe to a sandbox plan in the UI > User Settings. Instructions:
# https://developer.paddle.com/getting-started/ZG9jOjIxODY4NjYx-sandbox
#
# 2) find the created subscription_ID here:
# https://sandbox-vendors.paddle.com/subscriptions/customers
#
# 3) run from command line:
# mix pull_sandbox_subscription <subscription_ID>
@headers [
{"Content-type", "application/json"},
{"Accept", "application/json"}
]
def run([paddle_subscription_id]) do
Mix.Task.run("app.start")
config = Application.get_env(:plausible, :paddle)
endpoint = Plausible.Billing.PaddleApi.vendors_domain() <> "/api/2.0/subscription/users"
params = %{
vendor_id: config[:vendor_id],
vendor_auth_code: config[:vendor_auth_code],
subscription_id: paddle_subscription_id
}
case HTTPoison.post(endpoint, Jason.encode!(params), @headers) do
{:ok, response} ->
body = Jason.decode!(response.body)
if body["success"] do
res = body["response"] |> List.first()
user = Repo.get_by!(User, email: res["user_email"])
{:ok, team} = Plausible.Teams.get_or_create(user)
Plausible.Teams.sync_team(user)
subscription = %{
paddle_subscription_id: res["subscription_id"] |> to_string(),
paddle_plan_id: res["plan_id"] |> to_string(),
cancel_url: res["cancel_url"],
update_url: res["update_url"],
user_id: user.id,
team_id: team.id,
status: res["state"],
last_bill_date: res["last_payment"]["date"],
next_bill_date: res["next_payment"]["date"],
next_bill_amount: res["next_payment"]["amount"] |> to_string(),
currency_code: res["next_payment"]["currency"]
}
Subscription.changeset(%Subscription{}, subscription)
|> Repo.insert!()
Logger.info("Subscription created for user #{user.id} (#{user.email})")
else
Logger.error(body["error"])
end
{:error, reason} ->
Logger.error(reason)
end
end
end