Add initial Odoo integration (billing address)
This commit is contained in:
parent
1133025016
commit
dcb5f364c2
10 changed files with 188 additions and 0 deletions
|
@ -80,3 +80,10 @@ config :recycledcloud, :ldap,
|
||||||
bind_dn: "cn=admin,dc=example,dc=org",
|
bind_dn: "cn=admin,dc=example,dc=org",
|
||||||
bind_pw: "admin",
|
bind_pw: "admin",
|
||||||
default_group_gid: 1000
|
default_group_gid: 1000
|
||||||
|
|
||||||
|
## Odoo API credentials
|
||||||
|
config :recycledcloud, :odoo,
|
||||||
|
server: "https://odoo.staging.e-durable.ch",
|
||||||
|
database: "e-Durable",
|
||||||
|
user: "user",
|
||||||
|
secret: "secret"
|
||||||
|
|
|
@ -16,6 +16,7 @@ defmodule RecycledCloud.Accounts.User do
|
||||||
field :dn, :string, virtual: true
|
field :dn, :string, virtual: true
|
||||||
field :email, :string, virtual: true
|
field :email, :string, virtual: true
|
||||||
field :confirmed_at, :naive_datetime
|
field :confirmed_at, :naive_datetime
|
||||||
|
field :partner_id, :integer
|
||||||
|
|
||||||
has_many :keys, Accounts.Key
|
has_many :keys, Accounts.Key
|
||||||
|
|
||||||
|
|
93
lib/recycledcloud/billing/partner.ex
Normal file
93
lib/recycledcloud/billing/partner.ex
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
defmodule RecycledCloud.Billing.Partner do
|
||||||
|
alias RecycledCloud.Accounts.User
|
||||||
|
alias RecycledCloud.Billing.Partner
|
||||||
|
alias RecycledCloud.Odoo
|
||||||
|
alias RecycledCloud.Repo
|
||||||
|
|
||||||
|
import Ecto.Changeset
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
@address_fields [:street, :city, :zip]
|
||||||
|
|
||||||
|
# Note: Odoo stores partner's country under 'country_id'. We do not support
|
||||||
|
# editing it at the moment.
|
||||||
|
|
||||||
|
embedded_schema do
|
||||||
|
field :name, :string
|
||||||
|
field :email, :string
|
||||||
|
field :street, :string
|
||||||
|
field :city, :string
|
||||||
|
field :zip, :string
|
||||||
|
field :country, :string
|
||||||
|
end
|
||||||
|
|
||||||
|
def changeset(%Partner{} = partner, attrs) do
|
||||||
|
partner |> cast(attrs, @address_fields)
|
||||||
|
end
|
||||||
|
|
||||||
|
def apply(changeset) do
|
||||||
|
# Check if changeset is valid.
|
||||||
|
state = changeset |> Ecto.Changeset.apply_action(:update)
|
||||||
|
case state do
|
||||||
|
{:ok, partner} ->
|
||||||
|
changes = partner
|
||||||
|
|> Map.from_struct
|
||||||
|
|> Enum.filter(fn {k,_v} -> k in @address_fields end)
|
||||||
|
|> Enum.map(fn {k, v} -> {to_string(k), v} end)
|
||||||
|
|> Enum.into(%{})
|
||||||
|
|
||||||
|
# Propagate to Odoo
|
||||||
|
Odoo.query([
|
||||||
|
"res.partner",
|
||||||
|
"write",
|
||||||
|
[[partner.id], changes]
|
||||||
|
])
|
||||||
|
{:error, _} -> state
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(id) do
|
||||||
|
result = Odoo.query([
|
||||||
|
"res.partner",
|
||||||
|
"search_read",
|
||||||
|
[[["id", "=", id]]],
|
||||||
|
%{"fields" => ["id", "name", "email", "country_id"] ++ @address_fields}
|
||||||
|
])
|
||||||
|
|
||||||
|
format_fields = fn p ->
|
||||||
|
case p do
|
||||||
|
{k, false} when k in @address_fields -> {k, ""}
|
||||||
|
{:country_id, false} -> {:country, ""}
|
||||||
|
{:country_id, [_id, str]} -> {:country, str}
|
||||||
|
_ -> p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
case result do
|
||||||
|
{:ok, [raw]} ->
|
||||||
|
args = raw
|
||||||
|
|> Enum.map(fn {k, v} -> {String.to_atom(k), v} end)
|
||||||
|
|> Enum.map(format_fields)
|
||||||
|
struct(Partner, args)
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(name, email) do
|
||||||
|
Odoo.query([
|
||||||
|
"res.partner",
|
||||||
|
"create",
|
||||||
|
[%{"name" => name, "email" => email}]
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_or_create(%User{} = user) do
|
||||||
|
case user.partner_id do
|
||||||
|
nil ->
|
||||||
|
{:ok, id} = create(user.username, user.email)
|
||||||
|
{:ok, updated} = user |> change(%{partner_id: id}) |> Repo.update()
|
||||||
|
get_or_create(updated)
|
||||||
|
id -> get(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
33
lib/recycledcloud_web/controllers/billing_controller.ex
Normal file
33
lib/recycledcloud_web/controllers/billing_controller.ex
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
defmodule RecycledCloudWeb.BillingController do
|
||||||
|
use RecycledCloudWeb, :controller
|
||||||
|
|
||||||
|
alias RecycledCloud.Billing.Partner
|
||||||
|
alias RecycledCloud.Repo
|
||||||
|
|
||||||
|
def current_partner(conn) do
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
Partner.get_or_create(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def index(conn, _params) do
|
||||||
|
partner = conn |> current_partner
|
||||||
|
changeset = partner |> Partner.changeset(%{})
|
||||||
|
|
||||||
|
render(conn, "index.html", partner: partner, partner_changeset: changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(conn, %{"partner" => changes} = params) do
|
||||||
|
partner = conn |> current_partner
|
||||||
|
changeset = partner |> Partner.changeset(changes)
|
||||||
|
|
||||||
|
case Partner.apply(changeset) do
|
||||||
|
{:ok, _} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "Billing Partner has been updated")
|
||||||
|
|> redirect(to: Routes.billing_path(conn, :index))
|
||||||
|
{:error, changeset} ->
|
||||||
|
render(conn, "index.html", partner: partner, partner_changeset:
|
||||||
|
changeset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -55,6 +55,8 @@ defmodule RecycledCloudWeb.Router do
|
||||||
get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email
|
get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email
|
||||||
post "/users/settings/keys/new", UserKeysController, :new
|
post "/users/settings/keys/new", UserKeysController, :new
|
||||||
get "/users/settings/keys/:key_id/delete", UserKeysController, :delete
|
get "/users/settings/keys/:key_id/delete", UserKeysController, :delete
|
||||||
|
get "/billing", BillingController, :index
|
||||||
|
post "/billing/partner/update", BillingController, :update
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", RecycledCloudWeb do
|
scope "/", RecycledCloudWeb do
|
||||||
|
|
35
lib/recycledcloud_web/templates/billing/index.html.eex
Normal file
35
lib/recycledcloud_web/templates/billing/index.html.eex
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<h1>Billing</h1>
|
||||||
|
|
||||||
|
<p>You currently are registered as billing entity #<%= @partner.id %>.</p>
|
||||||
|
|
||||||
|
<h2>Billing address</h2>
|
||||||
|
|
||||||
|
<%= form_for @partner_changeset, Routes.billing_path(@conn, :update), fn f -> %>
|
||||||
|
<%= if @partner_changeset.action do %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p>Oops, something went wrong! Please check the errors below.</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= text_input f, :street, placeholder: "Street" %>
|
||||||
|
<%= error_tag f, :street %>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<%= text_input f, :city, placeholder: "City" %>
|
||||||
|
<%= error_tag f, :city %>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<%= text_input f, :zip, placeholder: "Zip" %>
|
||||||
|
<%= error_tag f, :zip %>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<%= text_input f, :country, placeholder: "Country", readonly: true %>
|
||||||
|
<%= error_tag f, :country %>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<%= submit "Change address" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
|
@ -4,6 +4,7 @@
|
||||||
<%= if @current_user do %>
|
<%= if @current_user do %>
|
||||||
<li>Logged in as <%= @current_user.username %></li>
|
<li>Logged in as <%= @current_user.username %></li>
|
||||||
<li><%= link "Settings", to: Routes.user_settings_path(@conn, :edit) %></li>
|
<li><%= link "Settings", to: Routes.user_settings_path(@conn, :edit) %></li>
|
||||||
|
<li><%= link "Billing", to: Routes.billing_path(@conn, :index) %></li>
|
||||||
<li><%= link "Log out", to: Routes.user_session_path(@conn, :delete), method: :delete %></li>
|
<li><%= link "Log out", to: Routes.user_session_path(@conn, :delete), method: :delete %></li>
|
||||||
<% else %>
|
<% else %>
|
||||||
<li><%= link "Log in", to: Routes.user_session_path(@conn, :new) %></li>
|
<li><%= link "Log in", to: Routes.user_session_path(@conn, :new) %></li>
|
||||||
|
|
3
lib/recycledcloud_web/views/billing_view.ex
Normal file
3
lib/recycledcloud_web/views/billing_view.ex
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
defmodule RecycledCloudWeb.BillingView do
|
||||||
|
use RecycledCloudWeb, :view
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
defmodule RecycledCloud.Repo.Migrations.AddUserPartnerId do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table(:users) do
|
||||||
|
add :partner_id, :integer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -20,6 +20,10 @@ input, textarea {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[readonly] {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
color: #000;
|
color: #000;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
|
Loading…
Reference in a new issue