Skip to content

Commit e0663e1

Browse files
Implement platform plan apis (#793)
1 parent a613e64 commit e0663e1

File tree

13 files changed

+885
-27
lines changed

13 files changed

+885
-27
lines changed

apps/core/lib/core/policies/payments.ex

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
defmodule Core.Policies.Payments do
22
use Piazza.Policy
3-
alias Core.Schema.{Plan, Subscription, User}
3+
import Core.Policies.Utils
4+
alias Core.Schema.{Plan, Subscription, PlatformPlan, PlatformSubscription, User}
45
alias Core.Policies.Publisher
56

7+
def can?(user, %PlatformPlan{}, _),
8+
do: check_rbac(user, :billing, account: user.account)
9+
10+
def can?(user, %PlatformSubscription{}, _),
11+
do: check_rbac(user, :billing, account: user.account)
12+
613
def can?(user, %Plan{} = plan, action) do
714
%{repository: %{publisher: pub}} = Core.Repo.preload(plan, [repository: :publisher])
815
Publisher.can?(user, pub, action)
@@ -27,4 +34,4 @@ defmodule Core.Policies.Payments do
2734
do: can?(user, apply_changes(cs), action)
2835

2936
def can?(_, _, _), do: {:error, :forbidden}
30-
end
37+
end

apps/core/lib/core/schema/account.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Core.Schema.Account do
22
use Piazza.Ecto.Schema
33
use Arc.Ecto.Schema
4-
alias Core.Schema.{User, DomainMapping}
4+
alias Core.Schema.{User, DomainMapping, PlatformSubscription}
55

66
schema "accounts" do
77
field :name, :string
@@ -12,6 +12,7 @@ defmodule Core.Schema.Account do
1212

1313
belongs_to :root_user, User
1414
has_many :domain_mappings, DomainMapping, on_replace: :delete
15+
has_one :subscription, PlatformSubscription
1516

1617
timestamps()
1718
end
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
defmodule Core.Schema.PlatformPlan do
2+
use Piazza.Ecto.Schema
3+
4+
defenum Period, monthly: 0, yearly: 1
5+
defenum Dimension, user: 0
6+
7+
defmodule LineItem do
8+
use Piazza.Ecto.Schema
9+
alias Core.Schema.PlatformPlan.{Period, Dimension}
10+
11+
embedded_schema do
12+
field :name, :string
13+
field :dimension, Dimension
14+
field :external_id, :string
15+
field :cost, :integer
16+
field :period, Period
17+
end
18+
19+
@valid ~w(name cost period dimension external_id)a
20+
21+
def changeset(model, attrs \\ %{}) do
22+
model
23+
|> cast(attrs, @valid)
24+
|> validate_required([:name, :cost, :period, :dimension])
25+
end
26+
end
27+
28+
schema "platform_plans" do
29+
field :name, :string
30+
field :visible, :boolean, default: true
31+
field :cost, :integer
32+
field :period, Period
33+
field :external_id, :string
34+
35+
embeds_one :features, Features, on_replace: :update do
36+
boolean_fields [:vpn]
37+
end
38+
39+
embeds_many :line_items, LineItem, on_replace: :delete
40+
41+
timestamps()
42+
end
43+
44+
def visible(query \\ __MODULE__), do: from(p in query, where: p.visible)
45+
46+
def ordered(query \\ __MODULE__, order \\ [asc: :name]),
47+
do: from(p in query, order_by: ^order)
48+
49+
def features(), do: __MODULE__.Features.__schema__(:fields) -- [:id]
50+
51+
@valid ~w(name visible cost period external_id)a
52+
53+
def changeset(schema, attrs \\ %{}) do
54+
schema
55+
|> cast(attrs, @valid)
56+
|> cast_embed(:line_items)
57+
|> cast_embed(:features, with: &features_changeset/2)
58+
|> validate_required([:name, :visible])
59+
end
60+
61+
def features_changeset(model, attrs) do
62+
model
63+
|> cast(attrs, features())
64+
end
65+
end
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
defmodule Core.Schema.PlatformSubscription do
2+
use Piazza.Ecto.Schema
3+
alias Core.Schema.{Account, PlatformPlan}
4+
5+
defmodule LineItem do
6+
use Piazza.Ecto.Schema
7+
alias Core.Schema.PlatformPlan
8+
9+
embedded_schema do
10+
field :dimension, PlatformPlan.Dimension
11+
field :quantity, :integer
12+
field :external_id, :string
13+
end
14+
15+
@valid ~w(dimension quantity external_id)a
16+
17+
def changeset(model, attrs \\ %{}) do
18+
model
19+
|> cast(attrs, @valid)
20+
|> validate_required([:dimension, :quantity])
21+
end
22+
end
23+
24+
schema "platform_subscriptions" do
25+
field :external_id, :string
26+
27+
embeds_many :line_items, LineItem, on_replace: :delete
28+
belongs_to :account, Account
29+
belongs_to :plan, PlatformPlan
30+
31+
timestamps()
32+
end
33+
34+
@valid ~w(account_id plan_id)a
35+
36+
def dimension(%__MODULE__{line_items: items}, dim) do
37+
case Enum.find(items, & &1.dimension == dim) do
38+
%{quantity: quantity} -> quantity
39+
_ -> 0
40+
end
41+
end
42+
43+
def line_item(%__MODULE__{line_items: items}, dim),
44+
do: Enum.find(items, & &1.dimension == dim)
45+
46+
def changeset(schema, attrs \\ %{}) do
47+
schema
48+
|> cast(attrs, @valid)
49+
|> cast_embed(:line_items)
50+
|> validate_required([:account_id, :plan_id])
51+
|> foreign_key_constraint(:account_id)
52+
|> foreign_key_constraint(:plan_id)
53+
|> unique_constraint(:account_id)
54+
end
55+
56+
@stripe_valid ~w(external_id)a
57+
58+
def stripe_changeset(schema, attrs \\ %{}) do
59+
schema
60+
|> cast(attrs, @stripe_valid)
61+
|> cast_embed(:line_items)
62+
|> unique_constraint(:account_id)
63+
|> unique_constraint(:external_id)
64+
end
65+
end

0 commit comments

Comments
 (0)