Skip to content

Commit c5643d4

Browse files
committed
add sanity checks
1 parent ed1f362 commit c5643d4

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

lib/algora/admin/migration.ex

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
defmodule Algora.Admin.Migration do
2+
@moduledoc false
3+
import Ecto.Query
4+
5+
alias Algora.Accounts.User
6+
alias Algora.Payments.Transaction
7+
alias Algora.Repo
8+
9+
def get_actual_balances(:individual) do
10+
with {:ok, content} <- File.read(".local/db/balance-2025-02-10.json"),
11+
{:ok, %{"individual" => balances}} <- Jason.decode(content) do
12+
Enum.map(balances, fn %{"provider_login" => login, "balance" => balance} ->
13+
%{
14+
provider_login: login,
15+
balance: Money.new!(:USD, Decimal.new(balance))
16+
}
17+
end)
18+
else
19+
error -> raise "Failed to load balances: #{inspect(error)}"
20+
end
21+
end
22+
23+
def get_balances(type) do
24+
Enum.filter(get_balances(), &(&1.type == type))
25+
end
26+
27+
def get_balances do
28+
user_txs =
29+
from t in Transaction,
30+
group_by: [t.user_id, t.type],
31+
select: %{
32+
user_id: t.user_id,
33+
type: t.type,
34+
net_amount: sum(t.net_amount)
35+
}
36+
37+
user_balances =
38+
from ut in subquery(user_txs),
39+
group_by: ut.user_id,
40+
select: %{
41+
user_id: ut.user_id,
42+
balance:
43+
sum(
44+
fragment(
45+
"""
46+
CASE
47+
WHEN ? = 'credit' THEN ?
48+
WHEN ? = 'debit' THEN money_negate(?)
49+
WHEN ? = 'charge' THEN ?
50+
WHEN ? = 'transfer' THEN money_negate(?)
51+
ELSE ('USD', 0)::money_with_currency
52+
END
53+
""",
54+
ut.type,
55+
ut.net_amount,
56+
ut.type,
57+
ut.net_amount,
58+
ut.type,
59+
ut.net_amount,
60+
ut.type,
61+
ut.net_amount
62+
)
63+
)
64+
}
65+
66+
query =
67+
from ub in subquery(user_balances),
68+
join: u in User,
69+
on: u.id == ub.user_id,
70+
where: ub.balance != fragment("('USD', 0)::money_with_currency"),
71+
order_by: [desc: u.type, desc: ub.balance, asc: u.provider_login],
72+
select: %{
73+
type: u.type,
74+
provider_login: u.provider_login,
75+
balance: ub.balance
76+
}
77+
78+
query
79+
|> Repo.all()
80+
|> Enum.map(fn
81+
user ->
82+
{currency, amount} = user.balance
83+
%{user | balance: Money.new!(currency, amount)}
84+
end)
85+
end
86+
87+
def diff_balances(type) do
88+
actual = Enum.map(get_actual_balances(type), &Map.take(&1, [:provider_login, :balance]))
89+
current = Enum.map(get_balances(type), &Map.take(&1, [:provider_login, :balance]))
90+
91+
actual_map = Map.new(actual, &{&1.provider_login, &1.balance})
92+
current_map = Map.new(current, &{&1.provider_login, &1.balance})
93+
94+
all_logins =
95+
MapSet.union(
96+
MapSet.new(Map.keys(actual_map)),
97+
MapSet.new(Map.keys(current_map))
98+
)
99+
100+
differences =
101+
Enum.reduce(all_logins, [], fn login, acc ->
102+
actual_balance = Map.get(actual_map, login)
103+
current_balance = Map.get(current_map, login)
104+
105+
cond do
106+
actual_balance == current_balance ->
107+
acc
108+
109+
actual_balance == nil ->
110+
[{:extra_in_current, login, current_balance} | acc]
111+
112+
current_balance == nil ->
113+
[{:missing_in_current, login, actual_balance} | acc]
114+
115+
true ->
116+
[{:different, login, actual_balance, current_balance} | acc]
117+
end
118+
end)
119+
120+
Enum.sort_by(differences, &elem(&1, 1))
121+
end
122+
end

0 commit comments

Comments
 (0)