defmodule Meta.Billing.Partner do alias Meta.Accounts.User alias Meta.Billing.Partner alias Meta.Odoo alias Meta.Repo import Ecto.Changeset use Ecto.Schema @address_fields [:display_name, :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 :display_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 fields = ["id", "name", "email", "country_id", "display_name"] ++ @address_fields result = Odoo.query([ "res.partner", "search_read", [[["id", "=", id]]], %{"fields" => 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