diff --git a/lib/policy_service/aggregates/car_policy_application.ex b/lib/policy_service/aggregates/car_policy_application.ex index 1e324fb..6b0a7c4 100644 --- a/lib/policy_service/aggregates/car_policy_application.ex +++ b/lib/policy_service/aggregates/car_policy_application.ex @@ -11,21 +11,52 @@ defmodule PolicyService.Aggregates.CarPolicyApplication do "make" => make, "model" => model, "year" => year, - "car_value" => car_value, + "use_type" => use_type, + "car_type" => car_type, + "rc_limits" => _rc_limits, + "market_value" => market_value, + "requested_value" => requested_value + }) + when is_binary(plate) and is_binary(make) and is_binary(model) and + is_integer(year) and + is_number(market_value) and market_value > 0 and + is_number(requested_value) and requested_value > 0 and + is_binary(use_type) and byte_size(use_type) > 0 and + is_binary(car_type) and byte_size(car_type) > 0 do + cond do + year < 1886 or year > Date.utc_today().year + 1 -> {:error, :invalid_car_year} + use_type not in @valid_use_types -> {:error, :invalid_use_type} + car_type not in @valid_car_types -> {:error, :invalid_car_type} + byte_size(plate) == 0 -> {:error, :missing_plate} + true -> :ok + end + end + + def validate_details(%{ + "plate" => plate, + "make" => make, + "model" => model, + "year" => year, "use_type" => use_type, "car_type" => car_type, "chassis_number" => chassis, - "engine_number" => engine + "engine_number" => engine, + "rc_limits" => _rc_limits, + "market_value" => market_value, + "requested_value" => requested_value }) when is_binary(plate) and is_binary(make) and is_binary(model) and - is_integer(year) and is_number(car_value) and car_value > 0 and + is_integer(year) and + is_number(market_value) and market_value > 0 and + is_number(requested_value) and requested_value > 0 and + is_binary(use_type) and byte_size(use_type) > 0 and + is_binary(car_type) and byte_size(car_type) > 0 and is_binary(chassis) and is_binary(engine) do cond do year < 1886 or year > Date.utc_today().year + 1 -> {:error, :invalid_car_year} use_type not in @valid_use_types -> {:error, :invalid_use_type} car_type not in @valid_car_types -> {:error, :invalid_car_type} - byte_size(chassis) == 0 -> {:error, :missing_chassis_number} - byte_size(engine) == 0 -> {:error, :missing_engine_number} + byte_size(plate) == 0 -> {:error, :missing_plate} true -> :ok end end diff --git a/lib/policy_service/aggregates/fire_contents_policy_application.ex b/lib/policy_service/aggregates/fire_contents_policy_application.ex new file mode 100644 index 0000000..5415643 --- /dev/null +++ b/lib/policy_service/aggregates/fire_contents_policy_application.ex @@ -0,0 +1,22 @@ +defmodule PolicyService.Aggregates.FireContentsPolicyApplication do + use PolicyService.Aggregates.PolicyApplication, + policy_type: "fire_contents", + commands: PolicyService.Commands.FireContentsPolicy + + def validate_details(%{ + "location" => location, + "contents_value" => value, + "property_use" => use_type, + "security_measures" => measures, + "high_value_items" => items + }) + when is_binary(location) and byte_size(location) > 0 and + is_number(value) and value > 0 and + is_binary(use_type) and byte_size(use_type) > 0 and + is_list(measures) and + is_list(items) do + :ok + end + + def validate_details(_), do: {:error, :invalid_fire_contents_details} +end diff --git a/lib/policy_service/aggregates/fire_structure_policy_application.ex b/lib/policy_service/aggregates/fire_structure_policy_application.ex new file mode 100644 index 0000000..812161f --- /dev/null +++ b/lib/policy_service/aggregates/fire_structure_policy_application.ex @@ -0,0 +1,22 @@ +defmodule PolicyService.Aggregates.FireStructurePolicyApplication do + use PolicyService.Aggregates.PolicyApplication, + policy_type: "fire_structure", + commands: PolicyService.Commands.FireStructurePolicy + + def validate_details(%{ + "location" => location, + "property_value" => value, + "property_use" => use_type, + "security_measures" => measures, + "market_value" => market_value + }) + when is_binary(location) and byte_size(location) > 0 and + is_number(value) and value > 0 and + is_binary(use_type) and byte_size(use_type) > 0 and + is_list(measures) and + is_number(market_value) and market_value > 0 do + :ok + end + + def validate_details(_), do: {:error, :invalid_fire_structure_details} +end diff --git a/lib/policy_service/aggregates/policy_application.ex b/lib/policy_service/aggregates/policy_application.ex index 95685e1..2e932c0 100644 --- a/lib/policy_service/aggregates/policy_application.ex +++ b/lib/policy_service/aggregates/policy_application.ex @@ -39,7 +39,8 @@ defmodule PolicyService.Aggregates.PolicyApplication do defstruct [ :id, :submitted_by, - :applicant_info, + :insured, + :buyer, :policy_details, :selected_providers, :accepted_plan_id, @@ -52,13 +53,15 @@ defmodule PolicyService.Aggregates.PolicyApplication do endorsements: %{} ] - # ── Execute ──────────────────────────────────────────────────────────── + # ── Execute ────────────────────────────────────────────────── @impl Commanded.Aggregates.Aggregate def execute(%__MODULE__{state: nil}, %SubmitPolicyApplication{} = cmd) do with :ok <- PolicyService.Aggregates.PolicyApplication.validate_policy_id(cmd.id), :ok <- - PolicyService.Aggregates.PolicyApplication.validate_applicant(cmd.applicant_info), + PolicyService.Aggregates.PolicyApplication.validate_insured(cmd.insured), + :ok <- + PolicyService.Aggregates.PolicyApplication.validate_buyer(cmd.buyer), :ok <- validate_details(cmd.policy_details), :ok <- PolicyService.Aggregates.PolicyApplication.validate_providers( @@ -70,7 +73,8 @@ defmodule PolicyService.Aggregates.PolicyApplication do id: cmd.id, provider_id: provider.provider_id, provider_email: provider.email, - applicant_info: cmd.applicant_info, + insured: cmd.insured, + buyer: cmd.buyer, policy_details: cmd.policy_details, requested_at: DateTime.utc_now() } @@ -80,7 +84,8 @@ defmodule PolicyService.Aggregates.PolicyApplication do %PolicyApplicationSubmitted{ id: cmd.id, submitted_by: cmd.submitted_by, - applicant_info: cmd.applicant_info, + insured: cmd.insured, + buyer: cmd.buyer, policy_details: cmd.policy_details, selected_providers: cmd.selected_providers, submitted_at: DateTime.utc_now() @@ -178,7 +183,7 @@ defmodule PolicyService.Aggregates.PolicyApplication do } end - # ── Apply ────────────────────────────────────────────────────────────── + # ── Apply ────────────────────────────────────────────────────── @impl Commanded.Aggregates.Aggregate def apply(%__MODULE__{} = agg, %PolicyApplicationSubmitted{} = e) do @@ -186,7 +191,8 @@ defmodule PolicyService.Aggregates.PolicyApplication do agg | id: e.id, submitted_by: e.submitted_by, - applicant_info: e.applicant_info, + insured: e.insured, + buyer: e.buyer, policy_details: e.policy_details, selected_providers: e.selected_providers, quotes: %{}, @@ -247,12 +253,17 @@ defmodule PolicyService.Aggregates.PolicyApplication do def validate_user(id) when is_binary(id) and byte_size(id) > 0, do: :ok def validate_user(_), do: {:error, :missing_user_id} - def validate_applicant(%{"name" => n, "date_of_birth" => _, "document_id" => d}) + def validate_insured(%{ + "type" => "individual", + "name" => n, + "date_of_birth" => _, + "document_id" => d + }) when is_binary(n) and is_binary(d) and byte_size(n) > 0 and byte_size(d) > 0, do: :ok - # Match on string keys for Company - def validate_applicant(%{ + def validate_insured(%{ + "type" => "corporate", "company_name" => c, "ruc" => r, "legal_rep_name" => rep, @@ -262,7 +273,29 @@ defmodule PolicyService.Aggregates.PolicyApplication do byte_size(c) > 0 and byte_size(r) > 0, do: :ok - def validate_applicant(_), do: {:error, :invalid_applicant_info} + def validate_insured(_), do: {:error, :invalid_insured_info} + + def validate_buyer(%{ + "type" => "individual", + "name" => n, + "date_of_birth" => _, + "document_id" => d + }) + when is_binary(n) and is_binary(d) and byte_size(n) > 0 and byte_size(d) > 0, + do: :ok + + def validate_buyer(%{ + "type" => "corporate", + "company_name" => c, + "ruc" => r, + "legal_rep_name" => rep, + "legal_rep_document" => rd + }) + when is_binary(c) and is_binary(r) and is_binary(rep) and is_binary(rd) and + byte_size(c) > 0 and byte_size(r) > 0, + do: :ok + + def validate_buyer(_), do: {:error, :invalid_buyer_info} def validate_providers(p) when is_list(p) and length(p) > 0, do: :ok def validate_providers(_), do: {:error, :no_providers_selected} diff --git a/lib/policy_service/aggregates/policy_id.ex b/lib/policy_service/aggregates/policy_id.ex index 17c3bc5..4590f5b 100644 --- a/lib/policy_service/aggregates/policy_id.ex +++ b/lib/policy_service/aggregates/policy_id.ex @@ -1,9 +1,9 @@ defmodule PolicyService.Aggregates.PolicyId do @type t :: %__MODULE__{ - org_id: String.t(), - policy_type: String.t(), - application_id: String.t() - } + org_id: String.t(), + policy_type: String.t(), + application_id: String.t() + } @derive Jason.Encoder defstruct [:org_id, :policy_type, :application_id] diff --git a/lib/policy_service/commanded_app.ex b/lib/policy_service/commanded_app.ex index 7508283..a37c3df 100644 --- a/lib/policy_service/commanded_app.ex +++ b/lib/policy_service/commanded_app.ex @@ -13,15 +13,39 @@ defmodule PolicyService.Router do identity: :id ) - # Route Fire commands to Fire Aggregate + # Route Life commands to Life Aggregate dispatch( [ - PolicyService.Commands.FirePolicy.SubmitPolicyApplication, - PolicyService.Commands.FirePolicy.RecordProviderQuote, - PolicyService.Commands.FirePolicy.AcceptQuoteAndSolicit, - PolicyService.Commands.FirePolicy.RecordPolicyIssued + PolicyService.Commands.LifePolicy.SubmitPolicyApplication, + PolicyService.Commands.LifePolicy.RecordProviderQuote, + PolicyService.Commands.LifePolicy.AcceptQuoteAndSolicit, + PolicyService.Commands.LifePolicy.RecordPolicyIssued ], - to: PolicyService.Aggregates.FirePolicyApplication, + to: PolicyService.Aggregates.LifePolicyApplication, + identity: :id + ) + + # Route FireStructure commands to FireStructure Aggregate + dispatch( + [ + PolicyService.Commands.FireStructurePolicy.SubmitPolicyApplication, + PolicyService.Commands.FireStructurePolicy.RecordProviderQuote, + PolicyService.Commands.FireStructurePolicy.AcceptQuoteAndSolicit, + PolicyService.Commands.FireStructurePolicy.RecordPolicyIssued + ], + to: PolicyService.Aggregates.FireStructurePolicyApplication, + identity: :id + ) + + # Route FireContents commands to FireContents Aggregate + dispatch( + [ + PolicyService.Commands.FireContentsPolicy.SubmitPolicyApplication, + PolicyService.Commands.FireContentsPolicy.RecordProviderQuote, + PolicyService.Commands.FireContentsPolicy.AcceptQuoteAndSolicit, + PolicyService.Commands.FireContentsPolicy.RecordPolicyIssued + ], + to: PolicyService.Aggregates.FireContentsPolicyApplication, identity: :id ) end @@ -31,4 +55,4 @@ defmodule PolicyService.CommandedApp do otp_app: :policy_service router(PolicyService.Router) -end \ No newline at end of file +end diff --git a/lib/policy_service/commands/car_policy.ex b/lib/policy_service/commands/car_policy.ex index 792ab50..dad6bc8 100644 --- a/lib/policy_service/commands/car_policy.ex +++ b/lib/policy_service/commands/car_policy.ex @@ -1,6 +1,8 @@ defmodule PolicyService.Commands.CarPolicy do - defmodule SubmitPolicyApplication, do: use(PolicyService.Commands.Policy.SubmitPolicyApplication) + defmodule SubmitPolicyApplication, + do: use(PolicyService.Commands.Policy.SubmitPolicyApplication) + defmodule RecordProviderQuote, do: use(PolicyService.Commands.Policy.RecordProviderQuote) defmodule AcceptQuoteAndSolicit, do: use(PolicyService.Commands.Policy.AcceptQuoteAndSolicit) defmodule RecordPolicyIssued, do: use(PolicyService.Commands.Policy.RecordPolicyIssued) -end \ No newline at end of file +end diff --git a/lib/policy_service/commands/fire_contents_policy.ex b/lib/policy_service/commands/fire_contents_policy.ex new file mode 100644 index 0000000..587f6e8 --- /dev/null +++ b/lib/policy_service/commands/fire_contents_policy.ex @@ -0,0 +1,8 @@ +defmodule PolicyService.Commands.FireContentsPolicy do + defmodule SubmitPolicyApplication, + do: use(PolicyService.Commands.Policy.SubmitPolicyApplication) + + defmodule RecordProviderQuote, do: use(PolicyService.Commands.Policy.RecordProviderQuote) + defmodule AcceptQuoteAndSolicit, do: use(PolicyService.Commands.Policy.AcceptQuoteAndSolicit) + defmodule RecordPolicyIssued, do: use(PolicyService.Commands.Policy.RecordPolicyIssued) +end diff --git a/lib/policy_service/commands/fire_policy.ex b/lib/policy_service/commands/fire_policy.ex index 77eefbb..4e46bae 100644 --- a/lib/policy_service/commands/fire_policy.ex +++ b/lib/policy_service/commands/fire_policy.ex @@ -1,6 +1,8 @@ defmodule PolicyService.Commands.FirePolicy do - defmodule SubmitPolicyApplication, do: use(PolicyService.Commands.Policy.SubmitPolicyApplication) + defmodule SubmitPolicyApplication, + do: use(PolicyService.Commands.Policy.SubmitPolicyApplication) + defmodule RecordProviderQuote, do: use(PolicyService.Commands.Policy.RecordProviderQuote) defmodule AcceptQuoteAndSolicit, do: use(PolicyService.Commands.Policy.AcceptQuoteAndSolicit) defmodule RecordPolicyIssued, do: use(PolicyService.Commands.Policy.RecordPolicyIssued) -end \ No newline at end of file +end diff --git a/lib/policy_service/commands/fire_structure_policy.ex b/lib/policy_service/commands/fire_structure_policy.ex new file mode 100644 index 0000000..946a2c0 --- /dev/null +++ b/lib/policy_service/commands/fire_structure_policy.ex @@ -0,0 +1,8 @@ +defmodule PolicyService.Commands.FireStructurePolicy do + defmodule SubmitPolicyApplication, + do: use(PolicyService.Commands.Policy.SubmitPolicyApplication) + + defmodule RecordProviderQuote, do: use(PolicyService.Commands.Policy.RecordProviderQuote) + defmodule AcceptQuoteAndSolicit, do: use(PolicyService.Commands.Policy.AcceptQuoteAndSolicit) + defmodule RecordPolicyIssued, do: use(PolicyService.Commands.Policy.RecordPolicyIssued) +end diff --git a/lib/policy_service/commands/life_policy.ex b/lib/policy_service/commands/life_policy.ex new file mode 100644 index 0000000..42515be --- /dev/null +++ b/lib/policy_service/commands/life_policy.ex @@ -0,0 +1,8 @@ +defmodule PolicyService.Commands.LifePolicy do + defmodule SubmitPolicyApplication, + do: use(PolicyService.Commands.Policy.SubmitPolicyApplication) + + defmodule RecordProviderQuote, do: use(PolicyService.Commands.Policy.RecordProviderQuote) + defmodule AcceptQuoteAndSolicit, do: use(PolicyService.Commands.Policy.AcceptQuoteAndSolicit) + defmodule RecordPolicyIssued, do: use(PolicyService.Commands.Policy.RecordPolicyIssued) +end diff --git a/lib/policy_service/commands/policy.ex b/lib/policy_service/commands/policy.ex index ec503df..ff7b916 100644 --- a/lib/policy_service/commands/policy.ex +++ b/lib/policy_service/commands/policy.ex @@ -11,7 +11,8 @@ defmodule PolicyService.Commands.Policy do typedstruct do field :id, PolicyService.Aggregates.PolicyId.t(), enforce: true field :submitted_by, String.t(), enforce: true - field :applicant_info, map(), enforce: true + field :insured, map(), enforce: true + field :buyer, map(), enforce: true field :policy_details, map() field :selected_providers, list(), enforce: true end @@ -67,4 +68,4 @@ defmodule PolicyService.Commands.Policy do end end end -end \ No newline at end of file +end diff --git a/lib/policy_service/consumers/quote_task_consumer.ex b/lib/policy_service/consumers/quote_task_consumer.ex index 84f3e17..cbe4c8c 100644 --- a/lib/policy_service/consumers/quote_task_consumer.ex +++ b/lib/policy_service/consumers/quote_task_consumer.ex @@ -42,6 +42,10 @@ defmodule PolicyService.Consumers.QuoteTaskConsumer do {:noreply, state} 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} + defp process(payload) do with {:ok, event} <- Jason.decode(payload), :ok <- dispatch(event) do @@ -49,10 +53,6 @@ defmodule PolicyService.Consumers.QuoteTaskConsumer do end 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} - defp dispatch(%{ "application_id" => %{ "org_id" => org_id, diff --git a/lib/policy_service/consumers/solicitation_task_consumer.ex b/lib/policy_service/consumers/solicitation_task_consumer.ex index fc22565..53d024b 100644 --- a/lib/policy_service/consumers/solicitation_task_consumer.ex +++ b/lib/policy_service/consumers/solicitation_task_consumer.ex @@ -41,6 +41,10 @@ defmodule PolicyService.Consumers.SolicitationTaskConsumer do {:noreply, state} 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} + defp process(payload) do with {:ok, event} <- Jason.decode(payload), :ok <- dispatch(event) do @@ -48,17 +52,13 @@ defmodule PolicyService.Consumers.SolicitationTaskConsumer do end 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} - defp dispatch(%{ "application_id" => %{ "org_id" => org_id, "policy_type" => policy_type, "application_id" => app_id }, - "task_info" => task_info, + "task_info" => _task_info, "submission" => submission }) do cmd = diff --git a/lib/policy_service/events/policy.ex b/lib/policy_service/events/policy.ex index 9446a79..008f430 100644 --- a/lib/policy_service/events/policy.ex +++ b/lib/policy_service/events/policy.ex @@ -8,7 +8,10 @@ defmodule PolicyService.Events do defmacro __using__(_opts) do quote do defimpl Commanded.Serialization.JsonDecoder do - def decode(%{id: %{org_id: org_id, policy_type: policy_type, application_id: application_id}} = event) do + def decode( + %{id: %{org_id: org_id, policy_type: policy_type, application_id: application_id}} = + event + ) do %{event | id: PolicyId.new(org_id, policy_type, application_id)} end @@ -26,19 +29,45 @@ defmodule PolicyService.Events.Policy do defmodule PolicyApplicationSubmitted do use PolicyService.Events @derive Jason.Encoder - defstruct [:id, :submitted_by, :applicant_info, :policy_details, :selected_providers, :submitted_at] + defstruct [ + :id, + :submitted_by, + :insured, + :buyer, + :policy_details, + :selected_providers, + :submitted_at + ] end defmodule QuoteRequestSent do use PolicyService.Events @derive Jason.Encoder - defstruct [:id, :provider_id, :provider_email, :applicant_info, :policy_details, :requested_at] + defstruct [ + :id, + :provider_id, + :provider_email, + :insured, + :buyer, + :policy_details, + :requested_at + ] end defmodule ProviderQuoteReceived do use PolicyService.Events @derive Jason.Encoder - defstruct [:id, :recorded_by, :provider_id, :quote_id, :premium, :coverage_details, :valid_until, :plans, :received_at] + defstruct [ + :id, + :recorded_by, + :provider_id, + :quote_id, + :premium, + :coverage_details, + :valid_until, + :plans, + :received_at + ] end defmodule AllQuotesReceived do @@ -53,11 +82,11 @@ defmodule PolicyService.Events.Policy do defstruct [:id, :accepted_by, :quote, :plan, :provider] end - defmodule SolicitationRequestSent do - use PolicyService.Events - @derive Jason.Encoder - defstruct [:id, :plan, :provider_id] - end + defmodule SolicitationRequestSent do + use PolicyService.Events + @derive Jason.Encoder + defstruct [:id, :plan, :provider_id] + end defmodule PolicyIssued do use PolicyService.Events diff --git a/lib/policy_service/handlers/solicitation_request_handler.ex b/lib/policy_service/handlers/solicitation_request_handler.ex index 9686237..5b1aad7 100644 --- a/lib/policy_service/handlers/solicitation_request_handler.ex +++ b/lib/policy_service/handlers/solicitation_request_handler.ex @@ -5,11 +5,16 @@ defmodule PolicyService.Handlers.SolicitationRequestHandler do require Logger - alias PolicyService.Events.Policy.SolicitationRequestSent - alias PolicyService.MessageBus + alias PolicyService.Events.Policy.SolicitationRequestSent + alias PolicyService.MessageBus - def handle(%SolicitationRequestSent{} = event, _metadata) do - MessageBus.publish("policy_service.events.solicitation_requested", "solicitation.requested", event) - :ok - end + def handle(%SolicitationRequestSent{} = event, _metadata) do + MessageBus.publish( + "policy_service.events.solicitation_requested", + "solicitation.requested", + event + ) + + :ok + end end diff --git a/lib/policy_service/message_bus.ex b/lib/policy_service/message_bus.ex index bc45139..4b5e03a 100644 --- a/lib/policy_service/message_bus.ex +++ b/lib/policy_service/message_bus.ex @@ -18,4 +18,4 @@ defmodule PolicyService.MessageBus do end defp amqp_url, do: Application.fetch_env!(:policy_service, :amqp_url) -end \ No newline at end of file +end diff --git a/lib/policy_service/policy/filters.ex b/lib/policy_service/policy/filters.ex index c0f7aeb..b2ed59a 100644 --- a/lib/policy_service/policy/filters.ex +++ b/lib/policy_service/policy/filters.ex @@ -7,10 +7,14 @@ defmodule PolicyService.Filters.PolicyApplicationFilters do where( query, [p], - fragment("?->>'name' ilike ?", p.applicant_info, ^term) or - fragment("?->>'company_name' ilike ?", p.applicant_info, ^term) or - fragment("?->>'document_id' ilike ?", p.applicant_info, ^term) or - fragment("?->>'ruc' ilike ?", p.applicant_info, ^term) or + fragment("?->>'name' ilike ?", p.insured, ^term) or + fragment("?->>'company_name' ilike ?", p.insured, ^term) or + fragment("?->>'document_id' ilike ?", p.insured, ^term) or + fragment("?->>'ruc' ilike ?", p.insured, ^term) or + fragment("?->>'name' ilike ?", p.buyer, ^term) or + fragment("?->>'company_name' ilike ?", p.buyer, ^term) or + fragment("?->>'document_id' ilike ?", p.buyer, ^term) or + fragment("?->>'ruc' ilike ?", p.buyer, ^term) or ilike(p.provider_policy_number, ^term) ) end diff --git a/lib/policy_service/projections/policy.ex b/lib/policy_service/projections/policy.ex index 82e3c31..a5b5ab6 100644 --- a/lib/policy_service/projections/policy.ex +++ b/lib/policy_service/projections/policy.ex @@ -2,29 +2,30 @@ defmodule PolicyService.Projections.PolicyApplication do use Ecto.Schema @derive {Jason.Encoder, - only: [ - :id, - :application_id, - :org_id, - :submitted_by, - :policy_type, - :applicant_info, - :policy_details, - :selected_providers, - :quotes, - :accepted_plan_id, - :accepted_by, - :provider_policy_number, - :premium, - :effective_date, - :expiry_date, - :status, - :submitted_at, - :solicitation_sent_at, - :issued_at, - :inserted_at, - :updated_at - ]} + only: [ + :id, + :application_id, + :org_id, + :submitted_by, + :policy_type, + :insured, + :buyer, + :policy_details, + :selected_providers, + :quotes, + :accepted_plan_id, + :accepted_by, + :provider_policy_number, + :premium, + :effective_date, + :expiry_date, + :status, + :submitted_at, + :solicitation_sent_at, + :issued_at, + :inserted_at, + :updated_at + ]} @derive { Flop.Schema, @@ -50,7 +51,8 @@ defmodule PolicyService.Projections.PolicyApplication do field :submitted_by, :string field :policy_type, :string - field :applicant_info, :map + field :insured, :map + field :buyer, :map field :policy_details, :map field :selected_providers, {:array, :string}, default: [] @@ -59,7 +61,7 @@ defmodule PolicyService.Projections.PolicyApplication do field :accepted_plan_id, :string field :accepted_by, :string - field :provider_policy_number, :string + field :provider_policy_number, :string field :premium, :decimal field :effective_date, :date diff --git a/lib/policy_service/projectors/policy_projector.ex b/lib/policy_service/projectors/policy_projector.ex index 8b15705..ae29498 100644 --- a/lib/policy_service/projectors/policy_projector.ex +++ b/lib/policy_service/projectors/policy_projector.ex @@ -24,7 +24,8 @@ defmodule PolicyService.Projectors.PolicyProjector do org_id: e.id.org_id, submitted_by: e.submitted_by, policy_type: e.id.policy_type, - applicant_info: atomize(e.applicant_info), + insured: atomize(e.insured), + buyer: atomize(e.buyer), policy_details: atomize(e.policy_details), selected_providers: Enum.map(e.selected_providers, & &1["provider_id"]), quotes: %{}, diff --git a/lib/policy_service/release.ex b/lib/policy_service/release.ex index d91715c..28cf87d 100644 --- a/lib/policy_service/release.ex +++ b/lib/policy_service/release.ex @@ -34,4 +34,4 @@ defmodule PolicyService.Release do :ok = EventStore.Tasks.Init.exec(config, []) end -end \ No newline at end of file +end diff --git a/lib/policy_service_web/controllers/policy_controller.ex b/lib/policy_service_web/controllers/policy_controller.ex index 7474290..507c622 100644 --- a/lib/policy_service_web/controllers/policy_controller.ex +++ b/lib/policy_service_web/controllers/policy_controller.ex @@ -7,6 +7,9 @@ defmodule PolicyServiceWeb.PolicyController do alias PolicyService.Aggregates.PolicyId alias PolicyService.Commands.CarPolicy + alias PolicyService.Commands.LifePolicy + alias PolicyService.Commands.FireStructurePolicy + alias PolicyService.Commands.FireContentsPolicy alias PolicyServiceWeb.Schemas.Policy, as: S alias PolicyServiceWeb.QueryHelpers @@ -16,10 +19,11 @@ defmodule PolicyServiceWeb.PolicyController do operation(:index, summary: "List policies", - parameters: QueryHelpers.flop( - [:status, :policy_type, :search], - [:submitted_at, :policy_type, :status] - ), + parameters: + QueryHelpers.flop( + [:status, :policy_type, :search], + [:submitted_at, :policy_type, :status] + ), responses: [ ok: {"Policy list", "application/json", S.PolicyListResponse}, bad_request: {"Invalid params", "application/json", S.ErrorResponse} @@ -89,7 +93,8 @@ defmodule PolicyServiceWeb.PolicyController do submitted_by = conn.assigns[:user_id] || "test" with {:ok, policy_type} <- parse_policy_type(params["policy_type"]), - {:ok, applicant_info} <- parse_applicant_info(params["applicant_info"]), + {:ok, insured} <- parse_insured(params["insured"]), + {:ok, buyer} <- parse_buyer(params["buyer"]), {:ok, policy_details} <- parse_policy_details(policy_type, params["policy_details"]), {:ok, providers} <- parse_providers(params["selected_providers"]) do command = @@ -98,7 +103,38 @@ defmodule PolicyServiceWeb.PolicyController do %CarPolicy.SubmitPolicyApplication{ id: PolicyId.new(org_id, policy_type, application_id), submitted_by: submitted_by, - applicant_info: applicant_info, + insured: insured, + buyer: buyer, + policy_details: policy_details, + selected_providers: providers + } + + "life" -> + %LifePolicy.SubmitPolicyApplication{ + id: PolicyId.new(org_id, policy_type, application_id), + submitted_by: submitted_by, + insured: insured, + buyer: buyer, + policy_details: policy_details, + selected_providers: providers + } + + "fire_structure" -> + %FireStructurePolicy.SubmitPolicyApplication{ + id: PolicyId.new(org_id, policy_type, application_id), + submitted_by: submitted_by, + insured: insured, + buyer: buyer, + policy_details: policy_details, + selected_providers: providers + } + + "fire_contents" -> + %FireContentsPolicy.SubmitPolicyApplication{ + id: PolicyId.new(org_id, policy_type, application_id), + submitted_by: submitted_by, + insured: insured, + buyer: buyer, policy_details: policy_details, selected_providers: providers } @@ -148,6 +184,27 @@ defmodule PolicyServiceWeb.PolicyController do accepted_by: params["accepted_by"] || "system", accepted_plan_id: params["accepted_plan_id"] } + + "life" -> + %LifePolicy.AcceptQuoteAndSolicit{ + id: PolicyId.new(org_id, policy.policy_type, application_id), + accepted_by: params["accepted_by"] || "system", + accepted_plan_id: params["accepted_plan_id"] + } + + "fire_structure" -> + %FireStructurePolicy.AcceptQuoteAndSolicit{ + id: PolicyId.new(org_id, policy.policy_type, application_id), + accepted_by: params["accepted_by"] || "system", + accepted_plan_id: params["accepted_plan_id"] + } + + "fire_contents" -> + %FireContentsPolicy.AcceptQuoteAndSolicit{ + id: PolicyId.new(org_id, policy.policy_type, application_id), + accepted_by: params["accepted_by"] || "system", + accepted_plan_id: params["accepted_plan_id"] + } end case CommandedApp.dispatch(command, consistency: :strong) do @@ -176,7 +233,8 @@ defmodule PolicyServiceWeb.PolicyController do application_id: p.application_id, policy_type: p.policy_type, status: p.status, - applicant_info: p.applicant_info, + insured: p.insured, + buyer: p.buyer, policy_details: p.policy_details, provider_policy_number: p.provider_policy_number, submitted_at: p.submitted_at @@ -190,7 +248,8 @@ defmodule PolicyServiceWeb.PolicyController do submitted_by: p.submitted_by, policy_type: p.policy_type, status: p.status, - applicant_info: p.applicant_info, + insured: p.insured, + buyer: p.buyer, policy_details: p.policy_details, selected_providers: p.selected_providers, quotes: p.quotes, @@ -221,41 +280,90 @@ defmodule PolicyServiceWeb.PolicyController do # Parse helpers # --------------------------------------------------------------------------- - defp parse_policy_type(type) when type in ["car", "life", "fire"], do: {:ok, type} + defp parse_policy_type(type) when type in ["car", "life", "fire_structure", "fire_contents"], + do: {:ok, type} + defp parse_policy_type(_), do: {:error, :invalid_policy_type} - # individual — has document_id - defp parse_applicant_info(%{"document_id" => doc} = info) - when is_binary(doc) and byte_size(doc) > 0 do - case info["date_of_birth"] do - nil -> - {:error, :missing_date_of_birth} + # insured — individual + defp parse_insured(info) do + case info["type"] do + "individual" -> + case info["date_of_birth"] do + nil -> + {:error, :missing_date_of_birth} - dob -> + dob -> + {:ok, + %{ + "type" => "individual", + "name" => info["name"], + "date_of_birth" => dob, + "document_id" => info["document_id"], + "email" => info["email"], + "phone" => info["phone"], + "address" => info["address"] + }} + end + + "corporate" -> {:ok, %{ - "name" => info["name"], - "date_of_birth" => dob, - "document_id" => doc, - "client_type" => "natural" + "type" => "corporate", + "company_name" => info["company_name"], + "ruc" => info["ruc"], + "legal_rep_name" => info["legal_rep_name"], + "legal_rep_document" => info["legal_rep_document"], + "email" => info["email"], + "phone" => info["phone"], + "address" => info["address"] }} + + _ -> + {:error, :invalid_insured_type} end end - # corporate — has ruc - defp parse_applicant_info(%{"ruc" => ruc} = info) - when is_binary(ruc) and byte_size(ruc) > 0 do - {:ok, - %{ - "company_name" => info["company_name"], - "ruc" => ruc, - "legal_rep_name" => info["legal_rep_name"], - "legal_rep_document" => info["legal_rep_document"], - "client_type" => "juridico" - }} + # buyer — individual + defp parse_buyer(info) do + case info["type"] do + "individual" -> + case info["date_of_birth"] do + nil -> + {:error, :missing_date_of_birth} + + dob -> + {:ok, + %{ + "type" => "individual", + "name" => info["name"], + "date_of_birth" => dob, + "document_id" => info["document_id"], + "email" => info["email"], + "phone" => info["phone"], + "address" => info["address"] + }} + end + + "corporate" -> + {:ok, + %{ + "type" => "corporate", + "company_name" => info["company_name"], + "ruc" => info["ruc"], + "legal_rep_name" => info["legal_rep_name"], + "legal_rep_document" => info["legal_rep_document"], + "email" => info["email"], + "phone" => info["phone"], + "address" => info["address"] + }} + + _ -> + {:error, :invalid_buyer_type} + end end - defp parse_applicant_info(_), do: {:error, :invalid_applicant_info} + # individual — has document_id # car details defp parse_policy_details("car", nil), do: {:error, :missing_policy_details} @@ -267,11 +375,13 @@ defmodule PolicyServiceWeb.PolicyController do "make" => d["make"], "model" => d["model"], "year" => d["year"], - "car_value" => d["car_value"], "use_type" => d["use_type"], "car_type" => d["car_type"], "chassis_number" => d["chassis_number"], - "engine_number" => d["engine_number"] + "engine_number" => d["engine_number"], + "rc_limits" => d["rc_limits"], + "market_value" => d["market_value"], + "requested_value" => d["requested_value"] }} end @@ -281,19 +391,42 @@ defmodule PolicyServiceWeb.PolicyController do defp parse_policy_details("life", d) do {:ok, %{ + "coverage_type" => d["coverage_type"], "coverage_amount" => d["coverage_amount"], - "beneficiary" => d["beneficiary"] + "coverage_years" => d["coverage_years"], + "smoker" => d["smoker"], + "medications" => d["medications"], + "surgeries" => d["surgeries"], + "weight" => d["weight"], + "height" => d["height"] }} end - # fire details - defp parse_policy_details("fire", nil), do: {:error, :missing_policy_details} + # fire_structure details + defp parse_policy_details("fire_structure", nil), do: {:error, :missing_policy_details} - defp parse_policy_details("fire", d) do + defp parse_policy_details("fire_structure", d) do {:ok, %{ - "property_address" => d["property_address"], - "property_value" => d["property_value"] + "location" => d["location"], + "property_value" => d["property_value"], + "property_use" => d["property_use"], + "security_measures" => d["security_measures"], + "market_value" => d["market_value"] + }} + end + + # fire_contents details + defp parse_policy_details("fire_contents", nil), do: {:error, :missing_policy_details} + + defp parse_policy_details("fire_contents", d) do + {:ok, + %{ + "location" => d["location"], + "contents_value" => d["contents_value"], + "property_use" => d["property_use"], + "security_measures" => d["security_measures"], + "high_value_items" => d["high_value_items"] }} end diff --git a/lib/policy_service_web/query_helpers.ex b/lib/policy_service_web/query_helpers.ex index 6f713f7..5144f98 100644 --- a/lib/policy_service_web/query_helpers.ex +++ b/lib/policy_service_web/query_helpers.ex @@ -9,8 +9,14 @@ defmodule PolicyServiceWeb.QueryHelpers do [ page: [in: :query, schema: %Schema{type: :number, default: 1}], page_size: [in: :query, schema: %Schema{type: :number, default: 20}], - order_by: [in: :query, schema: %Schema{type: :array, items: %Schema{type: :string, enum: order_fields}}], - order_directions: [in: :query, schema: %Schema{type: :array, items: %Schema{type: :string, enum: ["asc", "desc"]}}] + order_by: [ + in: :query, + schema: %Schema{type: :array, items: %Schema{type: :string, enum: order_fields}} + ], + order_directions: [ + in: :query, + schema: %Schema{type: :array, items: %Schema{type: :string, enum: ["asc", "desc"]}} + ] ] ++ build_filter_params(filter_fields) ++ other end @@ -18,9 +24,11 @@ defmodule PolicyServiceWeb.QueryHelpers do for i <- 0..(@filter_count - 1) do [ {:"filters[#{i}][field]", [in: :query, schema: %Schema{type: :string, enum: fields}]}, - {:"filters[#{i}][op]", [in: :query, schema: %Schema{type: :string, enum: Flop.Filter.allowed_operators(:all)}]}, + {:"filters[#{i}][op]", + [in: :query, schema: %Schema{type: :string, enum: Flop.Filter.allowed_operators(:all)}]}, {:"filters[#{i}][value]", [in: :query, schema: %Schema{type: :string}]} ] - end |> List.flatten() + end + |> List.flatten() end -end \ No newline at end of file +end diff --git a/lib/policy_service_web/schemas/policy.ex b/lib/policy_service_web/schemas/policy.ex index 1f805d2..304a483 100644 --- a/lib/policy_service_web/schemas/policy.ex +++ b/lib/policy_service_web/schemas/policy.ex @@ -18,8 +18,104 @@ defmodule PolicyServiceWeb.Schemas.Policy do }) end + defmodule InsuredIndividual do + require OpenApiSpex + + OpenApiSpex.schema(%{ + title: "InsuredIndividual", + type: :object, + required: [:type, :name, :date_of_birth, :document_id], + properties: %{ + type: %Schema{type: :string, enum: ["individual"]}, + name: %Schema{type: :string, example: "Juan Pérez"}, + date_of_birth: %Schema{type: :string, format: :date, example: "1985-06-15"}, + document_id: %Schema{type: :string, example: "8-123-456"}, + email: %Schema{type: :string, format: :email, example: "juan@example.com"}, + phone: %Schema{type: :string, example: "+507-1234-5678"}, + address: %Schema{type: :string, example: "Calle 50, Panama City"} + } + }) + end + + defmodule InsuredCorporate do + require OpenApiSpex + + OpenApiSpex.schema(%{ + title: "InsuredCorporate", + type: :object, + required: [:type, :company_name, :ruc, :legal_rep_name, :legal_rep_document], + properties: %{ + type: %Schema{type: :string, enum: ["corporate"]}, + company_name: %Schema{type: :string, example: "Empresa ABC S.A."}, + ruc: %Schema{type: :string, example: "123456-1-123456"}, + legal_rep_name: %Schema{type: :string, example: "María García"}, + legal_rep_document: %Schema{type: :string, example: "8-456-789"}, + email: %Schema{type: :string, format: :email, example: "contact@empresa-abc.com"}, + phone: %Schema{type: :string, example: "+507-1234-5678"}, + address: %Schema{type: :string, example: "Calle 50, Panama City"} + } + }) + end + + defmodule Insured do + require OpenApiSpex + + OpenApiSpex.schema(%{ + title: "Insured", + oneOf: [InsuredIndividual, InsuredCorporate] + }) + end + + defmodule BuyerIndividual do + require OpenApiSpex + + OpenApiSpex.schema(%{ + title: "BuyerIndividual", + type: :object, + required: [:type, :name, :date_of_birth, :document_id], + properties: %{ + type: %Schema{type: :string, enum: ["individual"]}, + name: %Schema{type: :string, example: "María García"}, + date_of_birth: %Schema{type: :string, format: :date, example: "1980-03-20"}, + document_id: %Schema{type: :string, example: "8-456-789"}, + email: %Schema{type: :string, format: :email, example: "maria@example.com"}, + phone: %Schema{type: :string, example: "+507-8765-4321"}, + address: %Schema{type: :string, example: "Calle 75, Panama City"} + } + }) + end + + defmodule BuyerCorporate do + require OpenApiSpex + + OpenApiSpex.schema(%{ + title: "BuyerCorporate", + type: :object, + required: [:type, :company_name, :ruc, :legal_rep_name, :legal_rep_document], + properties: %{ + type: %Schema{type: :string, enum: ["corporate"]}, + company_name: %Schema{type: :string, example: "Empresa XYZ S.A."}, + ruc: %Schema{type: :string, example: "987654-1-987654"}, + legal_rep_name: %Schema{type: :string, example: "Carlos López"}, + legal_rep_document: %Schema{type: :string, example: "8-789-012"}, + email: %Schema{type: :string, format: :email, example: "carlos@empresa-xyz.com"}, + phone: %Schema{type: :string, example: "+507-8765-4321"}, + address: %Schema{type: :string, example: "Calle 100, Panama City"} + } + }) + end + + defmodule Buyer do + require OpenApiSpex + + OpenApiSpex.schema(%{ + title: "Buyer", + oneOf: [BuyerIndividual, BuyerCorporate] + }) + end + # --------------------------------------------------------------------------- - # Applicant — discriminated by presence of keys + # Policy details — one per policy type # --------------------------------------------------------------------------- defmodule ApplicantIndividual do @@ -77,18 +173,17 @@ defmodule PolicyServiceWeb.Schemas.Policy do :make, :model, :year, - :car_value, :use_type, :car_type, - :chassis_number, - :engine_number + :rc_limits, + :market_value, + :requested_value ], properties: %{ plate: %Schema{type: :string, example: "ABC-1234"}, make: %Schema{type: :string, example: "Toyota"}, model: %Schema{type: :string, example: "Corolla"}, year: %Schema{type: :integer, example: 2022}, - car_value: %Schema{type: :number, example: 18000}, use_type: %Schema{type: :string, enum: ["private", "commercial", "bus", "taxi", "school"]}, car_type: %Schema{ type: :string, @@ -105,7 +200,16 @@ defmodule PolicyServiceWeb.Schemas.Policy do ] }, chassis_number: %Schema{type: :string, example: "9BWZZZ377VT004251"}, - engine_number: %Schema{type: :string, example: "1NZ-FE-1234567"} + engine_number: %Schema{type: :string, example: "1NZ-FE-1234567"}, + rc_limits: %Schema{ + type: :object, + properties: %{ + bodily_injury: %Schema{type: :number, example: 50000}, + property_damage: %Schema{type: :number, example: 25000} + } + }, + market_value: %Schema{type: :number, example: 18000}, + requested_value: %Schema{type: :number, example: 20000} } }) end @@ -116,24 +220,63 @@ defmodule PolicyServiceWeb.Schemas.Policy do OpenApiSpex.schema(%{ title: "LifePolicyDetails", type: :object, - required: [:coverage_amount, :beneficiary], + required: [:coverage_type, :coverage_amount, :coverage_years, :smoker, :weight, :height], properties: %{ + coverage_type: %Schema{ + type: :string, + enum: ["banking", "protection"] + }, coverage_amount: %Schema{type: :number, example: 100_000}, - beneficiary: %Schema{type: :string, example: "María Pérez"} + coverage_years: %Schema{type: :integer, example: 10}, + smoker: %Schema{type: :boolean, example: false}, + medications: %Schema{type: :array, items: %Schema{type: :string}}, + surgeries: %Schema{type: :array, items: %Schema{type: :string}}, + weight: %Schema{type: :number, example: 70}, + height: %Schema{type: :number, example: 175} } }) end - defmodule FirePolicyDetails do + defmodule FireStructurePolicyDetails do require OpenApiSpex OpenApiSpex.schema(%{ - title: "FirePolicyDetails", + title: "FireStructurePolicyDetails", type: :object, - required: [:property_address, :property_value], + required: [:location, :property_value, :property_use, :security_measures, :market_value], properties: %{ - property_address: %Schema{type: :string, example: "Calle 50, Panama City"}, - property_value: %Schema{type: :number, example: 250_000} + location: %Schema{type: :string, example: "Calle 50, Panama City"}, + property_value: %Schema{type: :number, example: 250_000}, + property_use: %Schema{type: :string, example: "residential"}, + security_measures: %Schema{type: :array, items: %Schema{type: :string}}, + market_value: %Schema{type: :number, example: 260_000} + } + }) + end + + defmodule FireContentsPolicyDetails do + require OpenApiSpex + + OpenApiSpex.schema(%{ + title: "FireContentsPolicyDetails", + type: :object, + required: [:location, :contents_value, :property_use, :security_measures], + properties: %{ + location: %Schema{type: :string, example: "Calle 50, Panama City"}, + contents_value: %Schema{type: :number, example: 50_000}, + property_use: %Schema{type: :string, example: "residential"}, + security_measures: %Schema{type: :array, items: %Schema{type: :string}}, + high_value_items: %Schema{ + type: :array, + items: %Schema{ + type: :object, + properties: %{ + description: %Schema{type: :string}, + value: %Schema{type: :number}, + type: %Schema{type: :string, enum: ["electronic", "other"]} + } + } + } } }) end @@ -143,7 +286,12 @@ defmodule PolicyServiceWeb.Schemas.Policy do OpenApiSpex.schema(%{ title: "PolicyDetails", - oneOf: [CarPolicyDetails, LifePolicyDetails, FirePolicyDetails] + oneOf: [ + CarPolicyDetails, + LifePolicyDetails, + FireStructurePolicyDetails, + FireContentsPolicyDetails + ] }) end @@ -207,14 +355,15 @@ defmodule PolicyServiceWeb.Schemas.Policy do OpenApiSpex.schema(%{ title: "CreatePolicyRequest", type: :object, - required: [:policy_type, :applicant_info, :policy_details, :selected_providers], + required: [:policy_type, :insured, :buyer, :policy_details, :selected_providers], properties: %{ policy_type: %Schema{ type: :string, - enum: ["car", "life", "fire"], + enum: ["car", "life", "fire_structure", "fire_contents"], description: "Determines the shape of policy_details" }, - applicant_info: ApplicantInfo, + insured: Insured, + buyer: Buyer, policy_details: PolicyDetails, selected_providers: %Schema{type: :array, items: SelectedProvider, minItems: 1} } @@ -262,12 +411,16 @@ defmodule PolicyServiceWeb.Schemas.Policy do type: :object, properties: %{ application_id: %Schema{type: :string}, - policy_type: %Schema{type: :string, enum: ["car", "life", "fire"]}, + policy_type: %Schema{ + type: :string, + enum: ["car", "life", "fire_structure", "fire_contents"] + }, status: %Schema{ type: :string, enum: ["quote_requested", "quotes_received", "awaiting_policy", "issued"] }, - applicant_info: ApplicantInfo, + insured: Insured, + buyer: Buyer, policy_details: PolicyDetails, provider_policy_number: %Schema{type: :string, nullable: true}, submitted_at: %Schema{type: :string, format: :"date-time"} @@ -285,12 +438,16 @@ defmodule PolicyServiceWeb.Schemas.Policy do application_id: %Schema{type: :string}, org_id: %Schema{type: :string}, submitted_by: %Schema{type: :string}, - policy_type: %Schema{type: :string, enum: ["car", "life", "fire"]}, + policy_type: %Schema{ + type: :string, + enum: ["car", "life", "fire_structure", "fire_contents"] + }, status: %Schema{ type: :string, enum: ["quote_requested", "quotes_received", "awaiting_policy", "issued"] }, - applicant_info: ApplicantInfo, + insured: Insured, + buyer: Buyer, policy_details: PolicyDetails, selected_providers: %Schema{type: :array, items: %Schema{type: :string}}, quotes: %Schema{type: :object, additionalProperties: QuoteData}, diff --git a/mix.exs b/mix.exs index 17891b3..9ec4b22 100644 --- a/mix.exs +++ b/mix.exs @@ -78,7 +78,13 @@ defmodule PolicyService.MixProject do "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], "ecto.reset": ["ecto.drop", "ecto.setup"], test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"], - precommit: ["compile --warnings-as-errors", "deps.unlock --unused", "format", "test"] + precommit: [ + "compile --warnings-as-errors", + "deps.unlock --unused", + "dialyzer", + "format", + "test" + ] ] end end diff --git a/mix.lock b/mix.lock index 21c97f6..0c97c22 100644 --- a/mix.lock +++ b/mix.lock @@ -45,9 +45,6 @@ "telemetry_registry": {:hex, :telemetry_registry, "0.3.2", "701576890320be6428189bff963e865e8f23e0ff3615eade8f78662be0fc003c", [:mix, :rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7ed191eb1d115a3034af8e1e35e4e63d5348851d556646d46ca3d1b4e16bab9"}, "thoas": {:hex, :thoas, "1.2.1", "19a25f31177a17e74004d4840f66d791d4298c5738790fa2cc73731eb911f195", [:rebar3], [], "hexpm", "e38697edffd6e91bd12cea41b155115282630075c2a727e7a6b2947f5408b86a"}, "thousand_island": {:hex, :thousand_island, "1.4.3", "2158209580f633be38d43ec4e3ce0a01079592b9657afff9080d5d8ca149a3af", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6e4ce09b0fd761a58594d02814d40f77daff460c48a7354a15ab353bb998ea0b"}, - "typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"}, - "typed_struct_ctor": {:hex, :typed_struct_ctor, "0.1.2", "00cc745439e99047615bb0700b43652311c199043293c13335151873505c5d01", [:mix], [{:ecto, "~> 3.10", [hex: :ecto, repo: "hexpm", optional: false]}, {:typed_struct_ecto_changeset, "~> 1.0.0", [hex: :typed_struct_ecto_changeset, repo: "hexpm", optional: false]}, {:typedstruct, "~> 0.5.2", [hex: :typedstruct, repo: "hexpm", optional: false]}], "hexpm", "79695303f7402f1a5b92e5914446014020b234bbfa1fccc664bacdf47101567f"}, - "typed_struct_ecto_changeset": {:hex, :typed_struct_ecto_changeset, "1.0.0", "40b6946074eabef74b44a6c55c79bbbcfda1abff9f82bd6fcbb738931937fa8f", [:mix], [], "hexpm", "9dccc15467402a75749907b7d07441638e92f45a2460cb068f0269d82bbc7a4e"}, "typedstruct": {:hex, :typedstruct, "0.5.4", "d1d33d58460a74f413e9c26d55e66fd633abd8ac0fb12639add9a11a60a0462a", [:make, :mix], [], "hexpm", "ffaef36d5dbaebdbf4ed07f7fb2ebd1037b2c1f757db6fb8e7bcbbfabbe608d8"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, "websock_adapter": {:hex, :websock_adapter, "0.5.9", "43dc3ba6d89ef5dec5b1d0a39698436a1e856d000d84bf31a3149862b01a287f", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "5534d5c9adad3c18a0f58a9371220d75a803bf0b9a3d87e6fe072faaeed76a08"}, diff --git a/priv/repo/migrations/20260310213733_create_car_policies.exs b/priv/repo/migrations/20260310213733_create_car_policies.exs index 02eb6b6..42aeafb 100644 --- a/priv/repo/migrations/20260310213733_create_car_policies.exs +++ b/priv/repo/migrations/20260310213733_create_car_policies.exs @@ -7,11 +7,14 @@ defmodule PolicyService.Repo.Migrations.CreatePolicyApplications do add :application_id, :string, null: false add :org_id, :string, null: false add :submitted_by, :string, null: false - # "car" | "life" | "fire" + # "car" | "life" | "fire_structure" | "fire_contents" add :policy_type, :string, null: false - # Applicant — full map, shape varies by individual vs corporate - add :applicant_info, :map, default: %{} + # Insured — full map, shape varies by individual vs corporate + add :insured, :map, default: %{} + + # Buyer — full map, shape varies by individual vs corporate + add :buyer, :map, default: %{} # Policy-type-specific details — shape varies by policy_type add :policy_details, :map, default: %{} @@ -20,15 +23,15 @@ defmodule PolicyService.Repo.Migrations.CreatePolicyApplications do add :selected_providers, {:array, :string}, default: [] add :quotes, :map, default: %{} - # Accepted plan - add :accepted_plan_id, :string - add :accepted_by, :string + # Accepted plan + add :accepted_plan_id, :string + add :accepted_by, :string - # Issued policy - add :provider_policy_number, :string - add :premium, :decimal - add :effective_date, :date - add :expiry_date, :date + # Issued policy + add :provider_policy_number, :string + add :premium, :decimal + add :effective_date, :date + add :expiry_date, :date # Status + timestamps add :status, :string, null: false