Files
policy-service/lib/policy_service/projectors/policy_projector.ex
HaimKortovich 5037bc3632
Some checks are pending
Build and Publish / build-release (push) Waiting to run
wip
2026-04-13 15:30:31 -05:00

145 lines
4.3 KiB
Elixir

defmodule PolicyService.Projectors.PolicyProjector do
use Commanded.Projections.Ecto,
application: PolicyService.CommandedApp,
repo: PolicyService.Repo,
name: "PolicyApplicationProjection",
consistency: :strong
alias PolicyService.Events.Policy.{
PolicyApplicationSubmitted,
ProviderQuoteReceived,
AllQuotesReceived,
QuoteAccepted,
SolicitationSent,
PolicyIssued
}
alias PolicyService.Projections.PolicyApplication
alias PolicyService.Aggregates.PolicyId
import Ecto.Query
project(%PolicyApplicationSubmitted{} = e, _meta, fn multi ->
%{policy_type: policy_type, application_id: application_id, org_id: org_id} = e.id
Ecto.Multi.insert(multi, :policy_application, %PolicyApplication{
id: to_string(PolicyId.new(org_id, policy_type, application_id)),
application_id: application_id,
org_id: org_id,
submitted_by: e.submitted_by,
policy_type: policy_type,
applicant_info: atomize(e.applicant_info),
policy_details: atomize(e.policy_details),
selected_providers: Enum.map(e.selected_providers, & &1["provider_id"]),
quotes: %{},
status: "quote_requested",
submitted_at: parse_datetime(e.submitted_at)
})
end)
project(%ProviderQuoteReceived{} = e, _meta, fn multi ->
multi
|> Ecto.Multi.run(:fetch, fn repo, _ ->
{:ok, repo.get!(PolicyApplication, to_string(e.id))}
end)
|> Ecto.Multi.update(:policy_application, fn %{fetch: p} ->
quote_data = %{
"quote_id" => e.quote_id,
"provider_id" => e.provider_id,
"valid_until" => e.valid_until,
"received_at" => parse_datetime(e.received_at),
"plans" => e.plans || []
}
Ecto.Changeset.change(p, quotes: Map.put(p.quotes, e.provider_id, quote_data))
end)
end)
project(%AllQuotesReceived{} = e, _meta, fn multi ->
multi
|> Ecto.Multi.run(:fetch, fn repo, _ ->
{:ok, repo.get!(PolicyApplication, to_string(e.id))}
end)
|> Ecto.Multi.update(:policy_application, fn %{fetch: p} ->
Ecto.Changeset.change(p, status: "quotes_received")
end)
end)
project(%QuoteAccepted{} = e, _meta, fn multi ->
multi
|> Ecto.Multi.run(:fetch, fn repo, _ ->
{:ok, repo.get!(PolicyApplication, to_string(e.id))}
end)
|> Ecto.Multi.update(:policy_application, fn %{fetch: p} ->
Ecto.Changeset.change(p,
accepted_quote_id: e.quote.quote_id,
accepted_plan_id: e.plan.plan_id,
accepted_provider_id: e.provider.id,
accepted_at: parse_datetime(e.accepted_at),
status: "solicitation_sent"
)
end)
end)
project(%SolicitationSent{} = e, _meta, fn multi ->
multi
|> Ecto.Multi.run(:fetch, fn repo, _ ->
{:ok, repo.get!(PolicyApplication, to_string(e.id))}
end)
|> Ecto.Multi.update(:policy_application, fn %{fetch: p} ->
Ecto.Changeset.change(p,
solicitation_id: e.solicitation_id,
solicitation_s3_key: e.s3_key,
solicitation_sent_at: parse_datetime(e.sent_at)
)
end)
end)
project(%PolicyIssued{} = e, _meta, fn multi ->
multi
|> Ecto.Multi.run(:fetch, fn repo, _ ->
{:ok, repo.get!(PolicyApplication, to_string(e.id))}
end)
|> Ecto.Multi.update(:policy_application, fn %{fetch: p} ->
Ecto.Changeset.change(p,
policy_number: e.policy_number,
effective_date: parse_date(e.effective_date),
expiry_date: parse_date(e.expiry_date),
issued_at: parse_datetime(e.issued_at),
status: "issued"
)
end)
end)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
defp atomize(nil), do: nil
defp atomize(map) when is_map(map) do
Map.new(map, fn {k, v} ->
{if(is_atom(k), do: Atom.to_string(k), else: k), v}
end)
end
defp parse_datetime(nil), do: nil
defp parse_datetime(%DateTime{} = dt), do: dt
defp parse_datetime(str) when is_binary(str) do
case DateTime.from_iso8601(str) do
{:ok, dt, _} -> dt
_ -> nil
end
end
defp parse_date(nil), do: nil
defp parse_date(%Date{} = d), do: d
defp parse_date(str) when is_binary(str) do
case Date.from_iso8601(str) do
{:ok, d} -> d
_ -> nil
end
end
end