auction_fun_core 0.8.5 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.standard.yml +2 -0
  3. data/CHANGELOG.md +48 -0
  4. data/Procfile +1 -0
  5. data/README.md +34 -32
  6. data/Rakefile +1 -1
  7. data/auction_fun_core.gemspec +1 -0
  8. data/db/migrate/20240229143000_create_auctions.rb +1 -0
  9. data/db/seeds.rb +87 -36
  10. data/i18n/en-US/contracts/contracts.en-US.yml +12 -0
  11. data/i18n/en-US/mail/application.en-US.yml +66 -0
  12. data/i18n/en-US/mail/auction_context/post_auction/participant.en-US.yml +13 -0
  13. data/i18n/en-US/mail/auction_context/post_auction/winner.en-US.yml +13 -0
  14. data/i18n/en-US/mail/auction_context/pre_auction/auction_start_reminder.en-US.yml +11 -0
  15. data/i18n/pt-BR/contracts/contracts.pt-BR.yml +12 -0
  16. data/i18n/pt-BR/mail/application.pt-BR.yml +66 -0
  17. data/i18n/pt-BR/mail/auction_context/post_auction/participant.pt-BR.yml +13 -0
  18. data/i18n/pt-BR/mail/auction_context/post_auction/winner.pt-BR.yml +13 -0
  19. data/i18n/pt-BR/mail/auction_context/pre_auction/auction_start_reminder.pt-BR.yml +11 -0
  20. data/i18n/pt-BR/mail/user_context/registration.pt-BR.yml +0 -4
  21. data/lib/auction_fun_core/business/configuration.rb +31 -0
  22. data/lib/auction_fun_core/business/token_generator.rb +19 -1
  23. data/lib/auction_fun_core/contracts/application_contract.rb +9 -1
  24. data/lib/auction_fun_core/contracts/auction_context/create_contract.rb +35 -20
  25. data/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb +64 -0
  26. data/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb +62 -0
  27. data/lib/auction_fun_core/contracts/auction_context/pre_auction/auction_start_reminder_contract.rb +48 -0
  28. data/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb +59 -0
  29. data/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb +60 -0
  30. data/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb +60 -0
  31. data/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb +16 -4
  32. data/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb +17 -5
  33. data/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb +16 -4
  34. data/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb +20 -11
  35. data/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb +18 -9
  36. data/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb +19 -10
  37. data/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb +18 -4
  38. data/lib/auction_fun_core/contracts/staff_context/registration_contract.rb +20 -8
  39. data/lib/auction_fun_core/contracts/user_context/authentication_contract.rb +18 -4
  40. data/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb +17 -2
  41. data/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb +17 -2
  42. data/lib/auction_fun_core/contracts/user_context/registration_contract.rb +26 -8
  43. data/lib/auction_fun_core/entities/auction.rb +52 -2
  44. data/lib/auction_fun_core/entities/bid.rb +3 -2
  45. data/lib/auction_fun_core/entities/staff.rb +15 -2
  46. data/lib/auction_fun_core/entities/user.rb +31 -2
  47. data/lib/auction_fun_core/events/app.rb +8 -2
  48. data/lib/auction_fun_core/events/listener.rb +19 -16
  49. data/lib/auction_fun_core/operations/auction_context/create_operation.rb +37 -11
  50. data/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb +85 -0
  51. data/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb +85 -0
  52. data/lib/auction_fun_core/operations/auction_context/pre_auction/auction_start_reminder_operation.rb +96 -0
  53. data/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb +172 -0
  54. data/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb +171 -0
  55. data/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb +171 -0
  56. data/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb +36 -1
  57. data/lib/auction_fun_core/operations/auction_context/processor/start_operation.rb +23 -11
  58. data/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb +36 -1
  59. data/lib/auction_fun_core/operations/bid_context/create_bid_penny_operation.rb +57 -7
  60. data/lib/auction_fun_core/operations/staff_context/registration_operation.rb +10 -0
  61. data/lib/auction_fun_core/relations/auctions.rb +252 -30
  62. data/lib/auction_fun_core/relations/bids.rb +18 -0
  63. data/lib/auction_fun_core/relations/staffs.rb +1 -1
  64. data/lib/auction_fun_core/repos/auction_context/auction_repository.rb +40 -11
  65. data/lib/auction_fun_core/repos/bid_context/bid_repository.rb +27 -5
  66. data/lib/auction_fun_core/repos/staff_context/staff_repository.rb +63 -21
  67. data/lib/auction_fun_core/repos/user_context/user_repository.rb +69 -25
  68. data/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb +37 -0
  69. data/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb +37 -0
  70. data/lib/auction_fun_core/services/mail/auction_context/pre_auction/auction_start_reminder_mailer.rb +35 -0
  71. data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/participant.html.erb +173 -0
  72. data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/winner.html.erb +174 -0
  73. data/lib/auction_fun_core/services/mail/templates/auction_context/pre_auction/auction_start_reminder.html.erb +192 -0
  74. data/lib/auction_fun_core/services/mail/templates/user_context/registration.html.erb +2 -2
  75. data/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb +6 -0
  76. data/lib/auction_fun_core/version.rb +1 -1
  77. data/lib/auction_fun_core/workers/application_job.rb +12 -0
  78. data/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb +38 -0
  79. data/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb +37 -0
  80. data/lib/auction_fun_core/workers/operations/auction_context/pre_auction/auction_start_reminder_operation_job.rb +44 -0
  81. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb +37 -0
  82. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb +40 -0
  83. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb +38 -0
  84. data/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb +6 -3
  85. data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb +56 -0
  86. data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb +57 -0
  87. data/lib/auction_fun_core/workers/services/mail/auction_context/pre_auction/auction_start_reminder_mailer_job.rb +48 -0
  88. data/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb +8 -6
  89. data/system/providers/background_job.rb +25 -0
  90. metadata +51 -5
  91. data/lib/auction_fun_core/contracts/auction_context/processor/finish_contract.rb +0 -27
  92. data/lib/auction_fun_core/operations/auction_context/processor/finish_operation.rb +0 -61
  93. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish_operation_job.rb +0 -32
@@ -2,8 +2,9 @@
2
2
 
3
3
  module AuctionFunCore
4
4
  module Entities
5
- # Bid Relations class. This return simple objects with attribute readers
6
- # to represent data in your bid.
5
+ ##
6
+ # Defines the Bid class as Entity. It appears to be a simple data structure
7
+ # class representing bid-related information.
7
8
  class Bid < ROM::Struct
8
9
  end
9
10
  end
@@ -2,17 +2,30 @@
2
2
 
3
3
  module AuctionFunCore
4
4
  module Entities
5
- # Staff Relations class. This return simple objects with attribute readers
6
- # to represent data in your staff.
5
+ ##
6
+ # Defines the Staff class as Entity. It appears to be a simple data structure
7
+ # class representing staff-related information.
7
8
  class Staff < ROM::Struct
9
+ ##
10
+ # Checks if the staff is active.
11
+ #
12
+ # @return [Boolean] True if the staff is active, otherwise false.
8
13
  def active?
9
14
  active
10
15
  end
11
16
 
17
+ ##
18
+ # Checks if the staff is inactive.
19
+ #
20
+ # @return [Boolean] True if the staff is inactive, otherwise false.
12
21
  def inactive?
13
22
  !active
14
23
  end
15
24
 
25
+ ##
26
+ # Returns staff information excluding password digest.
27
+ #
28
+ # @return [Hash] Staff information.
16
29
  def info
17
30
  attributes.except(:password_digest)
18
31
  end
@@ -2,33 +2,62 @@
2
2
 
3
3
  module AuctionFunCore
4
4
  module Entities
5
- # User Relations class. This return simple objects with attribute readers
6
- # to represent data in your user.
5
+ ##
6
+ # Defines the User class as Entity. It appears to be a simple data structure
7
+ # class representing user-related information.
7
8
  class User < ROM::Struct
9
+ ##
10
+ # Checks if the user is active.
11
+ #
12
+ # @return [Boolean] True if the user is active, otherwise false.
8
13
  def active?
9
14
  active
10
15
  end
11
16
 
17
+ ##
18
+ # Checks if the user is inactive.
19
+ #
20
+ # @return [Boolean] True if the user is inactive, otherwise false.
12
21
  def inactive?
13
22
  !active
14
23
  end
15
24
 
25
+ ##
26
+ # Checks if the user has been confirmed.
27
+ #
28
+ # @return [Boolean] True if the user is confirmed, otherwise false.
16
29
  def confirmed?
17
30
  confirmed_at.present?
18
31
  end
19
32
 
33
+ ##
34
+ # Checks if the user's email has been confirmed.
35
+ #
36
+ # @return [Boolean] True if the email is confirmed, otherwise false.
20
37
  def email_confirmed?
21
38
  email_confirmation_at.present?
22
39
  end
23
40
 
41
+ ##
42
+ # Checks if the user's phone has been confirmed.
43
+ #
44
+ # @return [Boolean] True if the phone is confirmed, otherwise false.
24
45
  def phone_confirmed?
25
46
  phone_confirmation_at.present?
26
47
  end
27
48
 
49
+ ##
50
+ # Returns user information excluding password digest.
51
+ #
52
+ # @return [Hash] User information.
28
53
  def info
29
54
  attributes.except(:password_digest)
30
55
  end
31
56
 
57
+ ##
58
+ # Returns the user's balance as a Money object.
59
+ #
60
+ # @return [Money] User's balance.
32
61
  def balance
33
62
  Money.new(balance_cents, balance_currency)
34
63
  end
@@ -2,23 +2,29 @@
2
2
 
3
3
  module AuctionFunCore
4
4
  module Events
5
- # Event class to register business events on system.
5
+ ##
6
+ # Represents the main application class for registering business events in the system.
7
+ #
8
+ # This class includes Dry::Events::Publisher[:app] to enable event publishing functionality.
6
9
  # @see https://dry-rb.org/gems/dry-events/main/
7
10
  class App
8
- # @!parser include Dry::Events::Publisher[:app]
9
11
  include Dry::Events::Publisher[:app]
10
12
 
13
+ # Registers events related to auctions.
11
14
  register_event("auctions.created")
12
15
  register_event("auctions.started")
13
16
  register_event("auctions.finished")
14
17
  register_event("auctions.paused")
15
18
  register_event("auctions.unpaused")
16
19
 
20
+ # Registers events related to bids.
17
21
  register_event("bids.created")
18
22
 
23
+ # Registers events related to staffs.
19
24
  register_event("staffs.authentication")
20
25
  register_event("staffs.registration")
21
26
 
27
+ # Registers events related to users.
22
28
  register_event("users.authentication")
23
29
  register_event("users.registration")
24
30
  register_event("users.confirmation")
@@ -2,7 +2,10 @@
2
2
 
3
3
  module AuctionFunCore
4
4
  module Events
5
- # Event class that can listen business events.
5
+ ##
6
+ # Represents a class that listens to business events and performs actions accordingly.
7
+ #
8
+ # This class defines methods to handle various events related to auctions, bids, staff, and users.
6
9
  # @see https://dry-rb.org/gems/dry-events/main/#event-listeners
7
10
  class Listener
8
11
  # Listener for to *auctions.created* event.
@@ -36,15 +39,15 @@ module AuctionFunCore
36
39
  end
37
40
 
38
41
  # Listener for to *bids.created* event.
39
- # @param event [Integer] Auction ID
42
+ # @param event [ROM::Struct::Bid] Auction ID
40
43
  def on_bids_created(bid)
41
44
  logger("Create bid with: #{bid.to_h}")
42
45
  end
43
46
 
44
- # Listener for to *staffs.authentication* event.
45
- # @param attributes [Hash] Authentication attributes
46
- # @option staff_id [Integer] Staff ID
47
- # @option time [DateTime] Authentication time
47
+ # Listener for the *staffs.authentication* event.
48
+ # @param attributes [Hash] Authentication attributes.
49
+ # @option attributes staff_id [Integer] Staff ID.
50
+ # @option attributes time [DateTime] Authentication time.
48
51
  def on_staffs_authentication(attributes)
49
52
  logger("Staff #{attributes[:staff_id]} authenticated on: #{attributes[:time].iso8601}")
50
53
  end
@@ -61,26 +64,26 @@ module AuctionFunCore
61
64
  logger("New registered user: #{user.to_h}")
62
65
  end
63
66
 
64
- # Listener for to *users.authentication* event.
65
- # @param attributes [Hash] Authentication attributes
66
- # @option user_id [Integer] User ID
67
- # @option time [DateTime] Authentication time
67
+ # Listener for the *users.authentication* event.
68
+ # @param attributes [Hash] Authentication attributes.
69
+ # @option attributes user_id [Integer] User ID.
70
+ # @option attributes time [DateTime] Authentication time.
68
71
  def on_users_authentication(attributes)
69
72
  logger("User #{attributes[:user_id]} authenticated on: #{attributes[:time].iso8601}")
70
73
  end
71
74
 
72
- # Listener for to *users.confirmation* event.
73
- # @param attributes [Hash] Confirmation attributes
74
- # @option user_id [Integer] User ID
75
- # @option time [DateTime] Authentication time
75
+ # Listener for the *users.confirmation* event.
76
+ # @param attributes [Hash] Confirmation attributes.
77
+ # @option user_id [Integer] User ID.
78
+ # @option time [DateTime] Authentication time.
76
79
  def on_users_confirmation(attributes)
77
80
  logger("User #{attributes[:user_id]} confirmed at: #{attributes[:time].iso8601}")
78
81
  end
79
82
 
80
83
  private
81
84
 
82
- # Append message to system log.
83
- # @param message [String] the message
85
+ # Appends a message to the system log.
86
+ # @param message [String] The message.
84
87
  def logger(message)
85
88
  Application[:logger].info(message)
86
89
  end
@@ -10,6 +10,7 @@ module AuctionFunCore
10
10
  include Import["repos.auction_context.auction_repository"]
11
11
  include Import["contracts.auction_context.create_contract"]
12
12
  include Import["workers.operations.auction_context.processor.start_operation_job"]
13
+ include Import["workers.operations.auction_context.pre_auction.auction_start_reminder_operation_job"]
13
14
 
14
15
  # @todo Add custom doc
15
16
  def self.call(attributes, &block)
@@ -21,11 +22,13 @@ module AuctionFunCore
21
22
  end
22
23
 
23
24
  def call(attributes)
24
- values = yield validate(attributes)
25
+ values = yield validate_contract(attributes)
26
+ values = yield assign_default_values(values)
25
27
 
26
28
  auction_repository.transaction do |_t|
27
29
  @auction = yield persist(values)
28
30
  yield scheduled_start_auction(@auction)
31
+ yield schedule_auction_notification(@auction)
29
32
  yield publish_auctions_created(@auction)
30
33
  end
31
34
 
@@ -38,7 +41,7 @@ module AuctionFunCore
38
41
  # of the informed attributes.
39
42
  # @param attrs [Hash] auction attributes
40
43
  # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
41
- def validate(attrs)
44
+ def validate_contract(attrs)
42
45
  contract = create_contract.call(attrs)
43
46
 
44
47
  return Failure(contract.errors.to_h) if contract.failure?
@@ -46,6 +49,15 @@ module AuctionFunCore
46
49
  Success(contract.to_h)
47
50
  end
48
51
 
52
+ # By default, the auction status is set to 'scheduled'.
53
+ # @todo Refactor this method in the future to consider the status as of the auction start date.
54
+ # @param attrs [Hash] auction attributes
55
+ # @return [Dry::Monads::Result::Success]
56
+ def assign_default_values(attrs)
57
+ attrs[:status] = "scheduled"
58
+ Success(attrs)
59
+ end
60
+
49
61
  # Calls the auction repository class to persist the attributes in the database.
50
62
  # @param result [Hash] Auction validated attributes
51
63
  # @return [ROM::Struct::Auction]
@@ -53,15 +65,6 @@ module AuctionFunCore
53
65
  Success(auction_repository.create(result))
54
66
  end
55
67
 
56
- # Triggers the publication of event *auctions.created*.
57
- # @param auction [Hash] Auction persisted attributes
58
- # @return [Dry::Monads::Result::Success]
59
- def publish_auctions_created(auction)
60
- Application[:event].publish("auctions.created", auction.to_h)
61
-
62
- Success()
63
- end
64
-
65
68
  # Calls the background job class that will schedule the start of the auction.
66
69
  # Added a small delay to perform operations (such as sending broadcasts and/or other operations).
67
70
  # @param auction [ROM::Struct::Auction]
@@ -71,6 +74,29 @@ module AuctionFunCore
71
74
 
72
75
  Success(start_operation_job.class.perform_at(perform_at, auction.id))
73
76
  end
77
+
78
+ # Schedules a notification to be sent to users one hour before the auction starts.
79
+ # The scheduling is only done if the start of the auction is more than one hour ahead of the current time,
80
+ # ensuring that there is sufficient time for the notification to be sent.
81
+ #
82
+ # @param auction [ROM::Struct::Auction]
83
+ # @return [String] sidekiq jid
84
+ def schedule_auction_notification(auction)
85
+ perform_time = auction.started_at - 1.hour
86
+
87
+ return Success() if perform_time <= Time.current
88
+
89
+ Success(auction_start_reminder_operation_job.class.perform_at(perform_time, auction.id))
90
+ end
91
+
92
+ # Triggers the publication of event *auctions.created*.
93
+ # @param auction [ROM::Struct::Auction]
94
+ # @return [Dry::Monads::Result::Success]
95
+ def publish_auctions_created(auction)
96
+ Application[:event].publish("auctions.created", auction.to_h)
97
+
98
+ Success()
99
+ end
74
100
  end
75
101
  end
76
102
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Operations
5
+ module AuctionContext
6
+ module PostAuction
7
+ ##
8
+ # Operation class for managing participants in auctions.
9
+ #
10
+ class ParticipantOperation < AuctionFunCore::Operations::Base
11
+ include Import["repos.user_context.user_repository"]
12
+ include Import["contracts.auction_context.post_auction.participant_contract"]
13
+ include Import["workers.services.mail.auction_context.post_auction.participant_mailer_job"]
14
+
15
+ ##
16
+ # Executes the participant operation with the provided attributes.
17
+ #
18
+ # @param attributes [Hash] The attributes for the winner operation.
19
+ # @option attributes auction_id [Integer] The ID of the auction.
20
+ # @option attributes participant_id [Integer] The participating user ID.
21
+ # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation.
22
+ # @return [Dry::Matcher::Evaluator] The result of the operation.
23
+ #
24
+ # @example
25
+ # attributes = { auction_id: 123, participant_id: 123 }
26
+ #
27
+ # AuctionFunCore::Operations::AuctionContext::PostAuction::ParticipantOperation.call(attributes) do |result|
28
+ # result.success { |auction| puts "Participation operation completed successfully! #{auction.to_h}" }
29
+ # result.failure { |failure| puts "Failed auction participation operation: #{failure.errors.to_h}"}
30
+ # end
31
+ def self.call(attributes, &block)
32
+ operation = new.call(attributes)
33
+
34
+ return operation unless block
35
+
36
+ Dry::Matcher::ResultMatcher.call(operation, &block)
37
+ end
38
+
39
+ ##
40
+ # Executes the participant operation.
41
+ #
42
+ # @param attributes [Hash] The attributes for the participant operation.
43
+ # @return [Dry::Monads::Result] The result of the operation.
44
+ #
45
+ def call(attributes)
46
+ auction, participant = yield validate_contract(attributes)
47
+
48
+ user_repository.transaction do |_t|
49
+ yield send_participant_email_with_statistics_and_payment_instructions(auction.id, participant.id)
50
+ end
51
+
52
+ Success([auction, participant])
53
+ end
54
+
55
+ private
56
+
57
+ ##
58
+ # Validates the contract with the provided attributes.
59
+ #
60
+ # @param attributes [Hash] The attributes to validate.
61
+ # @return [Dry::Monads::Result] The result of the validation.
62
+ #
63
+ def validate_contract(attributes)
64
+ contract = participant_contract.call(attributes)
65
+
66
+ return Failure(contract.errors.to_h) if contract.failure?
67
+
68
+ Success([contract.context[:auction], contract.context[:participant]])
69
+ end
70
+
71
+ ##
72
+ # Sends participant email with auction statistics and payment instructions.
73
+ #
74
+ # @param auction_id [Integer] The ID of the auction.
75
+ # @param participant_id [Integer] The ID of the participant.
76
+ # @return [Dry::Monads::Result] The result of sending the email.
77
+ #
78
+ def send_participant_email_with_statistics_and_payment_instructions(auction_id, participant_id)
79
+ Success(participant_mailer_job.class.perform_async(auction_id, participant_id))
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Operations
5
+ module AuctionContext
6
+ module PostAuction
7
+ ##
8
+ # Operation class for managing winners in auctions.
9
+ #
10
+ class WinnerOperation < AuctionFunCore::Operations::Base
11
+ include Import["repos.user_context.user_repository"]
12
+ include Import["contracts.auction_context.post_auction.winner_contract"]
13
+ include Import["workers.services.mail.auction_context.post_auction.winner_mailer_job"]
14
+
15
+ ##
16
+ # Executes the winner operation with the provided attributes.
17
+ #
18
+ # @param attributes [Hash] The attributes for the winner operation.
19
+ # @option attributes auction_id [Integer] The ID of the auction.
20
+ # @option attributes winner_id [Integer] The winning user ID
21
+ # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation.
22
+ # @return [Dry::Matcher::Evaluator] The result of the operation.
23
+ #
24
+ # @example
25
+ # attributes = { auction_id: 123, winner_id: 123 }
26
+ #
27
+ # AuctionFunCore::Operations::AuctionContext::PostAuction::WinnerOperation.call(attributes) do |result|
28
+ # result.success { |auction| puts "Winner operation completed successfully! #{auction.to_h}" }
29
+ # result.failure { |failure| puts "Failed auction winner operation: #{failure.errors.to_h}"}
30
+ # end
31
+ def self.call(attributes, &block)
32
+ operation = new.call(attributes)
33
+
34
+ return operation unless block
35
+
36
+ Dry::Matcher::ResultMatcher.call(operation, &block)
37
+ end
38
+
39
+ ##
40
+ # Executes the winner operation.
41
+ #
42
+ # @param attributes [Hash] The attributes for the winner operation.
43
+ # @return [Dry::Monads::Result] The result of the operation.
44
+ #
45
+ def call(attributes)
46
+ auction, winner = yield validate_contract(attributes)
47
+
48
+ user_repository.transaction do |_t|
49
+ send_winner_email_with_statistics_and_payment_instructions(auction.id, winner.id)
50
+ end
51
+
52
+ Success([auction, winner])
53
+ end
54
+
55
+ private
56
+
57
+ ##
58
+ # Validates the contract with the provided attributes.
59
+ #
60
+ # @param attributes [Hash] The attributes to validate.
61
+ # @return [Dry::Monads::Result] The result of the validation.
62
+ #
63
+ def validate_contract(attributes)
64
+ contract = winner_contract.call(attributes)
65
+
66
+ return Failure(contract.errors.to_h) if contract.failure?
67
+
68
+ Success([contract.context[:auction], contract.context[:winner]])
69
+ end
70
+
71
+ ##
72
+ # Sends winner email with auction statistics and payment instructions.
73
+ #
74
+ # @param auction_id [Integer] The ID of the auction.
75
+ # @param winner_id [Integer] The ID of the winner.
76
+ # @return [Dry::Monads::Result] The result of sending the email.
77
+ #
78
+ def send_winner_email_with_statistics_and_payment_instructions(auction_id, winner_id)
79
+ Success(winner_mailer_job.class.perform_async(auction_id, winner_id))
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Operations
5
+ module AuctionContext
6
+ module PreAuction
7
+ ##
8
+ # Operation class for sending a reminder email to a participant about the start of an auction.
9
+ #
10
+ class AuctionStartReminderOperation < AuctionFunCore::Operations::Base
11
+ include Import["repos.bid_context.bid_repository"]
12
+ include Import["contracts.auction_context.pre_auction.auction_start_reminder_contract"]
13
+ include Import["workers.services.mail.auction_context.pre_auction.auction_start_reminder_mailer_job"]
14
+
15
+ ##
16
+ # Executes the auction start reminder operation with the provided attributes.
17
+ #
18
+ # @param attributes [Hash] The attributes for the auction start reminder operation.
19
+ # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation.
20
+ # @return [Dry::Matcher::Evaluator] The result of the operation.
21
+ #
22
+ def self.call(attributes, &block)
23
+ operation = new.call(attributes)
24
+
25
+ return operation unless block
26
+
27
+ Dry::Matcher::ResultMatcher.call(operation, &block)
28
+ end
29
+
30
+ ##
31
+ # Executes the auction start reminder operation.
32
+ #
33
+ # @param attributes [Hash] The attributes for the auction start reminder operation.
34
+ # @return [Dry::Monads::Result] The result of the operation.
35
+ #
36
+ def call(attributes)
37
+ auction = yield validate_contract(attributes)
38
+ participant_ids = yield collect_current_auction_participants(auction.id)
39
+
40
+ bid_repository.transaction do |_t|
41
+ participant_ids.each do |participant_id|
42
+ yield send_auction_start_reminder_mailer_job(auction.id, participant_id)
43
+ end
44
+ end
45
+
46
+ Success([auction, participant_ids])
47
+ end
48
+
49
+ private
50
+
51
+ ##
52
+ # Validates the contract with the provided attributes.
53
+ #
54
+ # @param attributes [Hash] The attributes to validate.
55
+ # @option auction_id [Integer] The ID of the auction.
56
+ # @return [Dry::Monads::Result] The result of the validation.
57
+ #
58
+ def validate_contract(attributes)
59
+ contract = auction_start_reminder_contract.call(attributes)
60
+
61
+ return Failure(contract.errors.to_h) if contract.failure?
62
+
63
+ Success(contract.context[:auction])
64
+ end
65
+
66
+ ##
67
+ # Collects the participant IDs for the current auction.
68
+ #
69
+ # @param auction_id [Integer] The ID of the auction.
70
+ # @return [Dry::Monads::Result] The result of collecting the participant IDs.
71
+ #
72
+ def collect_current_auction_participants(auction_id)
73
+ Success(
74
+ AuctionFunCore::Application[:container]
75
+ .relations[:bids]
76
+ .participants(auction_id)
77
+ .one
78
+ .participant_ids.to_a
79
+ )
80
+ end
81
+
82
+ ##
83
+ # Sends the auction start reminder email to a participant.
84
+ #
85
+ # @param auction_id [Integer] The ID of the auction.
86
+ # @param participant_id [Integer] The ID of the participant.
87
+ # @return [Dry::Monads::Result] The result of sending the email.
88
+ #
89
+ def send_auction_start_reminder_mailer_job(auction_id, participant_id)
90
+ Success(auction_start_reminder_mailer_job.class.perform_async(auction_id, participant_id))
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end