auction_fun_core 0.8.5 → 0.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/auction_fun_core.gemspec +1 -0
  4. data/db/migrate/20240229143000_create_auctions.rb +1 -0
  5. data/db/seeds.rb +87 -36
  6. data/i18n/en-US/contracts/contracts.en-US.yml +9 -0
  7. data/i18n/en-US/mail/application.en-US.yml +59 -0
  8. data/i18n/en-US/mail/auction_context/post_auction/participant.en-US.yml +13 -0
  9. data/i18n/en-US/mail/auction_context/post_auction/winner.en-US.yml +13 -0
  10. data/i18n/pt-BR/contracts/contracts.pt-BR.yml +9 -0
  11. data/i18n/pt-BR/mail/application.pt-BR.yml +59 -0
  12. data/i18n/pt-BR/mail/auction_context/post_auction/participant.pt-BR.yml +13 -0
  13. data/i18n/pt-BR/mail/auction_context/post_auction/winner.pt-BR.yml +13 -0
  14. data/i18n/pt-BR/mail/user_context/registration.pt-BR.yml +0 -4
  15. data/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb +42 -0
  16. data/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb +41 -0
  17. data/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb +47 -0
  18. data/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb +48 -0
  19. data/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb +48 -0
  20. data/lib/auction_fun_core/entities/auction.rb +6 -0
  21. data/lib/auction_fun_core/operations/auction_context/create_operation.rb +12 -2
  22. data/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb +52 -0
  23. data/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb +51 -0
  24. data/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb +100 -0
  25. data/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb +100 -0
  26. data/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb +102 -0
  27. data/lib/auction_fun_core/operations/auction_context/processor/start_operation.rb +23 -11
  28. data/lib/auction_fun_core/operations/bid_context/create_bid_penny_operation.rb +57 -7
  29. data/lib/auction_fun_core/operations/staff_context/registration_operation.rb +10 -0
  30. data/lib/auction_fun_core/relations/auctions.rb +167 -26
  31. data/lib/auction_fun_core/relations/staffs.rb +1 -1
  32. data/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb +31 -0
  33. data/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb +31 -0
  34. data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/participant.html.erb +173 -0
  35. data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/winner.html.erb +174 -0
  36. data/lib/auction_fun_core/services/mail/templates/user_context/registration.html.erb +2 -2
  37. data/lib/auction_fun_core/version.rb +1 -1
  38. data/lib/auction_fun_core/workers/application_job.rb +2 -0
  39. data/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb +33 -0
  40. data/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb +33 -0
  41. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb +34 -0
  42. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb +37 -0
  43. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb +34 -0
  44. data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb +51 -0
  45. data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb +51 -0
  46. data/system/providers/background_job.rb +19 -0
  47. metadata +43 -5
  48. data/lib/auction_fun_core/contracts/auction_context/processor/finish_contract.rb +0 -27
  49. data/lib/auction_fun_core/operations/auction_context/processor/finish_operation.rb +0 -61
  50. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish_operation_job.rb +0 -32
@@ -5,6 +5,8 @@ module AuctionFunCore
5
5
  # Auction Relations class. This return simple objects with attribute readers
6
6
  # to represent data in your auction.
7
7
  class Auction < ROM::Struct
8
+ INQUIRER_ATTRIBUTES = Relations::Auctions::STATUSES.values.freeze
9
+
8
10
  def initial_bid
9
11
  Money.new(initial_bid_cents, initial_bid_currency)
10
12
  end
@@ -12,6 +14,10 @@ module AuctionFunCore
12
14
  def minimal_bid
13
15
  Money.new(minimal_bid_cents, minimal_bid_currency)
14
16
  end
17
+
18
+ def winner?
19
+ winner_id.present?
20
+ end
15
21
  end
16
22
  end
17
23
  end
@@ -21,7 +21,8 @@ module AuctionFunCore
21
21
  end
22
22
 
23
23
  def call(attributes)
24
- values = yield validate(attributes)
24
+ values = yield validate_contract(attributes)
25
+ values = yield assign_default_values(values)
25
26
 
26
27
  auction_repository.transaction do |_t|
27
28
  @auction = yield persist(values)
@@ -38,7 +39,7 @@ module AuctionFunCore
38
39
  # of the informed attributes.
39
40
  # @param attrs [Hash] auction attributes
40
41
  # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
41
- def validate(attrs)
42
+ def validate_contract(attrs)
42
43
  contract = create_contract.call(attrs)
43
44
 
44
45
  return Failure(contract.errors.to_h) if contract.failure?
@@ -46,6 +47,15 @@ module AuctionFunCore
46
47
  Success(contract.to_h)
47
48
  end
48
49
 
50
+ # By default, the auction status is set to 'scheduled'.
51
+ # @todo Refactor this method in the future to consider the status as of the auction start date.
52
+ # @param attrs [Hash] auction attributes
53
+ # @return [Dry::Monads::Result::Success]
54
+ def assign_default_values(attrs)
55
+ attrs[:status] = "scheduled"
56
+ Success(attrs)
57
+ end
58
+
49
59
  # Calls the auction repository class to persist the attributes in the database.
50
60
  # @param result [Hash] Auction validated attributes
51
61
  # @return [ROM::Struct::Auction]
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Operations
5
+ module AuctionContext
6
+ module PostAuction
7
+ ##
8
+ # Operation class for finish 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
+ def self.call(attributes, &block)
16
+ operation = new.call(attributes)
17
+
18
+ return operation unless block
19
+
20
+ Dry::Matcher::ResultMatcher.call(operation, &block)
21
+ end
22
+
23
+ ## @todo Add more actions
24
+ # Send email to participant with auction statistics.
25
+ def call(attributes)
26
+ auction, participant = yield validate_contract(attributes)
27
+
28
+ user_repository.transaction do |_t|
29
+ yield send_participant_email_with_statistics_and_payment_instructions(auction.id, participant.id)
30
+ end
31
+
32
+ Success([auction, participant])
33
+ end
34
+
35
+ private
36
+
37
+ def validate_contract(attributes)
38
+ contract = participant_contract.call(attributes)
39
+
40
+ return Failure(contract.errors.to_h) if contract.failure?
41
+
42
+ Success([contract.context[:auction], contract.context[:participant]])
43
+ end
44
+
45
+ def send_participant_email_with_statistics_and_payment_instructions(auction_id, participant_id)
46
+ Success(participant_mailer_job.class.perform_async(auction_id, participant_id))
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Operations
5
+ module AuctionContext
6
+ module PostAuction
7
+ ##
8
+ # Operation class for finish 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
+ def self.call(attributes, &block)
16
+ operation = new.call(attributes)
17
+
18
+ return operation unless block
19
+
20
+ Dry::Matcher::ResultMatcher.call(operation, &block)
21
+ end
22
+
23
+ ## @todo Add doc
24
+ def call(attributes)
25
+ auction, winner = yield validate_contract(attributes)
26
+
27
+ user_repository.transaction do |_t|
28
+ send_winner_email_with_statistics_and_payment_instructions(auction.id, winner.id)
29
+ end
30
+
31
+ Success([auction, winner])
32
+ end
33
+
34
+ private
35
+
36
+ def validate_contract(attributes)
37
+ contract = winner_contract.call(attributes)
38
+
39
+ return Failure(contract.errors.to_h) if contract.failure?
40
+
41
+ Success([contract.context[:auction], contract.context[:winner]])
42
+ end
43
+
44
+ def send_winner_email_with_statistics_and_payment_instructions(auction_id, winner_id)
45
+ Success(winner_mailer_job.class.perform_async(auction_id, winner_id))
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Operations
5
+ module AuctionContext
6
+ module Processor
7
+ module Finish
8
+ ##
9
+ # Operation class for finalizing a closed auction.
10
+ # By default, this change auction status from 'running' to 'finished'.
11
+ #
12
+ class ClosedOperation < AuctionFunCore::Operations::Base
13
+ include Import["repos.auction_context.auction_repository"]
14
+ include Import["contracts.auction_context.processor.finish.closed_contract"]
15
+ include Import["workers.operations.auction_context.post_auction.winner_operation_job"]
16
+ include Import["workers.operations.auction_context.post_auction.participant_operation_job"]
17
+
18
+ # @todo Add custom doc
19
+ def self.call(attributes, &block)
20
+ operation = new.call(attributes)
21
+
22
+ return operation unless block
23
+
24
+ Dry::Matcher::ResultMatcher.call(operation, &block)
25
+ end
26
+
27
+ # It only performs the basic processing of completing an auction.
28
+ # It just changes the status at the database level and triggers the finished event.
29
+ # @param auction_id [Integer] Auction ID
30
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
31
+ def call(attributes)
32
+ auction = yield validate_contract(attributes)
33
+ summary = yield load_closed_auction_winners_and_participants(auction.id)
34
+ update_auction_attributes = yield update_finished_auction(auction, summary)
35
+
36
+ auction_repository.transaction do |_t|
37
+ auction, _ = auction_repository.update(auction.id, update_auction_attributes)
38
+
39
+ yield winner_operation(auction.id, summary.winner_id)
40
+
41
+ summary.participant_ids.each do |participant_id|
42
+ yield participant_operation(auction.id, participant_id)
43
+ end
44
+
45
+ publish_auction_finish_event(auction)
46
+ end
47
+
48
+ Success(auction)
49
+ end
50
+
51
+ private
52
+
53
+ # Calls the finish contract class to perform the validation
54
+ # of the informed attributes.
55
+ # @param attributes [Hash] auction attributes
56
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
57
+ def validate_contract(attributes)
58
+ contract = closed_contract.call(attributes)
59
+
60
+ return Failure(contract.errors.to_h) if contract.failure?
61
+
62
+ Success(contract.context[:auction])
63
+ end
64
+
65
+ def load_closed_auction_winners_and_participants(auction_id)
66
+ summary = relation.load_closed_auction_winners_and_participants(auction_id).first
67
+
68
+ Success(summary)
69
+ end
70
+
71
+ def update_finished_auction(auction, summary)
72
+ attrs = {status: "finished"}
73
+ attrs[:winner_id] = summary.winner_id if summary.winner_id.present?
74
+
75
+ Success(attrs)
76
+ end
77
+
78
+ def relation
79
+ AuctionFunCore::Application[:container].relations[:auctions]
80
+ end
81
+
82
+ def winner_operation(auction_id, winner_id)
83
+ return Success() if winner_id.blank?
84
+
85
+ Success(winner_operation_job.class.perform_async(auction_id, winner_id))
86
+ end
87
+
88
+ def participant_operation(auction_id, participant_id)
89
+ Success(participant_operation_job.class.perform_async(auction_id, participant_id))
90
+ end
91
+
92
+ def publish_auction_finish_event(auction)
93
+ Application[:event].publish("auctions.finished", auction.to_h)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Operations
5
+ module AuctionContext
6
+ module Processor
7
+ module Finish
8
+ ##
9
+ # Operation class for finalizing a penny auction.
10
+ # By default, this change auction status from 'running' to 'finished'.
11
+ #
12
+ class PennyOperation < AuctionFunCore::Operations::Base
13
+ include Import["repos.auction_context.auction_repository"]
14
+ include Import["contracts.auction_context.processor.finish.penny_contract"]
15
+ include Import["workers.operations.auction_context.post_auction.winner_operation_job"]
16
+ include Import["workers.operations.auction_context.post_auction.participant_operation_job"]
17
+
18
+ # @todo Add custom doc
19
+ def self.call(attributes, &block)
20
+ operation = new.call(attributes)
21
+
22
+ return operation unless block
23
+
24
+ Dry::Matcher::ResultMatcher.call(operation, &block)
25
+ end
26
+
27
+ # It only performs the basic processing of completing an auction.
28
+ # It just changes the status at the database level and triggers the finished event.
29
+ # @param auction_id [Integer] Auction ID
30
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
31
+ def call(attributes)
32
+ auction = yield validate_contract(attributes)
33
+ summary = yield load_penny_auction_winners_and_participants(auction.id)
34
+ update_auction_attributes = yield update_finished_auction(auction, summary)
35
+
36
+ auction_repository.transaction do |_t|
37
+ auction, _ = auction_repository.update(auction.id, update_auction_attributes)
38
+
39
+ yield winner_operation(auction.id, summary.winner_id)
40
+
41
+ summary.participant_ids.each do |participant_id|
42
+ yield participant_operation(auction.id, participant_id)
43
+ end
44
+
45
+ publish_auction_finish_event(auction)
46
+ end
47
+
48
+ Success(auction)
49
+ end
50
+
51
+ private
52
+
53
+ # Calls the finish contract class to perform the validation
54
+ # of the informed attributes.
55
+ # @param attributes [Hash] auction attributes
56
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
57
+ def validate_contract(attributes)
58
+ contract = penny_contract.call(attributes)
59
+
60
+ return Failure(contract.errors.to_h) if contract.failure?
61
+
62
+ Success(contract.context[:auction])
63
+ end
64
+
65
+ def load_penny_auction_winners_and_participants(auction_id)
66
+ summary = relation.load_penny_auction_winners_and_participants(auction_id).first
67
+
68
+ Success(summary)
69
+ end
70
+
71
+ def update_finished_auction(auction, summary)
72
+ attrs = {status: "finished"}
73
+ attrs[:winner_id] = summary.winner_id if summary.winner_id.present?
74
+
75
+ Success(attrs)
76
+ end
77
+
78
+ def relation
79
+ AuctionFunCore::Application[:container].relations[:auctions]
80
+ end
81
+
82
+ def winner_operation(auction_id, winner_id)
83
+ return Success() if winner_id.blank?
84
+
85
+ Success(winner_operation_job.class.perform_async(auction_id, winner_id))
86
+ end
87
+
88
+ def participant_operation(auction_id, participant_id)
89
+ Success(participant_operation_job.class.perform_async(auction_id, participant_id))
90
+ end
91
+
92
+ def publish_auction_finish_event(auction)
93
+ Application[:event].publish("auctions.finished", auction.to_h)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Operations
5
+ module AuctionContext
6
+ module Processor
7
+ module Finish
8
+ ##
9
+ # Operation class for finalizing a standard auction.
10
+ # By default, this change auction status from 'running' to 'finished'.
11
+ #
12
+ class StandardOperation < AuctionFunCore::Operations::Base
13
+ include Import["repos.auction_context.auction_repository"]
14
+ include Import["contracts.auction_context.processor.finish.standard_contract"]
15
+ include Import["workers.operations.auction_context.post_auction.winner_operation_job"]
16
+ include Import["workers.operations.auction_context.post_auction.participant_operation_job"]
17
+
18
+ # @todo Add custom doc
19
+ def self.call(attributes, &block)
20
+ operation = new.call(attributes)
21
+
22
+ return operation unless block
23
+
24
+ Dry::Matcher::ResultMatcher.call(operation, &block)
25
+ end
26
+
27
+ # TODO: update doc
28
+ # It only performs the basic processing of completing an auction.
29
+ # It just changes the status at the database level and triggers the finished event.
30
+ # @param attrs [Hash] auction attributes
31
+ # @option auction_id [Integer] Auction ID
32
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
33
+ def call(attributes)
34
+ auction = yield validate_contract(attributes)
35
+ summary = yield load_standard_auction_winners_and_participants(auction.id)
36
+ update_auction_attributes = yield update_finished_auction(auction, summary)
37
+
38
+ auction_repository.transaction do |_t|
39
+ auction, _ = auction_repository.update(auction.id, update_auction_attributes)
40
+
41
+ yield winner_operation(auction.id, summary.winner_id)
42
+
43
+ summary.participant_ids.each do |participant_id|
44
+ yield participant_operation(auction.id, participant_id)
45
+ end
46
+
47
+ publish_auction_finish_event(auction)
48
+ end
49
+
50
+ Success(auction)
51
+ end
52
+
53
+ private
54
+
55
+ # Calls the finish standard contract class to perform the validation
56
+ # of the informed attributes.
57
+ # @param attributes [Hash] auction attributes
58
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
59
+ def validate_contract(attributes)
60
+ contract = standard_contract.call(attributes)
61
+
62
+ return Failure(contract.errors.to_h) if contract.failure?
63
+
64
+ Success(contract.context[:auction])
65
+ end
66
+
67
+ def load_standard_auction_winners_and_participants(auction_id)
68
+ summary = relation.load_standard_auction_winners_and_participants(auction_id).first
69
+
70
+ Success(summary)
71
+ end
72
+
73
+ def update_finished_auction(auction, summary)
74
+ attrs = {status: "finished"}
75
+ attrs[:winner_id] = summary.winner_id if summary.winner_id.present?
76
+
77
+ Success(attrs)
78
+ end
79
+
80
+ def relation
81
+ AuctionFunCore::Application[:container].relations[:auctions]
82
+ end
83
+
84
+ def winner_operation(auction_id, winner_id)
85
+ return Success() if winner_id.blank?
86
+
87
+ Success(winner_operation_job.class.perform_async(auction_id, winner_id))
88
+ end
89
+
90
+ def participant_operation(auction_id, participant_id)
91
+ Success(participant_operation_job.class.perform_async(auction_id, participant_id))
92
+ end
93
+
94
+ def publish_auction_finish_event(auction)
95
+ Application[:event].publish("auctions.finished", auction.to_h)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -11,7 +11,9 @@ module AuctionFunCore
11
11
  class StartOperation < AuctionFunCore::Operations::Base
12
12
  include Import["repos.auction_context.auction_repository"]
13
13
  include Import["contracts.auction_context.processor.start_contract"]
14
- include Import["workers.operations.auction_context.processor.finish_operation_job"]
14
+ include Import["workers.operations.auction_context.processor.finish.closed_operation_job"]
15
+ include Import["workers.operations.auction_context.processor.finish.penny_operation_job"]
16
+ include Import["workers.operations.auction_context.processor.finish.standard_operation_job"]
15
17
 
16
18
  # @todo Add custom doc
17
19
  def self.call(attributes, &block)
@@ -28,10 +30,10 @@ module AuctionFunCore
28
30
  # @option opts [Integer] :stopwatch auction stopwatch
29
31
  # @return [ROM::Struct::Auction] auction object
30
32
  def call(attributes)
31
- attrs = yield validate(attributes)
33
+ auction, attrs = yield validate_contract(attributes)
32
34
 
33
35
  auction_repository.transaction do |_t|
34
- @auction, _ = auction_repository.update(attrs[:auction_id], update_params(attrs))
36
+ @auction, _ = auction_repository.update(auction.id, update_params(auction, attrs))
35
37
 
36
38
  yield publish_auction_start_event(@auction)
37
39
  yield scheduled_finished_auction(@auction)
@@ -46,36 +48,46 @@ module AuctionFunCore
46
48
  # of the informed attributes.
47
49
  # @param attributes [Hash] auction attributes
48
50
  # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
49
- def validate(attributes)
51
+ def validate_contract(attributes)
50
52
  contract = start_contract.call(attributes)
51
53
 
52
54
  return Failure(contract.errors.to_h) if contract.failure?
53
55
 
54
- Success(contract.to_h)
56
+ Success([contract.context[:auction], contract.to_h])
55
57
  end
56
58
 
57
59
  # Updates the status of the auction and depending on the type of auction,
58
60
  # it already sets the final date.
59
61
  # @param attrs [Hash] auction attributes
60
62
  # @return [Hash]
61
- def update_params(attrs)
62
- return {status: "running"} unless attrs[:kind] == "penny"
63
+ def update_params(auction, attrs)
64
+ return {kind: auction.kind, status: "running"} unless attrs[:kind] == "penny"
63
65
 
64
- {status: "running", finished_at: attrs[:stopwatch].seconds.from_now}
66
+ {kind: auction.kind, status: "running", finished_at: attrs[:stopwatch].seconds.from_now}
65
67
  end
66
68
 
67
69
  def publish_auction_start_event(auction)
68
70
  Success(Application[:event].publish("auctions.started", auction.to_h))
69
71
  end
70
72
 
73
+ # TODO: Added a small delay to perform operations (such as sending broadcasts and/or other operations).
71
74
  # Calls the background job class that will schedule the finish of the auction.
72
- # Added a small delay to perform operations (such as sending broadcasts and/or other operations).
75
+ # In the case of the penny auction, the end of the auction occurs after the first timer resets.
73
76
  # @param auction [ROM::Struct::Auction]
74
77
  # @return [String] sidekiq jid
75
78
  def scheduled_finished_auction(auction)
76
- return Success() if auction.kind == "penny"
79
+ perform_at = auction.finished_at
77
80
 
78
- Success(finish_operation_job.class.perform_at(auction.finished_at, auction.id))
81
+ case auction.kind
82
+ in "penny"
83
+ perform_at = auction.started_at + auction.stopwatch.seconds
84
+
85
+ Success(penny_operation_job.class.perform_at(perform_at, auction.id))
86
+ in "standard"
87
+ Success(standard_operation_job.class.perform_at(perform_at, auction.id))
88
+ in "closed"
89
+ Success(closed_operation_job.class.perform_at(perform_at, auction.id))
90
+ end
79
91
  end
80
92
  end
81
93
  end
@@ -7,8 +7,10 @@ module AuctionFunCore
7
7
  # Operation class for create new bids for penny auctions.
8
8
  #
9
9
  class CreateBidPennyOperation < AuctionFunCore::Operations::Base
10
- include Import["contracts.bid_context.create_bid_penny_contract"]
11
10
  include Import["repos.bid_context.bid_repository"]
11
+ include Import["repos.auction_context.auction_repository"]
12
+ include Import["contracts.bid_context.create_bid_penny_contract"]
13
+ include Import["workers.operations.auction_context.processor.finish.penny_operation_job"]
12
14
 
13
15
  # @todo Add custom doc
14
16
  def self.call(attributes, &block)
@@ -21,10 +23,13 @@ module AuctionFunCore
21
23
 
22
24
  # @todo Add custom doc
23
25
  def call(attributes)
24
- values = yield validate(attributes)
26
+ auction, values = yield validate_contract(attributes)
25
27
 
26
28
  bid_repository.transaction do |_t|
27
29
  @bid = yield persist(values)
30
+ updated_auction = yield update_end_auction(auction)
31
+
32
+ yield reschedule_end_auction(updated_auction)
28
33
  yield publish_bid_created(@bid)
29
34
  end
30
35
 
@@ -35,19 +40,42 @@ module AuctionFunCore
35
40
  # of the informed attributes.
36
41
  # @param attrs [Hash] bid attributes
37
42
  # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
38
- def validate(attrs)
43
+ def validate_contract(attrs)
39
44
  contract = create_bid_penny_contract.call(attrs)
40
45
 
41
46
  return Failure(contract.errors.to_h) if contract.failure?
42
47
 
43
- Success(contract.to_h)
48
+ Success([contract.context[:auction], contract.to_h])
49
+ end
50
+
51
+ # Updates the end time of an auction if it has already started.
52
+ #
53
+ # This method checks whether an auction is currently running. If the auction is running,
54
+ # it calculates a new end time based on the current time and the duration specified
55
+ # by the auction's stopwatch. The auction's finish time is then updated in the repository.
56
+ # If the auction has not started, it returns the auction as is without any modifications.
57
+ #
58
+ # @param auction [ROM::Struct::Auction] An instance of Auction to be checked and potentially updated.
59
+ # @return [Dry::Monads::Result::Success<ROM::Struct::Auction>, Dry::Monads::Result::Failure]
60
+ def update_end_auction(auction)
61
+ return Success(auction) unless started_auction?(auction)
62
+
63
+ updated_attributes = {
64
+ finished_at: Time.current + auction.stopwatch.seconds,
65
+ kind: auction.kind,
66
+ status: auction.status
67
+ }
68
+
69
+ updated_auction, _ = auction_repository.update(auction.id, updated_attributes)
70
+
71
+ Success(updated_auction)
44
72
  end
45
73
 
46
74
  # Calls the bid repository class to persist the attributes in the database.
47
75
  # @param result [Hash] Bid validated attributes
48
- # @return [ROM::Struct::Bid]
49
- def persist(result)
50
- Success(bid_repository.create(result))
76
+ # @return [Dry::Monads::Result::Success<ROM::Struct::Bid>, Dry::Monads::Result::Failure]
77
+ def persist(values)
78
+ Success(bid_repository.create(values))
51
79
  end
52
80
 
53
81
  # Triggers the publication of event *bids.created*.
@@ -58,6 +86,28 @@ module AuctionFunCore
58
86
 
59
87
  Success()
60
88
  end
89
+
90
+ # TODO: Added a small delay to perform operations (such as sending broadcasts and/or other operations).
91
+ # Reschedules the end time of an auction's background job if the auction has already started.
92
+ #
93
+ # This method checks if the auction is running. If so, it schedules a background job to
94
+ # execute at the auction's current finish time using the job class defined by the
95
+ # penny_operation_job attribute of the auction. If the auction has not started, it
96
+ # simply returns a Success object with no parameters.
97
+ #
98
+ # @return [Dry::Monads::Result::Success<ROM::Struct::Auction>, Dry::Monads::Result::Success<String>]
99
+ def reschedule_end_auction(auction)
100
+ # binding.pry
101
+ return Success(auction) unless started_auction?(auction)
102
+
103
+ perform_at = auction.finished_at
104
+
105
+ Success(penny_operation_job.class.perform_at(perform_at, auction.id))
106
+ end
107
+
108
+ def started_auction?(auction)
109
+ auction.status == "running"
110
+ end
61
111
  end
62
112
  end
63
113
  end
@@ -21,6 +21,7 @@ module AuctionFunCore
21
21
  # @todo Add custom doc
22
22
  def call(attributes)
23
23
  values = yield validate_contract(attributes)
24
+ values = yield assign_default_values(values)
24
25
  values_with_encrypt_password = yield encrypt_password(values)
25
26
 
26
27
  staff_repository.transaction do |_t|
@@ -44,6 +45,15 @@ module AuctionFunCore
44
45
  Success(contract.to_h)
45
46
  end
46
47
 
48
+ # By default, there can only be a single root staff. All other members have their type set to 'common'.
49
+ # @param attrs [Hash] user attributes
50
+ # @return [Dry::Monads::Result::Success]
51
+ def assign_default_values(attrs)
52
+ attrs[:kind] = "common"
53
+
54
+ Success(attrs)
55
+ end
56
+
47
57
  # Transforms the password attribute, encrypting it to be saved in the database.
48
58
  # @param result [Hash] Staff valid contract attributes
49
59
  # @return [Hash] Valid staff database