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_pw: "admin",
|
||||
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 :email, :string, virtual: true
|
||||
field :confirmed_at, :naive_datetime
|
||||
field :partner_id, :integer
|
||||
|
||||
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
|
||||
post "/users/settings/keys/new", UserKeysController, :new
|
||||
get "/users/settings/keys/:key_id/delete", UserKeysController, :delete
|
||||
get "/billing", BillingController, :index
|
||||
post "/billing/partner/update", BillingController, :update
|
||||
end
|
||||
|
||||
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 %>
|
||||
<li>Logged in as <%= @current_user.username %></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>
|
||||
<% else %>
|
||||
<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;
|
||||
}
|
||||
|
||||
input[readonly] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
button {
|
||||
color: #000;
|
||||
padding: 5px;
|
||||
|
|
Loading…
Reference in a new issue