auctify 1.0.0

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 (115) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +229 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/config/auctify_manifest.js +1 -0
  6. data/app/assets/javascripts/folio/console/main_app.coffee +1 -0
  7. data/app/assets/stylesheets/auctify/application.css +15 -0
  8. data/app/assets/stylesheets/auctify/bidder_registrations.css +4 -0
  9. data/app/assets/stylesheets/auctify/bids.css +4 -0
  10. data/app/assets/stylesheets/auctify/sales.css +4 -0
  11. data/app/assets/stylesheets/auctify/sales_packs.css +4 -0
  12. data/app/assets/stylesheets/folio/console/_main_app.sass +1 -0
  13. data/app/assets/stylesheets/scaffold.css +80 -0
  14. data/app/cells/folio/console/atoms/previews/main_app.coffee +1 -0
  15. data/app/concerns/auctify/behavior/base.rb +20 -0
  16. data/app/concerns/auctify/behavior/buyer.rb +16 -0
  17. data/app/concerns/auctify/behavior/item.rb +27 -0
  18. data/app/concerns/auctify/behavior/seller.rb +36 -0
  19. data/app/concerns/auctify/sale/auction_callbacks.rb +44 -0
  20. data/app/controllers/auctify/api/v1/auctions_controller.rb +61 -0
  21. data/app/controllers/auctify/api/v1/base_controller.rb +22 -0
  22. data/app/controllers/auctify/api/v1/console/bids_controller.rb +37 -0
  23. data/app/controllers/auctify/application_controller.rb +8 -0
  24. data/app/controllers/auctify/bidder_registrations_controller.rb +65 -0
  25. data/app/controllers/auctify/bids_controller.rb +64 -0
  26. data/app/controllers/auctify/sales_controller.rb +75 -0
  27. data/app/controllers/auctify/sales_packs_controller.rb +75 -0
  28. data/app/helpers/auctify/application_helper.rb +10 -0
  29. data/app/helpers/auctify/bidder_registrations_helper.rb +6 -0
  30. data/app/helpers/auctify/bids_helper.rb +6 -0
  31. data/app/helpers/auctify/sales_helper.rb +15 -0
  32. data/app/helpers/auctify/sales_packs_helper.rb +6 -0
  33. data/app/jobs/auctify/application_job.rb +6 -0
  34. data/app/jobs/auctify/bidding_closer_job.rb +23 -0
  35. data/app/jobs/auctify/bidding_is_close_to_end_notifier_job.rb +29 -0
  36. data/app/mailers/auctify/application_mailer.rb +8 -0
  37. data/app/models/auctify/application_record.rb +14 -0
  38. data/app/models/auctify/behaviors.rb +27 -0
  39. data/app/models/auctify/bid.rb +72 -0
  40. data/app/models/auctify/bidder_registration.rb +84 -0
  41. data/app/models/auctify/sale/auction.rb +404 -0
  42. data/app/models/auctify/sale/base.rb +210 -0
  43. data/app/models/auctify/sale/retail.rb +97 -0
  44. data/app/models/auctify/sales_pack.rb +101 -0
  45. data/app/serializers/auctify/sale/auction_serializer.rb +46 -0
  46. data/app/services/auctify/bids_appender.rb +241 -0
  47. data/app/services/auctify/service_base.rb +78 -0
  48. data/app/types/auctify/minimal_bids_ladder_type.rb +77 -0
  49. data/app/views/auctify/api/v1/console/bids/index.html.erb +1 -0
  50. data/app/views/auctify/api/v1/console/bids/show.html.erb +1 -0
  51. data/app/views/auctify/bidder_registrations/_form.html.erb +27 -0
  52. data/app/views/auctify/bidder_registrations/edit.html.erb +6 -0
  53. data/app/views/auctify/bidder_registrations/index.html.erb +33 -0
  54. data/app/views/auctify/bidder_registrations/new.html.erb +5 -0
  55. data/app/views/auctify/bidder_registrations/show.html.erb +24 -0
  56. data/app/views/auctify/bids/_form.html.erb +32 -0
  57. data/app/views/auctify/bids/edit.html.erb +6 -0
  58. data/app/views/auctify/bids/index.html.erb +31 -0
  59. data/app/views/auctify/bids/new.html.erb +5 -0
  60. data/app/views/auctify/bids/show.html.erb +19 -0
  61. data/app/views/auctify/sales/_form.html.erb +32 -0
  62. data/app/views/auctify/sales/edit.html.erb +6 -0
  63. data/app/views/auctify/sales/index.html.erb +36 -0
  64. data/app/views/auctify/sales/new.html.erb +5 -0
  65. data/app/views/auctify/sales/show.html.erb +19 -0
  66. data/app/views/auctify/sales_packs/_form.html.erb +57 -0
  67. data/app/views/auctify/sales_packs/edit.html.erb +6 -0
  68. data/app/views/auctify/sales_packs/index.html.erb +40 -0
  69. data/app/views/auctify/sales_packs/new.html.erb +5 -0
  70. data/app/views/auctify/sales_packs/show.html.erb +44 -0
  71. data/app/views/layouts/auctify/application.html.erb +15 -0
  72. data/config/locales/auctify.cs.yml +121 -0
  73. data/config/locales/default.cs.yml +220 -0
  74. data/config/locales/default.en.yml +215 -0
  75. data/config/routes.rb +23 -0
  76. data/db/migrate/20210212163000_create_auctify_sales.rb +16 -0
  77. data/db/migrate/20210216151350_add_type_to_auctify_sales.rb +7 -0
  78. data/db/migrate/20210217101246_add_state_to_auctify_sales.rb +7 -0
  79. data/db/migrate/20210217110819_add_prices_to_auctify_sales.rb +9 -0
  80. data/db/migrate/20210222103031_add_published_at_to_auctify_sale.rb +7 -0
  81. data/db/migrate/20210223090240_create_auctify_bidder_registrations.rb +15 -0
  82. data/db/migrate/20210223152139_create_auctify_bids.rb +13 -0
  83. data/db/migrate/20210225103227_add_bid_steps_ladder_to_auctify_sales.rb +7 -0
  84. data/db/migrate/20210412114319_add_reserve_price_to_auctify_sales.rb +7 -0
  85. data/db/migrate/20210416140603_create_auctify_sales_packs.rb +17 -0
  86. data/db/migrate/20210416141111_add_pack_reference_to_auctify_sales.rb +7 -0
  87. data/db/migrate/20210419075003_add_ends_at_to_auctify_sales.rb +7 -0
  88. data/db/migrate/20210419082800_add_position_to_auctify_sales.rb +8 -0
  89. data/db/migrate/20210419083321_add_indexes.rb +12 -0
  90. data/db/migrate/20210421093652_add_number_to_auctify_sales.rb +7 -0
  91. data/db/migrate/20210423071326_removing_polymorphic_assoc_sale_to_item.rb +7 -0
  92. data/db/migrate/20210423071534_add_currently_ends_at_to_auctify_sales.rb +7 -0
  93. data/db/migrate/20210427121353_change_column_published_on_auctify_sale.rb +15 -0
  94. data/db/migrate/20210427122315_add_featured_to_auctify_sales.rb +7 -0
  95. data/db/migrate/20210428045651_add_sales_bool_indices.rb +9 -0
  96. data/db/migrate/20210428064615_allow_seller_to_be_nil.rb +13 -0
  97. data/db/migrate/20210429051508_add_sales_pack_start_and_end.rb +15 -0
  98. data/db/migrate/20210430080419_add_sales_slug.rb +11 -0
  99. data/db/migrate/20210503095704_add_cancelled_to_auctify_bids.rb +7 -0
  100. data/db/migrate/20210504072041_add_commission_and_contract_to_auctify_sales.rb +8 -0
  101. data/db/migrate/20210506064100_add_winner_to_auctify_sales.rb +7 -0
  102. data/db/migrate/20210506072438_add_bids_count_to_auctify_sales.rb +7 -0
  103. data/db/migrate/20210507085845_rename_bids_count_to_applied_bids_count.rb +7 -0
  104. data/db/migrate/20210510063146_add_dont_confirm_bids_to_registrations.rb +7 -0
  105. data/db/migrate/20210511081556_add_index_on_cancelled_on.rb +7 -0
  106. data/db/migrate/20210512162942_add_sold_at_to_auctify_sales.rb +7 -0
  107. data/db/migrate/20210607113440_add_commission_in_percent_to_sales_packs.rb +7 -0
  108. data/db/migrate/20210617062509_add_index_to_auctify_sales_currently_ends_at.rb +7 -0
  109. data/db/migrate/20210625125732_add_current_winner_to_auctify_sales.rb +7 -0
  110. data/lib/auctify.rb +7 -0
  111. data/lib/auctify/configuration.rb +43 -0
  112. data/lib/auctify/engine.rb +25 -0
  113. data/lib/auctify/version.rb +5 -0
  114. data/lib/tasks/auctify_tasks.rake +23 -0
  115. metadata +442 -0
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ module Behavior
5
+ module Buyer
6
+ extend ActiveSupport::Concern
7
+
8
+ include Auctify::Behavior::Base
9
+
10
+ included do
11
+ has_many :purchases, as: :buyer, class_name: "Auctify::Sale::Base"
12
+ has_many :bidder_registrations, as: :bidder, class_name: "Auctify::BidderRegistration"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ module Behavior
5
+ module Item
6
+ extend ActiveSupport::Concern
7
+
8
+ include Auctify::Behavior::Base
9
+
10
+ included do
11
+ has_many :sales, class_name: "Auctify::Sale::Base", foreign_key: :item_id, inverse_of: :item
12
+ has_many :auction_sales, class_name: "Auctify::Sale::Auction", foreign_key: :item_id, inverse_of: :item
13
+ has_many :retail_sales, class_name: "Auctify::Sale::Retail", foreign_key: :item_id, inverse_of: :item
14
+
15
+ c_name = self.name
16
+ Auctify::Sale::Base.class_eval do
17
+ belongs_to :item, class_name: c_name, counter_cache: :sales_count
18
+ end
19
+
20
+ has_one :last_published_sale, -> { merge(Auctify::Sale::Base.latest_published_by_item) },
21
+ class_name: "Auctify::Sale::Base",
22
+ foreign_key: :item_id,
23
+ inverse_of: :item
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ module Behavior
5
+ module Seller
6
+ extend ActiveSupport::Concern
7
+
8
+ include Auctify::Behavior::Base
9
+
10
+ included do
11
+ has_many :sales, as: :seller, class_name: "Auctify::Sale::Base"
12
+ has_many :auction_sales, as: :seller, class_name: "Auctify::Sale::Auction"
13
+ has_many :retail_sales, as: :seller, class_name: "Auctify::Sale::Retail"
14
+
15
+ def offer_to_sale!(item, options = {})
16
+ assoc = options[:in] == :auction ? auction_sales : retail_sales
17
+
18
+ if item.class.included_modules.include?(Auctify::Behavior::Item)
19
+ assoc.create!(item: item,
20
+ seller: self,
21
+ buyer: nil,
22
+ offered_price: options[:price],
23
+ # FIXME @foton - this method will not be used in AA
24
+ ends_at: options[:in] == :auction ? 1.day.from_now : nil)
25
+ else
26
+ sale = assoc.build(seller: self,
27
+ buyer: nil,
28
+ offered_price: options[:price])
29
+ sale.errors.add(:item, :not_auctified)
30
+ raise ActiveRecord::RecordInvalid.new(sale)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ module Sale
5
+ module AuctionCallbacks
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ CALLBACKS_WITHOUT_ARGS = %i[after_start_sale
10
+ before_bidding_is_close_to_end
11
+ after_close_bidding
12
+ after_sold_in_auction
13
+ after_not_sold_in_auction]
14
+ CALLBACKS_WITH_ARGS = %i[after_bid_appended
15
+ after_bid_not_appended ]
16
+
17
+
18
+ CALLBACKS_WITHOUT_ARGS.each do |cb|
19
+ define_method cb do
20
+ # override me, if You want
21
+ callback_runs[cb] += 1
22
+ end
23
+ end
24
+
25
+ def after_bid_appended(bid_appender)
26
+ # override me, if You want
27
+ # see bid_appender.result
28
+ # to get previous_winning bid, call `previous_winning_bid(bid_appender.bid)`
29
+ callback_runs[:after_bid_appended] += 1
30
+ end
31
+
32
+ def after_bid_not_appended(bid_appender)
33
+ # override me, if You want
34
+ # see bid_appender.errors
35
+ callback_runs[:after_bid_not_appended] += 1
36
+ end
37
+
38
+ def callback_runs
39
+ @callback_runs ||= (CALLBACKS_WITH_ARGS + CALLBACKS_WITHOUT_ARGS).index_with { |cb| 0 }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ module Api
5
+ module V1
6
+ class AuctionsController < Auctify::Api::V1::BaseController
7
+ before_action :find_auction, except: [:index]
8
+
9
+ def show
10
+ render_record @auction
11
+ end
12
+
13
+ def bids
14
+ if params[:confirmation] == "1"
15
+ if @auction.bid!(new_bid)
16
+ if params[:dont_confirm_bids] == "1"
17
+ # use SQL update in case of some obscure invalid attributes
18
+ current_user.bidder_registrations
19
+ .where(auction: @auction)
20
+ .update_all(dont_confirm_bids: true)
21
+ end
22
+
23
+ render_record @auction.reload, success: true
24
+ else
25
+ render_record @auction, bid: new_bid, status: 400
26
+ end
27
+ else
28
+ new_bid.errors.add(:base, :not_confirmed)
29
+ render_record @auction, bid: new_bid, status: 400
30
+ end
31
+ end
32
+
33
+ private
34
+ def find_auction
35
+ @auction = Auctify::Sale::Auction.find(params[:id])
36
+ end
37
+
38
+ def bid_params
39
+ params.require(:bid).permit(:max_price, :price)
40
+ end
41
+
42
+ def new_bid
43
+ @new_bid ||= Auctify::Bid.new(bid_params.merge(registration_params))
44
+ end
45
+
46
+ def registration_params
47
+ bidder_registration = @auction.bidder_registrations.find_by(bidder: current_user)
48
+ return { registration: bidder_registration } if bidder_registration.present?
49
+
50
+ { bidder: current_user }
51
+ end
52
+
53
+ def render_record(auction, bid: nil, status: 200, success: nil)
54
+ render json: {
55
+ data: cell("#{global_namespace_path}/auctify/auctions/form", auction, bid: bid, success: success).show
56
+ }, status: status
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ module Api
5
+ module V1
6
+ class BaseController < ApplicationController
7
+ include Folio::ApiControllerBase
8
+
9
+ # TODO handle authorization here if needed
10
+
11
+ private
12
+ def global_namespace_path
13
+ @global_namespace_path ||= global_namespace.underscore
14
+ end
15
+
16
+ def global_namespace
17
+ @global_namespace ||= Rails.application.class.name.deconstantize
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ module Api
5
+ module V1
6
+ module Console
7
+ class BidsController < Auctify::Api::V1::BaseController # Folio::Console::Api::BaseController
8
+ before_action :api_authenticate_account!
9
+ before_action :find_bid, except: [:index]
10
+
11
+ def destroy
12
+ auction = @bid.auction
13
+
14
+ if @bid.cancel!
15
+ render_list(auction.reload)
16
+ else
17
+ render_invalid(@bid)
18
+ end
19
+ end
20
+
21
+ private
22
+ def find_bid
23
+ @bid = Auctify::Bid.find(params[:id])
24
+ end
25
+
26
+ def api_authenticate_account!
27
+ fail CanCan::AccessDenied if current_account.blank?
28
+ end
29
+
30
+ def render_list(auction)
31
+ render json: { data: cell("folio/console/auctify/auctions/bid_list", auction).show }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ class ApplicationController < ActionController::Base
5
+ protect_from_forgery with: :exception
6
+ include Auctify::ApplicationHelper
7
+ end
8
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "auctify/application_controller"
4
+
5
+ module Auctify
6
+ class BidderRegistrationsController < ApplicationController
7
+ before_action :set_bidder_registration, only: [:show, :edit, :update, :destroy]
8
+
9
+ # GET /bidder_registrations
10
+ def index
11
+ @bidder_registrations = BidderRegistration.all
12
+ end
13
+
14
+ # GET /bidder_registrations/1
15
+ def show
16
+ end
17
+
18
+ # GET /bidder_registrations/new
19
+ def new
20
+ @bidder_registration = BidderRegistration.new
21
+ end
22
+
23
+ # GET /bidder_registrations/1/edit
24
+ def edit
25
+ end
26
+
27
+ # POST /bidder_registrations
28
+ def create
29
+ @bidder_registration = BidderRegistration.new(bidder_registration_params)
30
+
31
+ if @bidder_registration.save
32
+ redirect_to @bidder_registration, notice: "Bidder registration was successfully created."
33
+ else
34
+ render :new
35
+ end
36
+ end
37
+
38
+ # PATCH/PUT /bidder_registrations/1
39
+ def update
40
+ if @bidder_registration.update(bidder_registration_params)
41
+ redirect_to @bidder_registration, notice: "Bidder registration was successfully updated."
42
+ else
43
+ render :edit
44
+ end
45
+ end
46
+
47
+ # DELETE /bidder_registrations/1
48
+ def destroy
49
+ @bidder_registration.destroy
50
+ redirect_to auctify_bidder_registrations_url, notice: "Bidder registration was successfully destroyed."
51
+ end
52
+
53
+ private
54
+ # Use callbacks to share common setup or constraints between actions.
55
+ def set_bidder_registration
56
+ @bidder_registration = BidderRegistration.find(params[:id])
57
+ end
58
+
59
+ # Only allow a trusted parameter "white list" through.
60
+ def bidder_registration_params
61
+ params.require(:bidder_registration).permit(:bidder_id, :bidder_type, :auction_id, :aasm_state, :submitted_at,
62
+ :handled_at)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "auctify/application_controller"
4
+
5
+ module Auctify
6
+ class BidsController < ApplicationController
7
+ before_action :set_bid, only: [:show, :edit, :update, :destroy]
8
+
9
+ # GET /bids
10
+ def index
11
+ @bids = Bid.all
12
+ end
13
+
14
+ # GET /bids/1
15
+ def show
16
+ end
17
+
18
+ # GET /bids/new
19
+ def new
20
+ @bid = Bid.new
21
+ end
22
+
23
+ # GET /bids/1/edit
24
+ def edit
25
+ end
26
+
27
+ # POST /bids
28
+ def create
29
+ @bid = Bid.new(bid_params)
30
+
31
+ if @bid.save
32
+ redirect_to @bid, notice: "Bid was successfully created."
33
+ else
34
+ render :new
35
+ end
36
+ end
37
+
38
+ # PATCH/PUT /bids/1
39
+ def update
40
+ if @bid.update(bid_params)
41
+ redirect_to @bid, notice: "Bid was successfully updated."
42
+ else
43
+ render :edit
44
+ end
45
+ end
46
+
47
+ # DELETE /bids/1
48
+ def destroy
49
+ @bid.destroy
50
+ redirect_to auctify_bids_url, notice: "Bid was successfully destroyed."
51
+ end
52
+
53
+ private
54
+ # Use callbacks to share common setup or constraints between actions.
55
+ def set_bid
56
+ @bid = Bid.find(params[:id])
57
+ end
58
+
59
+ # Only allow a trusted parameter "white list" through.
60
+ def bid_params
61
+ params.require(:bid).permit(:registration_id, :price, :max_price)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "auctify/application_controller"
4
+
5
+ module Auctify
6
+ class SalesController < ApplicationController
7
+ before_action :set_sale, only: [:show, :edit, :update, :destroy]
8
+
9
+ # GET /sales
10
+ def index
11
+ @sales = scoped_sales.all
12
+ end
13
+
14
+ # GET /sales/1
15
+ def show
16
+ end
17
+
18
+ # GET /sales/new
19
+ def new
20
+ @sale = sale_class.new
21
+ end
22
+
23
+ # GET /sales/1/edit
24
+ def edit
25
+ end
26
+
27
+ # POST /sales
28
+ def create
29
+ @sale = sale_class.new(sale_params)
30
+
31
+ if @sale.save
32
+ redirect_to auctify_sale_path(@sale), notice: "Sale was successfully created."
33
+ else
34
+ render :new
35
+ end
36
+ end
37
+
38
+ # PATCH/PUT /sales/1
39
+ def update
40
+ if @sale.update(sale_params)
41
+ redirect_to auctify_sale_path(@sale), notice: "Sale was successfully updated."
42
+ else
43
+ render :edit
44
+ end
45
+ end
46
+
47
+ # DELETE /sales/1
48
+ def destroy
49
+ @sale.destroy
50
+ redirect_to auctify_sales_url, notice: "Sale was successfully destroyed."
51
+ end
52
+
53
+ private
54
+ def sale_class
55
+ Sale::Base
56
+ end
57
+
58
+ # Use callbacks to share common setup or constraints between actions.
59
+ def set_sale
60
+ @sale = scoped_sales.find(params[:id])
61
+ end
62
+
63
+ # Only allow a trusted parameter "white list" through.
64
+ def sale_params
65
+ params.require(:sale).permit(:seller_auctify_id, :buyer_auctify_id, :item_auctify_id, :published)
66
+ end
67
+
68
+ def scoped_sales
69
+ scope = sale_class
70
+ return scope if params[:list_all].to_s == "1"
71
+
72
+ scope.published.not_sold
73
+ end
74
+ end
75
+ end