simplify task api
All checks were successful
Build and Publish / build-release (push) Successful in 1m23s
All checks were successful
Build and Publish / build-release (push) Successful in 1m23s
This commit is contained in:
@@ -30,8 +30,6 @@ defmodule WorkloadService.Aggregates.Task do
|
|||||||
defstruct [
|
defstruct [
|
||||||
:id,
|
:id,
|
||||||
:application_id,
|
:application_id,
|
||||||
:provider_id,
|
|
||||||
:provider_name,
|
|
||||||
:task_info,
|
:task_info,
|
||||||
:submission,
|
:submission,
|
||||||
:attachments,
|
:attachments,
|
||||||
@@ -44,9 +42,7 @@ defmodule WorkloadService.Aggregates.Task do
|
|||||||
%WorkloadService.Events.TaskCreated{
|
%WorkloadService.Events.TaskCreated{
|
||||||
id: cmd.id,
|
id: cmd.id,
|
||||||
application_id: cmd.application_id,
|
application_id: cmd.application_id,
|
||||||
provider_id: cmd.provider_id,
|
task_info: cmd.task_info,
|
||||||
provider_name: cmd.provider_name,
|
|
||||||
task_info: cmd.task_info || %{},
|
|
||||||
attachments: cmd.attachments || []
|
attachments: cmd.attachments || []
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -71,9 +67,9 @@ defmodule WorkloadService.Aggregates.Task do
|
|||||||
end
|
end
|
||||||
|
|
||||||
@impl Aggregate
|
@impl Aggregate
|
||||||
def execute(%__MODULE__{status: "draft"}, %ApproveSubmission{}) do
|
def execute(%__MODULE__{id: id, status: "draft"}, %ApproveSubmission{}) do
|
||||||
%WorkloadService.Events.SubmissionApproved{
|
%WorkloadService.Events.SubmissionApproved{
|
||||||
id: nil
|
id: id
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -101,8 +97,6 @@ defmodule WorkloadService.Aggregates.Task do
|
|||||||
agg
|
agg
|
||||||
| id: e.id,
|
| id: e.id,
|
||||||
application_id: e.application_id,
|
application_id: e.application_id,
|
||||||
provider_id: e.provider_id,
|
|
||||||
provider_name: e.provider_name,
|
|
||||||
task_info: e.task_info,
|
task_info: e.task_info,
|
||||||
attachments: e.attachments,
|
attachments: e.attachments,
|
||||||
status: "created",
|
status: "created",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ defmodule WorkloadService.Application do
|
|||||||
children = [
|
children = [
|
||||||
WorkloadService.CommandedApp,
|
WorkloadService.CommandedApp,
|
||||||
WorkloadService.Consumers.QuoteRequestedConsumer,
|
WorkloadService.Consumers.QuoteRequestedConsumer,
|
||||||
WorkloadService.Consumers.SolicitationRequestedConsumer,
|
# WorkloadService.Consumers.SolicitationRequestedConsumer,
|
||||||
WorkloadService.Projectors.TaskProjector,
|
WorkloadService.Projectors.TaskProjector,
|
||||||
WorkloadService.Repo,
|
WorkloadService.Repo,
|
||||||
WorkloadServiceWeb.Telemetry,
|
WorkloadServiceWeb.Telemetry,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ defmodule WorkloadService.Commands.QuoteTask do
|
|||||||
Command to create a new quote task.
|
Command to create a new quote task.
|
||||||
"""
|
"""
|
||||||
@derive Jason.Encoder
|
@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
|
def new(attrs) do
|
||||||
struct(__MODULE__, attrs)
|
struct(__MODULE__, attrs)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ defmodule WorkloadService.Commands.SolicitationTask do
|
|||||||
Command to create a new solicitation task.
|
Command to create a new solicitation task.
|
||||||
"""
|
"""
|
||||||
@derive Jason.Encoder
|
@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
|
def new(attrs) do
|
||||||
struct(__MODULE__, attrs)
|
struct(__MODULE__, attrs)
|
||||||
|
|||||||
@@ -52,26 +52,22 @@ defmodule WorkloadService.Consumers.QuoteRequestedConsumer do
|
|||||||
|
|
||||||
defp handle_event(
|
defp handle_event(
|
||||||
%{
|
%{
|
||||||
"id" => application_id,
|
"id" => %{"org_id" => org_id} = application_id,
|
||||||
"org_id" => org_id,
|
|
||||||
"provider_id" => provider_id,
|
"provider_id" => provider_id,
|
||||||
"policy_type" => policy_type
|
"policy_details" => policy_details,
|
||||||
|
"applicant_info" => applicant_info
|
||||||
} = event
|
} = event
|
||||||
) do
|
) do
|
||||||
task_id = WorkloadService.Aggregates.TaskId.new(org_id, "quote", Ecto.UUID.generate())
|
task_id = WorkloadService.Aggregates.TaskId.new(org_id, "quote", Ecto.UUID.generate())
|
||||||
|
|
||||||
command = %QuoteTask.CreateTask{
|
command = %QuoteTask.CreateTask{
|
||||||
id: task_id,
|
id: task_id,
|
||||||
application_id: id,
|
application_id: application_id,
|
||||||
provider_id: provider_id,
|
|
||||||
provider_name: Map.get(event, "provider_name", ""),
|
|
||||||
task_info: %{
|
task_info: %{
|
||||||
"policy_type" => policy_type,
|
"provider_id" => provider_id,
|
||||||
"provider_email" => Map.get(event, "provider_email"),
|
"applicant_info" => applicant_info,
|
||||||
"applicant_info" => Map.get(event, "applicant_info", %{}),
|
"policy_details" => policy_details,
|
||||||
"car_details" => Map.get(event, "car_details", %{}),
|
"provider_email" => Map.get(event, "provider_email")
|
||||||
"building_details" => Map.get(event, "building_details", %{}),
|
|
||||||
"life_details" => Map.get(event, "life_details", %{})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,137 +1,137 @@
|
|||||||
defmodule WorkloadService.Consumers.SolicitationRequestedConsumer do
|
# defmodule WorkloadService.Consumers.SolicitationRequestedConsumer do
|
||||||
use GenServer
|
# use GenServer
|
||||||
require Logger
|
# require Logger
|
||||||
|
|
||||||
alias WorkloadService.CommandedApp
|
# alias WorkloadService.CommandedApp
|
||||||
alias WorkloadService.Commands.SolicitationTask
|
# alias WorkloadService.Commands.SolicitationTask
|
||||||
|
|
||||||
@exchange "workload_service.events.solicitation_requested"
|
# @exchange "workload_service.events.solicitation_requested"
|
||||||
@queue "workload_service.solicitation_requested"
|
# @queue "workload_service.solicitation_requested"
|
||||||
@routing_key "solicitation.requested"
|
# @routing_key "solicitation.requested"
|
||||||
|
|
||||||
@provider_service_url "http://localhost:4002"
|
# @provider_service_url "http://localhost:4002"
|
||||||
@solicitation_service_url "http://localhost:8081"
|
# @solicitation_service_url "http://localhost:8081"
|
||||||
|
|
||||||
def start_link(opts \\ []) do
|
# def start_link(opts \\ []) do
|
||||||
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
# GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
||||||
end
|
# end
|
||||||
|
|
||||||
def init(_opts) do
|
# def init(_opts) do
|
||||||
{:ok, conn} = AMQP.Connection.open(amqp_url())
|
# {:ok, conn} = AMQP.Connection.open(amqp_url())
|
||||||
{:ok, channel} = AMQP.Channel.open(conn)
|
# {:ok, channel} = AMQP.Channel.open(conn)
|
||||||
|
|
||||||
AMQP.Queue.declare(channel, @queue, durable: true)
|
# AMQP.Queue.declare(channel, @queue, durable: true)
|
||||||
AMQP.Queue.bind(channel, @queue, @exchange, routing_key: @routing_key)
|
# AMQP.Queue.bind(channel, @queue, @exchange, routing_key: @routing_key)
|
||||||
{:ok, _tag} = AMQP.Basic.consume(channel, @queue)
|
# {:ok, _tag} = AMQP.Basic.consume(channel, @queue)
|
||||||
|
|
||||||
Logger.info("SolicitationRequestedConsumer started, listening on #{@queue}")
|
# Logger.info("SolicitationRequestedConsumer started, listening on #{@queue}")
|
||||||
|
|
||||||
{:ok, %{channel: channel}}
|
# {:ok, %{channel: channel}}
|
||||||
end
|
# end
|
||||||
|
|
||||||
def handle_info({:basic_consume_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, _}, state), do: {:stop, :normal, state}
|
||||||
def handle_info({:basic_cancel_ok, _}, state), do: {:noreply, state}
|
# def handle_info({:basic_cancel_ok, _}, state), do: {:noreply, state}
|
||||||
|
|
||||||
def handle_info({:basic_deliver, payload, meta}, state) do
|
# def handle_info({:basic_deliver, payload, meta}, state) do
|
||||||
case process(payload) do
|
# case process(payload) do
|
||||||
:ok ->
|
# :ok ->
|
||||||
AMQP.Basic.ack(state.channel, meta.delivery_tag)
|
# AMQP.Basic.ack(state.channel, meta.delivery_tag)
|
||||||
|
|
||||||
{:error, reason} ->
|
# {:error, reason} ->
|
||||||
Logger.error("SolicitationRequestedConsumer: failed to process: #{inspect(reason)}")
|
# Logger.error("SolicitationRequestedConsumer: failed to process: #{inspect(reason)}")
|
||||||
AMQP.Basic.reject(state.channel, meta.delivery_tag, requeue: false)
|
# AMQP.Basic.reject(state.channel, meta.delivery_tag, requeue: false)
|
||||||
end
|
# end
|
||||||
|
|
||||||
{:noreply, state}
|
# {:noreply, state}
|
||||||
end
|
# end
|
||||||
|
|
||||||
defp process(payload) do
|
# defp process(payload) do
|
||||||
with {:ok, event} <- Jason.decode(payload),
|
# with {:ok, event} <- Jason.decode(payload),
|
||||||
{:ok, provider} <- get_provider(event["provider_id"]),
|
# {:ok, provider} <- get_provider(event["provider_id"]),
|
||||||
{:ok, template} <- get_active_template(provider, event["policy_type"]),
|
# {:ok, template} <- get_active_template(provider, event["policy_type"]),
|
||||||
{:ok, result} <- generate_solicitation(event, template),
|
# {:ok, result} <- generate_solicitation(event, template),
|
||||||
:ok <- create_task(event, result) do
|
# :ok <- create_task(event, result) do
|
||||||
:ok
|
# :ok
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|
||||||
defp get_provider(provider_id) do
|
# defp get_provider(provider_id) do
|
||||||
url = "#{@provider_service_url}/api/v1/providers/#{provider_id}"
|
# url = "#{@provider_service_url}/api/v1/providers/#{provider_id}"
|
||||||
|
|
||||||
case Req.get(url) do
|
# case Req.get(url) do
|
||||||
{:ok, %{status: 200, body: %{"data" => provider}}} -> {:ok, provider}
|
# {:ok, %{status: 200, body: %{"data" => provider}}} -> {:ok, provider}
|
||||||
{:ok, %{status: 404}} -> {:error, :provider_not_found}
|
# {:ok, %{status: 404}} -> {:error, :provider_not_found}
|
||||||
{:error, reason} -> {:error, reason}
|
# {:error, reason} -> {:error, reason}
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|
||||||
defp get_active_template(provider, policy_type) do
|
# defp get_active_template(provider, policy_type) do
|
||||||
templates = get_in(provider, ["templates", policy_type]) || []
|
# templates = get_in(provider, ["templates", policy_type]) || []
|
||||||
default_id = get_in(provider, ["default_templates", policy_type])
|
# default_id = get_in(provider, ["default_templates", policy_type])
|
||||||
|
|
||||||
template =
|
# template =
|
||||||
if default_id do
|
# if default_id do
|
||||||
Enum.find(templates, &(&1["template_id"] == default_id))
|
# Enum.find(templates, &(&1["template_id"] == default_id))
|
||||||
else
|
# else
|
||||||
Enum.find(templates, &(&1["active"] == true))
|
# Enum.find(templates, &(&1["active"] == true))
|
||||||
end
|
# end
|
||||||
|
|
||||||
case template do
|
# case template do
|
||||||
nil -> {:error, :no_active_template}
|
# nil -> {:error, :no_active_template}
|
||||||
t -> {:ok, t}
|
# t -> {:ok, t}
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|
||||||
defp generate_solicitation(event, template) do
|
# defp generate_solicitation(event, template) do
|
||||||
url = "#{@solicitation_service_url}/api/solicitations/generate"
|
# url = "#{@solicitation_service_url}/api/solicitations/generate"
|
||||||
|
|
||||||
body = %{
|
# body = %{
|
||||||
org_id: event["org_id"],
|
# org_id: event["org_id"],
|
||||||
id: event["id"],
|
# id: event["id"],
|
||||||
template_document_url: template["document_url"],
|
# template_document_url: template["document_url"],
|
||||||
fields: event["fields"] || %{}
|
# fields: event["fields"] || %{}
|
||||||
}
|
# }
|
||||||
|
|
||||||
case Req.post(url, json: body) do
|
# case Req.post(url, json: body) do
|
||||||
{:ok, %{status: 200, body: result}} ->
|
# {:ok, %{status: 200, body: result}} ->
|
||||||
{:ok, result}
|
# {:ok, result}
|
||||||
|
|
||||||
{:ok, %{status: status, body: body}} ->
|
# {:ok, %{status: status, body: body}} ->
|
||||||
{:error, "solicitation_service returned #{status}: #{inspect(body)}"}
|
# {:error, "solicitation_service returned #{status}: #{inspect(body)}"}
|
||||||
|
|
||||||
{:error, reason} ->
|
# {:error, reason} ->
|
||||||
{:error, reason}
|
# {:error, reason}
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|
||||||
defp create_task(event, result) do
|
# defp create_task(event, result) do
|
||||||
org_id = event["org_id"]
|
# org_id = event["org_id"]
|
||||||
task_id = WorkloadService.Aggregates.TaskId.new(org_id, "solicitation", Ecto.UUID.generate())
|
# task_id = WorkloadService.Aggregates.TaskId.new(org_id, "solicitation", Ecto.UUID.generate())
|
||||||
|
|
||||||
command = %SolicitationTask.CreateTask{
|
# command = %SolicitationTask.CreateTask{
|
||||||
id: task_id,
|
# id: task_id,
|
||||||
application_id: event["id"],
|
# application_id: event["id"],
|
||||||
provider_id: event["provider_id"],
|
# provider_id: event["provider_id"],
|
||||||
provider_name: event["provider_name"] || "",
|
# provider_name: event["provider_name"] || "",
|
||||||
task_info: %{
|
# task_info: %{
|
||||||
"quote" => event["quote"],
|
# "quote" => event["quote"],
|
||||||
"plan" => event["plan"]
|
# "plan" => event["plan"]
|
||||||
},
|
# },
|
||||||
attachments: [result["document_url"]] |> Enum.filter(& &1)
|
# attachments: [result["document_url"]] |> Enum.filter(& &1)
|
||||||
}
|
# }
|
||||||
|
|
||||||
case CommandedApp.dispatch(command) do
|
# case CommandedApp.dispatch(command) do
|
||||||
:ok ->
|
# :ok ->
|
||||||
Logger.info("SolicitationRequestedConsumer: created task #{task_id}")
|
# Logger.info("SolicitationRequestedConsumer: created task #{task_id}")
|
||||||
:ok
|
# :ok
|
||||||
|
|
||||||
{:error, reason} ->
|
# {:error, reason} ->
|
||||||
{:error, reason}
|
# {:error, reason}
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|
||||||
defp amqp_url do
|
# defp amqp_url do
|
||||||
Application.get_env(:workload_service, :amqp_url, "amqp://guest:guest@localhost:5672")
|
# Application.get_env(:workload_service, :amqp_url, "amqp://guest:guest@localhost:5672")
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ defmodule WorkloadService.Events do
|
|||||||
ID format: "org_id:type:task_id" (e.g., "test:quote:uuid") - TaskId struct
|
ID format: "org_id:type:task_id" (e.g., "test:quote:uuid") - TaskId struct
|
||||||
"""
|
"""
|
||||||
@derive Jason.Encoder
|
@derive Jason.Encoder
|
||||||
defstruct [:id, :application_id, :provider_id, :provider_name, :task_info, :attachments]
|
defstruct [:id, :application_id, :task_info, :attachments]
|
||||||
end
|
end
|
||||||
|
|
||||||
defmodule SubmissionUpdated do
|
defmodule SubmissionUpdated do
|
||||||
@@ -36,12 +36,4 @@ defmodule WorkloadService.Events do
|
|||||||
@derive Jason.Encoder
|
@derive Jason.Encoder
|
||||||
defstruct [:id, :completed_by]
|
defstruct [:id, :completed_by]
|
||||||
end
|
end
|
||||||
|
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
|
|
||||||
|
|||||||
@@ -8,15 +8,13 @@ defmodule WorkloadService.Projections.Task do
|
|||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
@derive {Flop.Schema,
|
@derive {Flop.Schema,
|
||||||
filterable: [:status, :org_id, :application_id, :provider_id],
|
filterable: [:status, :org_id, :application_id],
|
||||||
sortable: [:inserted_at, :updated_at, :status]}
|
sortable: [:inserted_at, :updated_at, :status]}
|
||||||
|
|
||||||
@primary_key {:id, :string, []}
|
@primary_key {:id, :string, []}
|
||||||
schema "tasks" do
|
schema "tasks" do
|
||||||
field(:org_id, :string)
|
field(:org_id, :string)
|
||||||
field(:application_id, :string)
|
field(:application_id, :string)
|
||||||
field(:provider_id, :string)
|
|
||||||
field(:provider_name, :string)
|
|
||||||
field(:task_info, :map)
|
field(:task_info, :map)
|
||||||
field(:submission, :map)
|
field(:submission, :map)
|
||||||
field(:attachments, {:array, :string})
|
field(:attachments, {:array, :string})
|
||||||
@@ -40,8 +38,6 @@ defmodule WorkloadService.Projections.Task do
|
|||||||
:id,
|
:id,
|
||||||
:org_id,
|
:org_id,
|
||||||
:application_id,
|
:application_id,
|
||||||
:provider_id,
|
|
||||||
:provider_name,
|
|
||||||
:task_info,
|
:task_info,
|
||||||
:submission,
|
:submission,
|
||||||
:attachments,
|
:attachments,
|
||||||
@@ -52,8 +48,6 @@ defmodule WorkloadService.Projections.Task do
|
|||||||
:id,
|
:id,
|
||||||
:org_id,
|
:org_id,
|
||||||
:application_id,
|
:application_id,
|
||||||
:provider_id,
|
|
||||||
:provider_name,
|
|
||||||
:status
|
:status
|
||||||
])
|
])
|
||||||
|> validate_inclusion(:status, @statuses)
|
|> validate_inclusion(:status, @statuses)
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ defmodule WorkloadService.Projectors.TaskProjector do
|
|||||||
id: to_string(e.id),
|
id: to_string(e.id),
|
||||||
org_id: org_id,
|
org_id: org_id,
|
||||||
application_id: e.application_id,
|
application_id: e.application_id,
|
||||||
provider_id: e.provider_id,
|
|
||||||
provider_name: e.provider_name,
|
|
||||||
task_info: e.task_info,
|
task_info: e.task_info,
|
||||||
attachments: e.attachments || [],
|
attachments: e.attachments || [],
|
||||||
status: "created"
|
status: "created"
|
||||||
|
|||||||
@@ -14,10 +14,8 @@ defmodule WorkloadServiceWeb.TaskController do
|
|||||||
page: [in: :query, type: :integer, required: false, example: 1],
|
page: [in: :query, type: :integer, required: false, example: 1],
|
||||||
page_size: [in: :query, type: :integer, required: false, example: 20],
|
page_size: [in: :query, type: :integer, required: false, example: 20],
|
||||||
status: [in: :query, type: :string, required: false],
|
status: [in: :query, type: :string, required: false],
|
||||||
policy_type: [in: :query, type: :string, required: false],
|
|
||||||
org_id: [in: :query, type: :string, required: false],
|
org_id: [in: :query, type: :string, required: false],
|
||||||
application_id: [in: :query, type: :string, required: false],
|
application_id: [in: :query, type: :string, required: false]
|
||||||
provider_id: [in: :query, type: :string, required: false]
|
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
ok: {"Task list", "application/json", S.TaskListResponse},
|
ok: {"Task list", "application/json", S.TaskListResponse},
|
||||||
@@ -61,20 +59,35 @@ defmodule WorkloadServiceWeb.TaskController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
operation(:respond_to_quote,
|
operation(:submit,
|
||||||
summary: "Record quote response",
|
summary: "Submit task data (quote response or confirm delivery)",
|
||||||
parameters: [
|
parameters: [
|
||||||
id: [in: :path, type: :string, required: true]
|
id: [in: :path, type: :string, required: true]
|
||||||
],
|
],
|
||||||
request_body: {"Quote response", "application/json", S.QuoteResponseRequest, required: true},
|
request_body: {"Task submission", "application/json", S.SubmitRequest, required: true},
|
||||||
responses: [
|
responses: [
|
||||||
ok: {"Quote response recorded", "application/json", S.TaskDetailResponse},
|
ok: {"Task submitted", "application/json", S.TaskDetailResponse},
|
||||||
not_found: {"Not found", "application/json", S.ErrorResponse},
|
not_found: {"Not found", "application/json", S.ErrorResponse},
|
||||||
unprocessable_entity: {"Error", "application/json", S.ErrorResponse}
|
unprocessable_entity: {"Error", "application/json", S.ErrorResponse}
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
def respond_to_quote(conn, %{"id" => id} = params) do
|
def submit(conn, %{"id" => id} = params) do
|
||||||
|
task_type = get_task_type(id)
|
||||||
|
|
||||||
|
case task_type do
|
||||||
|
"quote" ->
|
||||||
|
handle_quote_submit(conn, id, params)
|
||||||
|
|
||||||
|
"solicitation" ->
|
||||||
|
handle_solicitation_submit(conn, id, params)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid task type"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_quote_submit(conn, id, params) do
|
||||||
case Queries.get_task_by_id(id) do
|
case Queries.get_task_by_id(id) do
|
||||||
{:error, :not_found} ->
|
{:error, :not_found} ->
|
||||||
conn |> put_status(:not_found) |> json(%{error: "task not found"})
|
conn |> put_status(:not_found) |> json(%{error: "task not found"})
|
||||||
@@ -86,70 +99,20 @@ defmodule WorkloadServiceWeb.TaskController do
|
|||||||
"quote_id" => params["quote_id"],
|
"quote_id" => params["quote_id"],
|
||||||
"plans" => params["plans"],
|
"plans" => params["plans"],
|
||||||
"valid_until" => params["valid_until"],
|
"valid_until" => params["valid_until"],
|
||||||
"responded_by" => params["responded_by"],
|
"recorded_by" => params["recorded_by"],
|
||||||
"document_data" => params["document_data"]
|
"document_data" => params["document_data"]
|
||||||
},
|
},
|
||||||
attachments: [params["document_url"]] |> Enum.filter(& &1)
|
attachments: List.wrap(params["document_url"])
|
||||||
}
|
}
|
||||||
|
|
||||||
case CommandedApp.dispatch(command) do
|
dispatch_and_respond(conn, id, command)
|
||||||
:ok ->
|
|
||||||
{:ok, task} = Queries.get_task_by_id(id)
|
|
||||||
conn |> put_status(:ok) |> json(%{data: task_detail(task)})
|
|
||||||
|
|
||||||
{:error, reason} ->
|
|
||||||
conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)})
|
|
||||||
end
|
|
||||||
|
|
||||||
{:ok, %{status: "draft"} = _task} ->
|
|
||||||
command = %WorkloadService.Commands.QuoteTask.ApproveSubmission{
|
|
||||||
id: id
|
|
||||||
}
|
|
||||||
|
|
||||||
case CommandedApp.dispatch(command) do
|
|
||||||
:ok ->
|
|
||||||
{:ok, task} = Queries.get_task_by_id(id)
|
|
||||||
conn |> put_status(:ok) |> json(%{data: task_detail(task)})
|
|
||||||
|
|
||||||
{:error, reason} ->
|
|
||||||
conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)})
|
|
||||||
end
|
|
||||||
|
|
||||||
{:ok, %{status: "approved"} = _task} ->
|
|
||||||
command = %WorkloadService.Commands.QuoteTask.CompleteTask{
|
|
||||||
id: id,
|
|
||||||
completed_by: params["completed_by"] || "system"
|
|
||||||
}
|
|
||||||
|
|
||||||
case CommandedApp.dispatch(command) do
|
|
||||||
:ok ->
|
|
||||||
{:ok, task} = Queries.get_task_by_id(id)
|
|
||||||
conn |> put_status(:ok) |> json(%{data: task_detail(task)})
|
|
||||||
|
|
||||||
{:error, reason} ->
|
|
||||||
conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)})
|
|
||||||
end
|
|
||||||
|
|
||||||
{:ok, _task} ->
|
{:ok, _task} ->
|
||||||
conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid state"})
|
conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid state for submit"})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
operation(:confirm_delivery,
|
defp handle_solicitation_submit(conn, id, params) do
|
||||||
summary: "Confirm solicitation delivery",
|
|
||||||
parameters: [
|
|
||||||
id: [in: :path, type: :string, required: true]
|
|
||||||
],
|
|
||||||
request_body:
|
|
||||||
{"Delivery confirmation", "application/json", S.ConfirmDeliveryRequest, required: false},
|
|
||||||
responses: [
|
|
||||||
ok: {"Delivery confirmed", "application/json", S.TaskDetailResponse},
|
|
||||||
not_found: {"Not found", "application/json", S.ErrorResponse},
|
|
||||||
unprocessable_entity: {"Error", "application/json", S.ErrorResponse}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def confirm_delivery(conn, %{"id" => id} = params) do
|
|
||||||
case Queries.get_task_by_id(id) do
|
case Queries.get_task_by_id(id) do
|
||||||
{:error, :not_found} ->
|
{:error, :not_found} ->
|
||||||
conn |> put_status(:not_found) |> json(%{error: "task not found"})
|
conn |> put_status(:not_found) |> json(%{error: "task not found"})
|
||||||
@@ -158,51 +121,122 @@ defmodule WorkloadServiceWeb.TaskController do
|
|||||||
command = %WorkloadService.Commands.SolicitationTask.SubmitResponse{
|
command = %WorkloadService.Commands.SolicitationTask.SubmitResponse{
|
||||||
id: id,
|
id: id,
|
||||||
submission: %{
|
submission: %{
|
||||||
"delivery_confirmed_by" => params["delivery_confirmed_by"] || "system"
|
"recorded_by" => params["recorded_by"] || "system"
|
||||||
},
|
},
|
||||||
attachments: []
|
attachments: []
|
||||||
}
|
}
|
||||||
|
|
||||||
case CommandedApp.dispatch(command) do
|
dispatch_and_respond(conn, id, command)
|
||||||
:ok ->
|
|
||||||
{:ok, task} = Queries.get_task_by_id(id)
|
|
||||||
conn |> put_status(:ok) |> json(%{data: task_detail(task)})
|
|
||||||
|
|
||||||
{:error, reason} ->
|
|
||||||
conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)})
|
|
||||||
end
|
|
||||||
|
|
||||||
{:ok, %{status: "draft"} = _task} ->
|
|
||||||
command = %WorkloadService.Commands.SolicitationTask.ApproveSubmission{
|
|
||||||
id: id
|
|
||||||
}
|
|
||||||
|
|
||||||
case CommandedApp.dispatch(command) do
|
|
||||||
:ok ->
|
|
||||||
{:ok, task} = Queries.get_task_by_id(id)
|
|
||||||
conn |> put_status(:ok) |> json(%{data: task_detail(task)})
|
|
||||||
|
|
||||||
{:error, reason} ->
|
|
||||||
conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)})
|
|
||||||
end
|
|
||||||
|
|
||||||
{:ok, %{status: "approved"} = _task} ->
|
|
||||||
command = %WorkloadService.Commands.SolicitationTask.CompleteTask{
|
|
||||||
id: id,
|
|
||||||
completed_by: params["completed_by"] || "system"
|
|
||||||
}
|
|
||||||
|
|
||||||
case CommandedApp.dispatch(command) do
|
|
||||||
:ok ->
|
|
||||||
{:ok, task} = Queries.get_task_by_id(id)
|
|
||||||
conn |> put_status(:ok) |> json(%{data: task_detail(task)})
|
|
||||||
|
|
||||||
{:error, reason} ->
|
|
||||||
conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)})
|
|
||||||
end
|
|
||||||
|
|
||||||
{:ok, _task} ->
|
{:ok, _task} ->
|
||||||
conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid state"})
|
conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid state for submit"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
operation(:approve,
|
||||||
|
summary: "Approve submission",
|
||||||
|
parameters: [
|
||||||
|
id: [in: :path, type: :string, required: true]
|
||||||
|
],
|
||||||
|
responses: [
|
||||||
|
ok: {"Task approved", "application/json", S.TaskDetailResponse},
|
||||||
|
not_found: {"Not found", "application/json", S.ErrorResponse},
|
||||||
|
unprocessable_entity: {"Error", "application/json", S.ErrorResponse}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def approve(conn, %{"id" => id}) do
|
||||||
|
task_type = get_task_type(id)
|
||||||
|
|
||||||
|
case task_type do
|
||||||
|
"quote" ->
|
||||||
|
handle_approve(conn, id, WorkloadService.Commands.QuoteTask.ApproveSubmission)
|
||||||
|
|
||||||
|
"solicitation" ->
|
||||||
|
handle_approve(conn, id, WorkloadService.Commands.SolicitationTask.ApproveSubmission)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid task type"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_approve(conn, id, command_module) do
|
||||||
|
case Queries.get_task_by_id(id) do
|
||||||
|
{:error, :not_found} ->
|
||||||
|
conn |> put_status(:not_found) |> json(%{error: "task not found"})
|
||||||
|
|
||||||
|
{:ok, %{status: "draft"} = _task} ->
|
||||||
|
command = struct(command_module, id: id)
|
||||||
|
dispatch_and_respond(conn, id, command)
|
||||||
|
|
||||||
|
{:ok, _task} ->
|
||||||
|
conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid state for approve"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
operation(:complete,
|
||||||
|
summary: "Complete task",
|
||||||
|
parameters: [
|
||||||
|
id: [in: :path, type: :string, required: true]
|
||||||
|
],
|
||||||
|
request_body: {"Complete request", "application/json", S.CompleteRequest, required: false},
|
||||||
|
responses: [
|
||||||
|
ok: {"Task completed", "application/json", S.TaskDetailResponse},
|
||||||
|
not_found: {"Not found", "application/json", S.ErrorResponse},
|
||||||
|
unprocessable_entity: {"Error", "application/json", S.ErrorResponse}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def complete(conn, %{"id" => id} = params) do
|
||||||
|
task_type = get_task_type(id)
|
||||||
|
completed_by = params["completed_by"] || "system"
|
||||||
|
|
||||||
|
case task_type do
|
||||||
|
"quote" ->
|
||||||
|
handle_complete(conn, id, completed_by, WorkloadService.Commands.QuoteTask.CompleteTask)
|
||||||
|
|
||||||
|
"solicitation" ->
|
||||||
|
handle_complete(
|
||||||
|
conn,
|
||||||
|
id,
|
||||||
|
completed_by,
|
||||||
|
WorkloadService.Commands.SolicitationTask.CompleteTask
|
||||||
|
)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid task type"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_complete(conn, id, completed_by, command_module) do
|
||||||
|
case Queries.get_task_by_id(id) do
|
||||||
|
{:error, :not_found} ->
|
||||||
|
conn |> put_status(:not_found) |> json(%{error: "task not found"})
|
||||||
|
|
||||||
|
{:ok, %{status: "approved"} = _task} ->
|
||||||
|
command = struct(command_module, id: id, completed_by: completed_by)
|
||||||
|
dispatch_and_respond(conn, id, command)
|
||||||
|
|
||||||
|
{:ok, _task} ->
|
||||||
|
conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid state for complete"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp dispatch_and_respond(conn, id, command) do
|
||||||
|
case CommandedApp.dispatch(command) do
|
||||||
|
:ok ->
|
||||||
|
{:ok, task} = Queries.get_task_by_id(id)
|
||||||
|
conn |> put_status(:ok) |> json(%{data: task_detail(task)})
|
||||||
|
|
||||||
|
{:error, reason} ->
|
||||||
|
conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_task_type(id) do
|
||||||
|
case WorkloadService.Aggregates.TaskId.parse(id) do
|
||||||
|
{:ok, %{type: type}} -> type
|
||||||
|
_ -> "unknown"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -211,8 +245,6 @@ defmodule WorkloadServiceWeb.TaskController do
|
|||||||
id: t.id,
|
id: t.id,
|
||||||
org_id: t.org_id,
|
org_id: t.org_id,
|
||||||
application_id: t.application_id,
|
application_id: t.application_id,
|
||||||
provider_id: t.provider_id,
|
|
||||||
provider_name: t.provider_name,
|
|
||||||
task_info: t.task_info,
|
task_info: t.task_info,
|
||||||
status: t.status,
|
status: t.status,
|
||||||
created_at: t.inserted_at
|
created_at: t.inserted_at
|
||||||
@@ -224,8 +256,6 @@ defmodule WorkloadServiceWeb.TaskController do
|
|||||||
id: t.id,
|
id: t.id,
|
||||||
org_id: t.org_id,
|
org_id: t.org_id,
|
||||||
application_id: t.application_id,
|
application_id: t.application_id,
|
||||||
provider_id: t.provider_id,
|
|
||||||
provider_name: t.provider_name,
|
|
||||||
task_info: t.task_info,
|
task_info: t.task_info,
|
||||||
submission: t.submission,
|
submission: t.submission,
|
||||||
attachments: t.attachments,
|
attachments: t.attachments,
|
||||||
@@ -246,4 +276,4 @@ defmodule WorkloadServiceWeb.TaskController do
|
|||||||
has_prev: meta.has_previous_page?
|
has_prev: meta.has_previous_page?
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ defmodule WorkloadServiceWeb.Router do
|
|||||||
scope "/v1" do
|
scope "/v1" do
|
||||||
get "/tasks", TaskController, :list
|
get "/tasks", TaskController, :list
|
||||||
get "/tasks/:id", TaskController, :show
|
get "/tasks/:id", TaskController, :show
|
||||||
post "/tasks/:id/respond-quote", TaskController, :respond_to_quote
|
post "/tasks/:id/submit", TaskController, :submit
|
||||||
post "/tasks/:id/confirm-delivery", TaskController, :confirm_delivery
|
post "/tasks/:id/approve", TaskController, :approve
|
||||||
|
post "/tasks/:id/complete", TaskController, :complete
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -29,4 +30,4 @@ defmodule WorkloadServiceWeb.Router do
|
|||||||
get "/", OpenApiSpex.Plug.SwaggerUI, path: "/api/openapi"
|
get "/", OpenApiSpex.Plug.SwaggerUI, path: "/api/openapi"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -26,11 +26,40 @@ defmodule WorkloadServiceWeb.Schemas.Task do
|
|||||||
type: :object,
|
type: :object,
|
||||||
properties: %{
|
properties: %{
|
||||||
plan_id: %Schema{type: :string},
|
plan_id: %Schema{type: :string},
|
||||||
plan_name: %Schema{type: :string},
|
name: %Schema{type: :string},
|
||||||
premium: %Schema{type: :number},
|
premium: %Schema{type: :number},
|
||||||
coverage_details: %Schema{type: :string},
|
coverage_details: %Schema{type: :object, additionalProperties: true}
|
||||||
deductible: %Schema{type: :number, nullable: true},
|
}
|
||||||
coverage_limit: %Schema{type: :number, nullable: true}
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
defmodule QuoteSubmission do
|
||||||
|
require OpenApiSpex
|
||||||
|
|
||||||
|
OpenApiSpex.schema(%{
|
||||||
|
title: "QuoteSubmission",
|
||||||
|
type: :object,
|
||||||
|
required: [:recorded_by, :quote_id],
|
||||||
|
properties: %{
|
||||||
|
recorded_by: %Schema{type: :string},
|
||||||
|
quote_id: %Schema{type: :string},
|
||||||
|
valid_until: %Schema{type: :string, format: :date},
|
||||||
|
plans: %Schema{type: :array, items: Plan},
|
||||||
|
document_url: %Schema{type: :string},
|
||||||
|
document_data: %Schema{type: :object, additionalProperties: true}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
defmodule SolicitationSubmission do
|
||||||
|
require OpenApiSpex
|
||||||
|
|
||||||
|
OpenApiSpex.schema(%{
|
||||||
|
title: "SolicitationSubmission",
|
||||||
|
type: :object,
|
||||||
|
required: [:recorded_by],
|
||||||
|
properties: %{
|
||||||
|
recorded_by: %Schema{type: :string}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
@@ -45,8 +74,6 @@ defmodule WorkloadServiceWeb.Schemas.Task do
|
|||||||
id: %Schema{type: :string},
|
id: %Schema{type: :string},
|
||||||
org_id: %Schema{type: :string},
|
org_id: %Schema{type: :string},
|
||||||
application_id: %Schema{type: :string},
|
application_id: %Schema{type: :string},
|
||||||
provider_id: %Schema{type: :string},
|
|
||||||
provider_name: %Schema{type: :string},
|
|
||||||
task_info: %Schema{type: :object},
|
task_info: %Schema{type: :object},
|
||||||
status: %Schema{type: :string, enum: ["created", "draft", "approved", "completed"]},
|
status: %Schema{type: :string, enum: ["created", "draft", "approved", "completed"]},
|
||||||
created_at: %Schema{type: :string, format: :"date-time"}
|
created_at: %Schema{type: :string, format: :"date-time"}
|
||||||
@@ -64,8 +91,6 @@ defmodule WorkloadServiceWeb.Schemas.Task do
|
|||||||
id: %Schema{type: :string},
|
id: %Schema{type: :string},
|
||||||
org_id: %Schema{type: :string},
|
org_id: %Schema{type: :string},
|
||||||
application_id: %Schema{type: :string},
|
application_id: %Schema{type: :string},
|
||||||
provider_id: %Schema{type: :string},
|
|
||||||
provider_name: %Schema{type: :string},
|
|
||||||
task_info: %Schema{type: :object},
|
task_info: %Schema{type: :object},
|
||||||
submission: %Schema{type: :object, nullable: true},
|
submission: %Schema{type: :object, nullable: true},
|
||||||
attachments: %Schema{type: :array, items: %Schema{type: :string}},
|
attachments: %Schema{type: :array, items: %Schema{type: :string}},
|
||||||
@@ -77,32 +102,24 @@ defmodule WorkloadServiceWeb.Schemas.Task do
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
defmodule QuoteResponseRequest do
|
defmodule SubmitRequest do
|
||||||
require OpenApiSpex
|
require OpenApiSpex
|
||||||
|
|
||||||
OpenApiSpex.schema(%{
|
OpenApiSpex.schema(%{
|
||||||
title: "QuoteResponseRequest",
|
title: "SubmitRequest",
|
||||||
type: :object,
|
type: :object,
|
||||||
required: [:quote_id, :document_url],
|
anyOf: [QuoteSubmission, SolicitationSubmission]
|
||||||
properties: %{
|
|
||||||
quote_id: %Schema{type: :string},
|
|
||||||
plans: %Schema{type: :array, items: Plan},
|
|
||||||
valid_until: %Schema{type: :string, format: :date},
|
|
||||||
responded_by: %Schema{type: :string},
|
|
||||||
document_url: %Schema{type: :string},
|
|
||||||
document_data: %Schema{type: :object, additionalProperties: true}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
defmodule ConfirmDeliveryRequest do
|
defmodule CompleteRequest do
|
||||||
require OpenApiSpex
|
require OpenApiSpex
|
||||||
|
|
||||||
OpenApiSpex.schema(%{
|
OpenApiSpex.schema(%{
|
||||||
title: "ConfirmDeliveryRequest",
|
title: "CompleteRequest",
|
||||||
type: :object,
|
type: :object,
|
||||||
properties: %{
|
properties: %{
|
||||||
delivery_confirmed_by: %Schema{type: :string}
|
completed_by: %Schema{type: :string}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
@@ -143,4 +160,4 @@ defmodule WorkloadServiceWeb.Schemas.Task do
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,23 +3,20 @@ defmodule WorkloadService.Repo.Migrations.CreateTasks do
|
|||||||
|
|
||||||
def change do
|
def change do
|
||||||
create table(:tasks, primary_key: false) do
|
create table(:tasks, primary_key: false) do
|
||||||
add :id, :string, primary_key: true
|
add(:id, :string, primary_key: true)
|
||||||
add :org_id, :string, null: false
|
add(:org_id, :string, null: false)
|
||||||
add :application_id, :string, null: false
|
add(:application_id, :string, null: false)
|
||||||
add :provider_id, :string, null: false
|
add(:task_info, :map, default: %{})
|
||||||
add :provider_name, :string
|
add(:submission, :map)
|
||||||
add :task_info, :map, default: %{}
|
add(:attachments, {:array, :string}, default: [])
|
||||||
add :submission, :map
|
add(:status, :string, null: false, default: "created")
|
||||||
add :attachments, {:array, :string}, default: []
|
add(:version, :integer, default: 1)
|
||||||
add :status, :string, null: false, default: "created"
|
|
||||||
add :version, :integer, default: 1
|
|
||||||
|
|
||||||
timestamps type: :utc_datetime
|
timestamps(type: :utc_datetime)
|
||||||
end
|
end
|
||||||
|
|
||||||
create index(:tasks, [:application_id])
|
create(index(:tasks, [:application_id]))
|
||||||
create index(:tasks, [:org_id])
|
create(index(:tasks, [:org_id]))
|
||||||
create index(:tasks, [:provider_id])
|
create(index(:tasks, [:status]))
|
||||||
create index(:tasks, [:status])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user