simplify task api
All checks were successful
Build and Publish / build-release (push) Successful in 1m23s

This commit is contained in:
2026-04-17 11:42:19 -05:00
parent 202538e844
commit 01ad2270bc
13 changed files with 320 additions and 301 deletions

View File

@@ -30,8 +30,6 @@ defmodule WorkloadService.Aggregates.Task do
defstruct [
:id,
:application_id,
:provider_id,
:provider_name,
:task_info,
:submission,
:attachments,
@@ -44,9 +42,7 @@ defmodule WorkloadService.Aggregates.Task do
%WorkloadService.Events.TaskCreated{
id: cmd.id,
application_id: cmd.application_id,
provider_id: cmd.provider_id,
provider_name: cmd.provider_name,
task_info: cmd.task_info || %{},
task_info: cmd.task_info,
attachments: cmd.attachments || []
}
end
@@ -71,9 +67,9 @@ defmodule WorkloadService.Aggregates.Task do
end
@impl Aggregate
def execute(%__MODULE__{status: "draft"}, %ApproveSubmission{}) do
def execute(%__MODULE__{id: id, status: "draft"}, %ApproveSubmission{}) do
%WorkloadService.Events.SubmissionApproved{
id: nil
id: id
}
end
@@ -101,8 +97,6 @@ defmodule WorkloadService.Aggregates.Task do
agg
| id: e.id,
application_id: e.application_id,
provider_id: e.provider_id,
provider_name: e.provider_name,
task_info: e.task_info,
attachments: e.attachments,
status: "created",

View File

@@ -8,7 +8,7 @@ defmodule WorkloadService.Application do
children = [
WorkloadService.CommandedApp,
WorkloadService.Consumers.QuoteRequestedConsumer,
WorkloadService.Consumers.SolicitationRequestedConsumer,
# WorkloadService.Consumers.SolicitationRequestedConsumer,
WorkloadService.Projectors.TaskProjector,
WorkloadService.Repo,
WorkloadServiceWeb.Telemetry,

View File

@@ -8,7 +8,7 @@ defmodule WorkloadService.Commands.QuoteTask do
Command to create a new quote task.
"""
@derive Jason.Encoder
defstruct [:id, :application_id, :provider_id, :provider_name, :task_info, :attachments]
defstruct [:id, :application_id, :task_info, :attachments]
def new(attrs) do
struct(__MODULE__, attrs)

View File

@@ -8,7 +8,7 @@ defmodule WorkloadService.Commands.SolicitationTask do
Command to create a new solicitation task.
"""
@derive Jason.Encoder
defstruct [:id, :application_id, :provider_id, :provider_name, :task_info, :attachments]
defstruct [:id, :application_id, :task_info, :attachments]
def new(attrs) do
struct(__MODULE__, attrs)

View File

@@ -52,26 +52,22 @@ defmodule WorkloadService.Consumers.QuoteRequestedConsumer do
defp handle_event(
%{
"id" => application_id,
"org_id" => org_id,
"id" => %{"org_id" => org_id} = application_id,
"provider_id" => provider_id,
"policy_type" => policy_type
"policy_details" => policy_details,
"applicant_info" => applicant_info
} = event
) do
task_id = WorkloadService.Aggregates.TaskId.new(org_id, "quote", Ecto.UUID.generate())
command = %QuoteTask.CreateTask{
id: task_id,
application_id: id,
provider_id: provider_id,
provider_name: Map.get(event, "provider_name", ""),
application_id: application_id,
task_info: %{
"policy_type" => policy_type,
"provider_email" => Map.get(event, "provider_email"),
"applicant_info" => Map.get(event, "applicant_info", %{}),
"car_details" => Map.get(event, "car_details", %{}),
"building_details" => Map.get(event, "building_details", %{}),
"life_details" => Map.get(event, "life_details", %{})
"provider_id" => provider_id,
"applicant_info" => applicant_info,
"policy_details" => policy_details,
"provider_email" => Map.get(event, "provider_email")
}
}

View File

@@ -1,137 +1,137 @@
defmodule WorkloadService.Consumers.SolicitationRequestedConsumer do
use GenServer
require Logger
# defmodule WorkloadService.Consumers.SolicitationRequestedConsumer do
# use GenServer
# require Logger
alias WorkloadService.CommandedApp
alias WorkloadService.Commands.SolicitationTask
# alias WorkloadService.CommandedApp
# alias WorkloadService.Commands.SolicitationTask
@exchange "workload_service.events.solicitation_requested"
@queue "workload_service.solicitation_requested"
@routing_key "solicitation.requested"
# @exchange "workload_service.events.solicitation_requested"
# @queue "workload_service.solicitation_requested"
# @routing_key "solicitation.requested"
@provider_service_url "http://localhost:4002"
@solicitation_service_url "http://localhost:8081"
# @provider_service_url "http://localhost:4002"
# @solicitation_service_url "http://localhost:8081"
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end
# def start_link(opts \\ []) do
# GenServer.start_link(__MODULE__, opts, name: __MODULE__)
# end
def init(_opts) do
{:ok, conn} = AMQP.Connection.open(amqp_url())
{:ok, channel} = AMQP.Channel.open(conn)
# def init(_opts) do
# {:ok, conn} = AMQP.Connection.open(amqp_url())
# {:ok, channel} = AMQP.Channel.open(conn)
AMQP.Queue.declare(channel, @queue, durable: true)
AMQP.Queue.bind(channel, @queue, @exchange, routing_key: @routing_key)
{:ok, _tag} = AMQP.Basic.consume(channel, @queue)
# AMQP.Queue.declare(channel, @queue, durable: true)
# AMQP.Queue.bind(channel, @queue, @exchange, routing_key: @routing_key)
# {:ok, _tag} = AMQP.Basic.consume(channel, @queue)
Logger.info("SolicitationRequestedConsumer started, listening on #{@queue}")
# Logger.info("SolicitationRequestedConsumer started, listening on #{@queue}")
{:ok, %{channel: channel}}
end
# {:ok, %{channel: channel}}
# end
def handle_info({:basic_consume_ok, _}, state), do: {:noreply, state}
def handle_info({:basic_cancel, _}, state), do: {:stop, :normal, state}
def handle_info({:basic_cancel_ok, _}, state), do: {:noreply, state}
# def handle_info({:basic_consume_ok, _}, state), do: {:noreply, state}
# def handle_info({:basic_cancel, _}, state), do: {:stop, :normal, state}
# def handle_info({:basic_cancel_ok, _}, state), do: {:noreply, state}
def handle_info({:basic_deliver, payload, meta}, state) do
case process(payload) do
:ok ->
AMQP.Basic.ack(state.channel, meta.delivery_tag)
# def handle_info({:basic_deliver, payload, meta}, state) do
# case process(payload) do
# :ok ->
# AMQP.Basic.ack(state.channel, meta.delivery_tag)
{:error, reason} ->
Logger.error("SolicitationRequestedConsumer: failed to process: #{inspect(reason)}")
AMQP.Basic.reject(state.channel, meta.delivery_tag, requeue: false)
end
# {:error, reason} ->
# Logger.error("SolicitationRequestedConsumer: failed to process: #{inspect(reason)}")
# AMQP.Basic.reject(state.channel, meta.delivery_tag, requeue: false)
# end
{:noreply, state}
end
# {:noreply, state}
# end
defp process(payload) do
with {:ok, event} <- Jason.decode(payload),
{:ok, provider} <- get_provider(event["provider_id"]),
{:ok, template} <- get_active_template(provider, event["policy_type"]),
{:ok, result} <- generate_solicitation(event, template),
:ok <- create_task(event, result) do
:ok
end
end
# defp process(payload) do
# with {:ok, event} <- Jason.decode(payload),
# {:ok, provider} <- get_provider(event["provider_id"]),
# {:ok, template} <- get_active_template(provider, event["policy_type"]),
# {:ok, result} <- generate_solicitation(event, template),
# :ok <- create_task(event, result) do
# :ok
# end
# end
defp get_provider(provider_id) do
url = "#{@provider_service_url}/api/v1/providers/#{provider_id}"
# defp get_provider(provider_id) do
# url = "#{@provider_service_url}/api/v1/providers/#{provider_id}"
case Req.get(url) do
{:ok, %{status: 200, body: %{"data" => provider}}} -> {:ok, provider}
{:ok, %{status: 404}} -> {:error, :provider_not_found}
{:error, reason} -> {:error, reason}
end
end
# case Req.get(url) do
# {:ok, %{status: 200, body: %{"data" => provider}}} -> {:ok, provider}
# {:ok, %{status: 404}} -> {:error, :provider_not_found}
# {:error, reason} -> {:error, reason}
# end
# end
defp get_active_template(provider, policy_type) do
templates = get_in(provider, ["templates", policy_type]) || []
default_id = get_in(provider, ["default_templates", policy_type])
# defp get_active_template(provider, policy_type) do
# templates = get_in(provider, ["templates", policy_type]) || []
# default_id = get_in(provider, ["default_templates", policy_type])
template =
if default_id do
Enum.find(templates, &(&1["template_id"] == default_id))
else
Enum.find(templates, &(&1["active"] == true))
end
# template =
# if default_id do
# Enum.find(templates, &(&1["template_id"] == default_id))
# else
# Enum.find(templates, &(&1["active"] == true))
# end
case template do
nil -> {:error, :no_active_template}
t -> {:ok, t}
end
end
# case template do
# nil -> {:error, :no_active_template}
# t -> {:ok, t}
# end
# end
defp generate_solicitation(event, template) do
url = "#{@solicitation_service_url}/api/solicitations/generate"
# defp generate_solicitation(event, template) do
# url = "#{@solicitation_service_url}/api/solicitations/generate"
body = %{
org_id: event["org_id"],
id: event["id"],
template_document_url: template["document_url"],
fields: event["fields"] || %{}
}
# body = %{
# org_id: event["org_id"],
# id: event["id"],
# template_document_url: template["document_url"],
# fields: event["fields"] || %{}
# }
case Req.post(url, json: body) do
{:ok, %{status: 200, body: result}} ->
{:ok, result}
# case Req.post(url, json: body) do
# {:ok, %{status: 200, body: result}} ->
# {:ok, result}
{:ok, %{status: status, body: body}} ->
{:error, "solicitation_service returned #{status}: #{inspect(body)}"}
# {:ok, %{status: status, body: body}} ->
# {:error, "solicitation_service returned #{status}: #{inspect(body)}"}
{:error, reason} ->
{:error, reason}
end
end
# {:error, reason} ->
# {:error, reason}
# end
# end
defp create_task(event, result) do
org_id = event["org_id"]
task_id = WorkloadService.Aggregates.TaskId.new(org_id, "solicitation", Ecto.UUID.generate())
# defp create_task(event, result) do
# org_id = event["org_id"]
# task_id = WorkloadService.Aggregates.TaskId.new(org_id, "solicitation", Ecto.UUID.generate())
command = %SolicitationTask.CreateTask{
id: task_id,
application_id: event["id"],
provider_id: event["provider_id"],
provider_name: event["provider_name"] || "",
task_info: %{
"quote" => event["quote"],
"plan" => event["plan"]
},
attachments: [result["document_url"]] |> Enum.filter(& &1)
}
# command = %SolicitationTask.CreateTask{
# id: task_id,
# application_id: event["id"],
# provider_id: event["provider_id"],
# provider_name: event["provider_name"] || "",
# task_info: %{
# "quote" => event["quote"],
# "plan" => event["plan"]
# },
# attachments: [result["document_url"]] |> Enum.filter(& &1)
# }
case CommandedApp.dispatch(command) do
:ok ->
Logger.info("SolicitationRequestedConsumer: created task #{task_id}")
:ok
# case CommandedApp.dispatch(command) do
# :ok ->
# Logger.info("SolicitationRequestedConsumer: created task #{task_id}")
# :ok
{:error, reason} ->
{:error, reason}
end
end
# {:error, reason} ->
# {:error, reason}
# end
# end
defp amqp_url do
Application.get_env(:workload_service, :amqp_url, "amqp://guest:guest@localhost:5672")
end
end
# defp amqp_url do
# Application.get_env(:workload_service, :amqp_url, "amqp://guest:guest@localhost:5672")
# end
# end

View File

@@ -9,7 +9,7 @@ defmodule WorkloadService.Events do
ID format: "org_id:type:task_id" (e.g., "test:quote:uuid") - TaskId struct
"""
@derive Jason.Encoder
defstruct [:id, :application_id, :provider_id, :provider_name, :task_info, :attachments]
defstruct [:id, :application_id, :task_info, :attachments]
end
defmodule SubmissionUpdated do
@@ -36,12 +36,4 @@ defmodule WorkloadService.Events do
@derive Jason.Encoder
defstruct [:id, :completed_by]
end
defmodule QuoteAccepted do
@moduledoc """
Emitted when a quote is accepted - triggers solicitation generation.
"""
@derive Jason.Encoder
defstruct [:id, :provider_id, :quote_id, :plan_id]
end
end
end

View File

@@ -8,15 +8,13 @@ defmodule WorkloadService.Projections.Task do
import Ecto.Changeset
@derive {Flop.Schema,
filterable: [:status, :org_id, :application_id, :provider_id],
filterable: [:status, :org_id, :application_id],
sortable: [:inserted_at, :updated_at, :status]}
@primary_key {:id, :string, []}
schema "tasks" do
field(:org_id, :string)
field(:application_id, :string)
field(:provider_id, :string)
field(:provider_name, :string)
field(:task_info, :map)
field(:submission, :map)
field(:attachments, {:array, :string})
@@ -40,8 +38,6 @@ defmodule WorkloadService.Projections.Task do
:id,
:org_id,
:application_id,
:provider_id,
:provider_name,
:task_info,
:submission,
:attachments,
@@ -52,8 +48,6 @@ defmodule WorkloadService.Projections.Task do
:id,
:org_id,
:application_id,
:provider_id,
:provider_name,
:status
])
|> validate_inclusion(:status, @statuses)

View File

@@ -17,8 +17,6 @@ defmodule WorkloadService.Projectors.TaskProjector do
id: to_string(e.id),
org_id: org_id,
application_id: e.application_id,
provider_id: e.provider_id,
provider_name: e.provider_name,
task_info: e.task_info,
attachments: e.attachments || [],
status: "created"