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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/auction_fun_core.gemspec +1 -0
- data/db/migrate/20240229143000_create_auctions.rb +1 -0
- data/db/seeds.rb +87 -36
- data/i18n/en-US/contracts/contracts.en-US.yml +9 -0
- data/i18n/en-US/mail/application.en-US.yml +59 -0
- data/i18n/en-US/mail/auction_context/post_auction/participant.en-US.yml +13 -0
- data/i18n/en-US/mail/auction_context/post_auction/winner.en-US.yml +13 -0
- data/i18n/pt-BR/contracts/contracts.pt-BR.yml +9 -0
- data/i18n/pt-BR/mail/application.pt-BR.yml +59 -0
- data/i18n/pt-BR/mail/auction_context/post_auction/participant.pt-BR.yml +13 -0
- data/i18n/pt-BR/mail/auction_context/post_auction/winner.pt-BR.yml +13 -0
- data/i18n/pt-BR/mail/user_context/registration.pt-BR.yml +0 -4
- data/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb +42 -0
- data/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb +41 -0
- data/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb +47 -0
- data/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb +48 -0
- data/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb +48 -0
- data/lib/auction_fun_core/entities/auction.rb +6 -0
- data/lib/auction_fun_core/operations/auction_context/create_operation.rb +12 -2
- data/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb +52 -0
- data/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb +51 -0
- data/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb +100 -0
- data/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb +100 -0
- data/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb +102 -0
- data/lib/auction_fun_core/operations/auction_context/processor/start_operation.rb +23 -11
- data/lib/auction_fun_core/operations/bid_context/create_bid_penny_operation.rb +57 -7
- data/lib/auction_fun_core/operations/staff_context/registration_operation.rb +10 -0
- data/lib/auction_fun_core/relations/auctions.rb +167 -26
- data/lib/auction_fun_core/relations/staffs.rb +1 -1
- data/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb +31 -0
- data/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb +31 -0
- data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/participant.html.erb +173 -0
- data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/winner.html.erb +174 -0
- data/lib/auction_fun_core/services/mail/templates/user_context/registration.html.erb +2 -2
- data/lib/auction_fun_core/version.rb +1 -1
- data/lib/auction_fun_core/workers/application_job.rb +2 -0
- data/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb +33 -0
- data/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb +33 -0
- data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb +34 -0
- data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb +37 -0
- data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb +34 -0
- data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb +51 -0
- data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb +51 -0
- data/system/providers/background_job.rb +19 -0
- metadata +43 -5
- data/lib/auction_fun_core/contracts/auction_context/processor/finish_contract.rb +0 -27
- data/lib/auction_fun_core/operations/auction_context/processor/finish_operation.rb +0 -61
- 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
|
|
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
|
|
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.
|
|
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
|
|
33
|
+
auction, attrs = yield validate_contract(attributes)
|
|
32
34
|
|
|
33
35
|
auction_repository.transaction do |_t|
|
|
34
|
-
@auction, _ = auction_repository.update(
|
|
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
|
|
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
|
-
#
|
|
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
|
-
|
|
79
|
+
perform_at = auction.finished_at
|
|
77
80
|
|
|
78
|
-
|
|
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
|
|
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
|
|
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(
|
|
50
|
-
Success(bid_repository.create(
|
|
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
|