mirror of
https://codeberg.org/JasterV/spazio-solazzo.git
synced 2026-04-26 18:20:03 +00:00
192 lines
5.6 KiB
Elixir
192 lines
5.6 KiB
Elixir
defmodule SpazioSolazzo.BookingSystem.Booking do
|
|
@moduledoc """
|
|
Represents a customer booking with state management for reservation lifecycle.
|
|
"""
|
|
|
|
use Ash.Resource,
|
|
otp_app: :spazio_solazzo,
|
|
domain: SpazioSolazzo.BookingSystem,
|
|
data_layer: AshPostgres.DataLayer,
|
|
notifiers: [Ash.Notifier.PubSub],
|
|
authorizers: [Ash.Policy.Authorizer],
|
|
extensions: [AshStateMachine]
|
|
|
|
alias SpazioSolazzo.BookingSystem.Booking.EmailWorker
|
|
|
|
postgres do
|
|
table "bookings"
|
|
repo SpazioSolazzo.Repo
|
|
|
|
references do
|
|
reference :user, on_delete: :nilify, index?: true
|
|
end
|
|
end
|
|
|
|
state_machine do
|
|
initial_states([:reserved])
|
|
default_initial_state(:reserved)
|
|
|
|
transitions do
|
|
transition(:confirm_booking, from: :reserved, to: :completed)
|
|
transition(:cancel, from: :reserved, to: :cancelled)
|
|
end
|
|
end
|
|
|
|
actions do
|
|
defaults [:read]
|
|
|
|
read :list_active_asset_bookings_by_date do
|
|
argument :asset_id, :uuid, allow_nil?: false
|
|
argument :date, :date, allow_nil?: false
|
|
|
|
filter expr(
|
|
asset_id == ^arg(:asset_id) and date == ^arg(:date) and
|
|
state in [:reserved, :completed]
|
|
)
|
|
end
|
|
|
|
create :create do
|
|
argument :time_slot_template_id, :uuid, allow_nil?: false
|
|
argument :asset_id, :uuid, allow_nil?: false
|
|
argument :user_id, :uuid, allow_nil?: false
|
|
argument :date, :date, allow_nil?: false
|
|
argument :customer_name, :string, allow_nil?: false
|
|
argument :customer_email, :string, allow_nil?: false
|
|
argument :customer_phone, :string, allow_nil?: false
|
|
argument :customer_comment, :string, allow_nil?: true
|
|
|
|
change manage_relationship(:time_slot_template_id, :time_slot_template,
|
|
type: :append_and_remove
|
|
)
|
|
|
|
change manage_relationship(:asset_id, :asset, type: :append_and_remove)
|
|
|
|
change manage_relationship(:user_id, :user, type: :append_and_remove, authorize?: false)
|
|
|
|
change fn changeset, _ctx ->
|
|
template_id = Ash.Changeset.get_argument(changeset, :time_slot_template_id)
|
|
|
|
case Ash.get(SpazioSolazzo.BookingSystem.TimeSlotTemplate, template_id) do
|
|
{:ok, template} ->
|
|
changeset
|
|
|> Ash.Changeset.force_change_attribute(:start_time, template.start_time)
|
|
|> Ash.Changeset.force_change_attribute(:end_time, template.end_time)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:date,
|
|
Ash.Changeset.get_argument(changeset, :date)
|
|
)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:customer_name,
|
|
Ash.Changeset.get_argument(changeset, :customer_name)
|
|
)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:customer_email,
|
|
Ash.Changeset.get_argument(changeset, :customer_email)
|
|
)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:customer_phone,
|
|
Ash.Changeset.get_argument(changeset, :customer_phone)
|
|
)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:customer_comment,
|
|
Ash.Changeset.get_argument(changeset, :customer_comment)
|
|
)
|
|
|
|
{:error, _} ->
|
|
Ash.Changeset.add_error(changeset,
|
|
field: :time_slot_template_id,
|
|
message: "Template not found"
|
|
)
|
|
end
|
|
end
|
|
|
|
change after_action(fn _changeset, booking, _ctx ->
|
|
%{
|
|
booking_id: booking.id,
|
|
customer_name: booking.customer_name,
|
|
customer_email: booking.customer_email,
|
|
customer_phone: booking.customer_phone,
|
|
customer_comment: booking.customer_comment,
|
|
date: Calendar.strftime(booking.date, "%A, %B %d"),
|
|
start_time: booking.start_time,
|
|
end_time: booking.end_time
|
|
}
|
|
|> EmailWorker.new()
|
|
|> Oban.insert!()
|
|
|
|
{:ok, booking}
|
|
end)
|
|
end
|
|
|
|
update :confirm_booking do
|
|
accept []
|
|
change transition_state(:completed)
|
|
end
|
|
|
|
update :cancel do
|
|
accept []
|
|
change transition_state(:cancelled)
|
|
end
|
|
|
|
destroy :destroy do
|
|
description "Delete a booking record"
|
|
primary? true
|
|
end
|
|
end
|
|
|
|
policies do
|
|
policy action([:cancel, :confirm_booking]) do
|
|
authorize_if always()
|
|
end
|
|
|
|
policy action_type(:destroy) do
|
|
authorize_if expr(:user_id == ^actor(:id))
|
|
end
|
|
|
|
policy action_type(:read) do
|
|
authorize_if always()
|
|
end
|
|
|
|
policy action_type(:create) do
|
|
authorize_if always()
|
|
end
|
|
end
|
|
|
|
pub_sub do
|
|
module SpazioSolazzoWeb.Endpoint
|
|
prefix "booking"
|
|
|
|
publish :create, ["created"]
|
|
publish :cancel, ["cancelled"]
|
|
end
|
|
|
|
attributes do
|
|
uuid_primary_key :id
|
|
attribute :date, :date, allow_nil?: false
|
|
attribute :customer_name, :string, allow_nil?: false
|
|
attribute :customer_email, :string, allow_nil?: false
|
|
attribute :start_time, :time, allow_nil?: false
|
|
attribute :end_time, :time, allow_nil?: false
|
|
attribute :customer_phone, :string, allow_nil?: false
|
|
attribute :customer_comment, :string, allow_nil?: true
|
|
|
|
attribute :state, :atom do
|
|
allow_nil? false
|
|
default :reserved
|
|
public? true
|
|
constraints one_of: [:reserved, :completed, :cancelled]
|
|
end
|
|
|
|
create_timestamp :inserted_at
|
|
update_timestamp :updated_at
|
|
end
|
|
|
|
relationships do
|
|
belongs_to :asset, SpazioSolazzo.BookingSystem.Asset
|
|
belongs_to :time_slot_template, SpazioSolazzo.BookingSystem.TimeSlotTemplate
|
|
|
|
belongs_to :user, SpazioSolazzo.Accounts.User do
|
|
allow_nil? true
|
|
end
|
|
end
|
|
end
|