init commit
All checks were successful
Build and Publish / build-release (push) Successful in 4m46s

This commit is contained in:
2026-04-15 15:31:56 -05:00
commit f566d04a04
41 changed files with 2430 additions and 0 deletions

View File

@@ -0,0 +1,341 @@
defmodule ProviderService.Aggregates.Provider do
defstruct [
:provider_id,
:name,
:email,
:phone,
:contact_name,
:ruc,
:address,
:active,
templates: %{},
default_templates: %{}
]
alias ProviderService.Commands.{
RegisterProvider,
UpdateProvider,
DeactivateProvider,
ReactivateProvider,
AddProviderTemplate,
ActivateProviderTemplate,
DeactivateProviderTemplate,
SetDefaultProviderTemplate,
RemoveProviderTemplate
}
alias ProviderService.Events.{
ProviderRegistered,
ProviderUpdated,
ProviderDeactivated,
ProviderReactivated,
ProviderTemplateAdded,
ProviderTemplateActivated,
ProviderTemplateDeactivated,
ProviderTemplateDefaultSet,
ProviderTemplateRemoved
}
# ---------------------------------------------------------------------------
# Execute — Provider
# ---------------------------------------------------------------------------
def execute(%__MODULE__{provider_id: nil}, %RegisterProvider{} = cmd) do
%ProviderRegistered{
provider_id: cmd.provider_id,
name: cmd.name,
email: cmd.email,
phone: cmd.phone,
contact_name: cmd.contact_name,
ruc: cmd.ruc,
address: cmd.address,
registered_at: DateTime.utc_now()
}
end
def execute(%__MODULE__{active: false}, %UpdateProvider{}),
do: {:error, :provider_inactive}
def execute(%__MODULE__{} = agg, %UpdateProvider{} = cmd) do
%ProviderUpdated{
provider_id: agg.provider_id,
name: cmd.name,
email: cmd.email,
phone: cmd.phone,
contact_name: cmd.contact_name,
ruc: cmd.ruc,
address: cmd.address,
updated_at: DateTime.utc_now()
}
end
def execute(%__MODULE__{active: false}, %DeactivateProvider{}),
do: {:error, :already_inactive}
def execute(%__MODULE__{} = agg, %DeactivateProvider{} = cmd) do
%ProviderDeactivated{
provider_id: agg.provider_id,
deactivated_by: cmd.deactivated_by,
deactivated_at: DateTime.utc_now()
}
end
def execute(%__MODULE__{active: true}, %ReactivateProvider{}),
do: {:error, :already_active}
def execute(%__MODULE__{} = agg, %ReactivateProvider{} = cmd) do
%ProviderReactivated{
provider_id: agg.provider_id,
reactivated_by: cmd.reactivated_by,
reactivated_at: DateTime.utc_now()
}
end
# ---------------------------------------------------------------------------
# Execute — Templates
# ---------------------------------------------------------------------------
def execute(%__MODULE__{active: false}, %AddProviderTemplate{}),
do: {:error, :provider_inactive}
def execute(%__MODULE__{} = agg, %AddProviderTemplate{} = cmd) do
existing = get_in(agg.templates, [cmd.policy_type, cmd.client_type]) || []
version = length(existing) + 1
%ProviderTemplateAdded{
provider_id: agg.provider_id,
template_id: cmd.template_id,
policy_type: cmd.policy_type,
client_type: cmd.client_type,
s3_key: cmd.s3_key,
fields: cmd.fields,
version: version,
added_at: DateTime.utc_now()
}
end
def execute(%__MODULE__{} = agg, %ActivateProviderTemplate{} = cmd) do
case find_template(agg, cmd.policy_type, cmd.client_type, cmd.template_id) do
nil ->
{:error, :template_not_found}
_ ->
%ProviderTemplateActivated{
provider_id: agg.provider_id,
template_id: cmd.template_id,
policy_type: cmd.policy_type,
client_type: cmd.client_type,
activated_at: DateTime.utc_now()
}
end
end
def execute(%__MODULE__{} = agg, %DeactivateProviderTemplate{} = cmd) do
case find_template(agg, cmd.policy_type, cmd.client_type, cmd.template_id) do
nil ->
{:error, :template_not_found}
_ ->
%ProviderTemplateDeactivated{
provider_id: agg.provider_id,
template_id: cmd.template_id,
policy_type: cmd.policy_type,
client_type: cmd.client_type,
deactivated_at: DateTime.utc_now()
}
end
end
def execute(%__MODULE__{} = agg, %SetDefaultProviderTemplate{} = cmd) do
case find_template(agg, cmd.policy_type, cmd.client_type, cmd.template_id) do
nil ->
{:error, :template_not_found}
%{active: false} ->
{:error, :template_not_active}
_ ->
%ProviderTemplateDefaultSet{
provider_id: agg.provider_id,
template_id: cmd.template_id,
policy_type: cmd.policy_type,
client_type: cmd.client_type,
set_at: DateTime.utc_now()
}
end
end
def execute(%__MODULE__{} = agg, %RemoveProviderTemplate{} = cmd) do
case find_template(agg, cmd.policy_type, cmd.client_type, cmd.template_id) do
nil ->
{:error, :template_not_found}
_ ->
%ProviderTemplateRemoved{
provider_id: agg.provider_id,
template_id: cmd.template_id,
policy_type: cmd.policy_type,
client_type: cmd.client_type,
removed_at: DateTime.utc_now()
}
end
end
# ---------------------------------------------------------------------------
# Apply — Provider
# ---------------------------------------------------------------------------
def apply(%__MODULE__{} = agg, %ProviderRegistered{} = e) do
%__MODULE__{
agg
| provider_id: e.provider_id,
name: e.name,
email: e.email,
phone: e.phone,
contact_name: e.contact_name,
ruc: e.ruc,
address: e.address,
active: true
}
end
def apply(%__MODULE__{} = agg, %ProviderUpdated{} = e) do
%__MODULE__{
agg
| name: e.name,
email: e.email,
phone: e.phone,
contact_name: e.contact_name,
ruc: e.ruc,
address: e.address
}
end
def apply(%__MODULE__{} = agg, %ProviderDeactivated{}),
do: %__MODULE__{agg | active: false}
def apply(%__MODULE__{} = agg, %ProviderReactivated{}),
do: %__MODULE__{agg | active: true}
# ---------------------------------------------------------------------------
# Apply — Templates
# ---------------------------------------------------------------------------
def apply(%__MODULE__{} = agg, %ProviderTemplateAdded{} = e) do
existing = get_in(agg.templates, [e.policy_type, e.client_type]) || []
templates =
agg.templates
|> Map.update(e.policy_type, %{e.client_type => []}, fn inner ->
Map.update(inner, e.client_type, [], fn list -> list end)
end)
|> put_in(
[e.policy_type, e.client_type],
existing ++
[
%{
template_id: e.template_id,
s3_key: e.s3_key,
fields: e.fields,
version: e.version,
active: true
}
]
)
%__MODULE__{agg | templates: templates}
end
def apply(%__MODULE__{} = agg, %ProviderTemplateActivated{} = e) do
templates =
update_template(
agg.templates,
e.policy_type,
e.client_type,
e.template_id,
&Map.put(&1, :active, true)
)
%__MODULE__{agg | templates: templates}
end
def apply(%__MODULE__{} = agg, %ProviderTemplateDeactivated{} = e) do
templates =
update_template(
agg.templates,
e.policy_type,
e.client_type,
e.template_id,
&Map.put(&1, :active, false)
)
template_id = e.template_id
# Clear default if the deactivated template was the default
default_templates =
case get_in(agg.default_templates, [e.policy_type, e.client_type]) do
^template_id ->
update_in(agg.default_templates, [e.policy_type], &Map.delete(&1, e.client_type))
_ ->
agg.default_templates
end
%__MODULE__{agg | templates: templates, default_templates: default_templates}
end
def apply(%__MODULE__{} = agg, %ProviderTemplateDefaultSet{} = e) do
default_templates =
agg.default_templates
|> Map.update(e.policy_type, %{e.client_type => e.template_id}, fn inner ->
Map.put(inner, e.client_type, e.template_id)
end)
%__MODULE__{agg | default_templates: default_templates}
end
def apply(%__MODULE__{} = agg, %ProviderTemplateRemoved{} = e) do
templates =
agg.templates
|> update_in([e.policy_type, e.client_type], fn list ->
Enum.reject(list || [], &(&1.template_id == e.template_id))
end)
template_id = e.template_id
# Clear default if the removed template was the default
default_templates =
case get_in(agg.default_templates, [e.policy_type, e.client_type]) do
^template_id ->
update_in(agg.default_templates, [e.policy_type], &Map.delete(&1, e.client_type))
_ ->
agg.default_templates
end
%__MODULE__{agg | templates: templates, default_templates: default_templates}
end
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
# templates structure: %{ policy_type => %{ client_type => [%{template_id, ...}] } }
# default_templates: %{ policy_type => %{ client_type => template_id } }
defp find_template(agg, policy_type, client_type, template_id) do
agg.templates
|> get_in([policy_type, client_type])
|> List.wrap()
|> Enum.find(&(&1.template_id == template_id))
end
defp update_template(templates, policy_type, client_type, template_id, fun) do
templates
|> Map.update(policy_type, %{}, fn inner ->
Map.update(inner, client_type, [], fn list ->
Enum.map(list, fn t ->
if t.template_id == template_id, do: fun.(t), else: t
end)
end)
end)
end
end