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,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ module Sale
5
+ class Base < ApplicationRecord
6
+ include Folio::FriendlyId
7
+ include Folio::Positionable
8
+ include Folio::Featurable::Basic
9
+ include Folio::Publishable::Basic
10
+
11
+ self.table_name = "auctify_sales"
12
+
13
+ attribute :bid_steps_ladder, MinimalBidsLadderType.new
14
+
15
+ include Auctify::Behavior::Base
16
+
17
+ belongs_to :seller, polymorphic: true, optional: true
18
+ belongs_to :buyer, polymorphic: true, optional: true
19
+ # added on usage of `auctify_as :item` => belongs_to :item, class_name: ???
20
+ belongs_to :pack, class_name: "Auctify::SalesPack", inverse_of: :sales, optional: true, counter_cache: :sales_count
21
+
22
+ validate :valid_seller
23
+ validate :valid_item
24
+ validate :valid_buyer
25
+
26
+ validates :offered_price,
27
+ :current_price,
28
+ :sold_price,
29
+ :reserve_price,
30
+ numericality: { greater_than_or_equal_to: 0 },
31
+ allow_nil: true
32
+
33
+ validate :validate_offered_price_when_published
34
+
35
+ scope :not_sold, -> { where(sold_price: nil) }
36
+
37
+ # need auction scopes here because of has_many :sales, class_name: "Auctify::Sale::Base"
38
+ scope :auctions_open_for_bids, -> do
39
+ where(aasm_state: "in_sale").where("currently_ends_at > ?", Time.current)
40
+ end
41
+
42
+ scope :auctions_finished, -> do
43
+ where.not(aasm_state: %w[offered accepted refused]).where("currently_ends_at < ?", Time.current)
44
+ end
45
+
46
+ scope :latest_published_by_item, -> { joins(latest_published_sales_by_item_subtable.join_sources) }
47
+
48
+ delegate :to_label,
49
+ to: :item
50
+
51
+ def self.latest_published_sales_by_item_subtable
52
+ # see https://www.salsify.com/blog/engineering/most-recent-by-group-in-rails
53
+ sales_table = self.arel_table
54
+
55
+ latest_sales_query = sales_table.project(sales_table[:item_id],
56
+ sales_table[:id].maximum.as("latest_sale_id"))
57
+ .where(sales_table[:published].eq(true))
58
+ .group(sales_table[:item_id])
59
+
60
+ latest_sales_table = Arel::Table.new(latest_sales_query).alias(:latest_sales) # need to perform join
61
+
62
+ sales_table.join(latest_sales_query.as(latest_sales_table.name.to_s), Arel::Nodes::InnerJoin)
63
+ .on(sales_table[:id].eq(latest_sales_table[:latest_sale_id]))
64
+ end
65
+
66
+ def initialize(*args)
67
+ super
68
+
69
+ self.bid_steps_ladder = configuration.default_bid_steps_ladder if bid_steps_ladder.blank?
70
+ end
71
+
72
+ # need to cover wrong class of item before assigning
73
+ def item=(item)
74
+ @item = item
75
+ valid_item
76
+
77
+ super if errors.blank?
78
+ end
79
+
80
+ [:seller, :buyer, :item].each do |behavior|
81
+ define_method("#{behavior}_auctify_id=") do |auctify_id|
82
+ self.send("#{behavior}=", object_from_auctify_id(auctify_id))
83
+ end
84
+
85
+ define_method("#{behavior}_auctify_id") do
86
+ self.send("#{behavior}")&.auctify_id
87
+ end
88
+ end
89
+
90
+ def publish!
91
+ self.published = true
92
+ save
93
+ end
94
+
95
+ def auctioneer_commission
96
+ return nil if sold_price.nil?
97
+
98
+ percent = commission_in_percent \
99
+ || (pack&.commission_in_percent) \
100
+ || Auctify.configuration.auctioneer_commission_in_percent
101
+
102
+ sold_price * percent * 0.01
103
+ end
104
+
105
+ private
106
+ def valid_seller
107
+ return true if seller_id.blank?
108
+
109
+ db_seller = db_presence_of(seller)
110
+
111
+ errors.add(:seller, :required) unless db_seller.present?
112
+ end
113
+
114
+ def valid_item
115
+ item = @item || self.item
116
+ errors.delete(:item)
117
+
118
+ db_item = db_presence_of(item)
119
+ if db_item.present?
120
+ errors.add(:item, :already_on_sale_in_sales_pack, sale_pack_title: pack.title) if pack && pack.sales
121
+ .where(item: db_item)
122
+ .where.not(id: self.id)
123
+ .exists?
124
+ else
125
+ # Rails will add "required" on item.nil? automagically (and after this validation) but not for non-persisted item
126
+ # we do not allow creating sale along with item, so this trying to cover that
127
+ errors.add(:item, :required) unless item.blank? || errors.details[:item].include?({ error: :blank })
128
+ end
129
+ end
130
+
131
+ def valid_buyer
132
+ db_buyer = db_presence_of(buyer)
133
+ errors.add(:buyer, :required) if buyer.present? && db_buyer.blank?
134
+ end
135
+
136
+ def db_presence_of(record)
137
+ return nil if record.blank?
138
+
139
+ record.reload
140
+ rescue ActiveRecord::RecordNotFound
141
+ nil
142
+ end
143
+
144
+ def configuration
145
+ Auctify.configuration
146
+ end
147
+
148
+ def validate_offered_price_when_published
149
+ if published? && offered_price.blank?
150
+ errors.add(:offered_price, :required_for_published)
151
+ end
152
+ end
153
+
154
+ def slug_candidates
155
+ base = try(:item).try(:title).presence || self.class.model_name.human
156
+ year = Time.zone.now.year
157
+ [base, "#{base}-#{year}"] + 9.times.map { |i| "#{base}-#{year}-#{i + 2}" }
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ # == Schema Information
164
+ #
165
+ # Table name: auctify_sales
166
+ #
167
+ # id :bigint(8) not null, primary key
168
+ # seller_type :string
169
+ # seller_id :integer
170
+ # buyer_type :string
171
+ # buyer_id :integer
172
+ # item_id :integer not null
173
+ # created_at :datetime not null
174
+ # updated_at :datetime not null
175
+ # type :string default("Auctify::Sale::Base")
176
+ # aasm_state :string default("offered"), not null
177
+ # offered_price :decimal(, )
178
+ # current_price :decimal(, )
179
+ # sold_price :decimal(, )
180
+ # bid_steps_ladder :json
181
+ # reserve_price :decimal(, )
182
+ # pack_id :bigint(8)
183
+ # ends_at :datetime
184
+ # position :integer
185
+ # number :string
186
+ # currently_ends_at :datetime
187
+ # published :boolean default(FALSE)
188
+ # featured :boolean default(FALSE)
189
+ # slug :string
190
+ # contract_number :string
191
+ # commission_in_percent :integer
192
+ # winner_type :string
193
+ # winner_id :bigint(8)
194
+ # applied_bids_count :integer default(0)
195
+ # sold_at :datetime
196
+ # current_winner_type :string
197
+ # current_winner_id :bigint(8)
198
+ #
199
+ # Indexes
200
+ #
201
+ # index_auctify_sales_on_buyer_type_and_buyer_id (buyer_type,buyer_id)
202
+ # index_auctify_sales_on_currently_ends_at (currently_ends_at)
203
+ # index_auctify_sales_on_featured (featured)
204
+ # index_auctify_sales_on_pack_id (pack_id)
205
+ # index_auctify_sales_on_position (position)
206
+ # index_auctify_sales_on_published (published)
207
+ # index_auctify_sales_on_seller_type_and_seller_id (seller_type,seller_id)
208
+ # index_auctify_sales_on_slug (slug) UNIQUE
209
+ # index_auctify_sales_on_winner_type_and_winner_id (winner_type,winner_id)
210
+ #
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ module Sale
5
+ class Retail < Auctify::Sale::Base
6
+ include AASM
7
+
8
+ aasm do
9
+ state :offered, initial: true, color: "red"
10
+ state :accepted, color: "red"
11
+ state :refused, color: "dark"
12
+ state :in_sale, color: "yellow"
13
+ state :sold, color: "green"
14
+ state :not_sold, color: "dark"
15
+ state :cancelled, color: "red"
16
+
17
+ event :accept_offer do
18
+ transitions from: :offered, to: :accepted
19
+ end
20
+
21
+ event :refuse_offer do
22
+ transitions from: :offered, to: :refused
23
+ end
24
+
25
+ event :start_sale do
26
+ transitions from: :accepted, to: :in_sale
27
+ end
28
+
29
+ event :sell do
30
+ transitions from: :in_sale, to: :sold
31
+ after do |*args| # TODO: sold_at
32
+ params = args.first # expecting keys :buyer, :price
33
+ self.buyer = params[:buyer]
34
+ self.sold_price = params[:price]
35
+ end
36
+ end
37
+
38
+ event :end_sale do
39
+ transitions from: :in_sale, to: :not_sold
40
+ end
41
+
42
+ event :cancel do
43
+ transitions from: [:offered, :accepted], to: :cancelled
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ # == Schema Information
51
+ #
52
+ # Table name: auctify_sales
53
+ #
54
+ # id :bigint(8) not null, primary key
55
+ # seller_type :string
56
+ # seller_id :integer
57
+ # buyer_type :string
58
+ # buyer_id :integer
59
+ # item_id :integer not null
60
+ # created_at :datetime not null
61
+ # updated_at :datetime not null
62
+ # type :string default("Auctify::Sale::Base")
63
+ # aasm_state :string default("offered"), not null
64
+ # offered_price :decimal(, )
65
+ # current_price :decimal(, )
66
+ # sold_price :decimal(, )
67
+ # bid_steps_ladder :json
68
+ # reserve_price :decimal(, )
69
+ # pack_id :bigint(8)
70
+ # ends_at :datetime
71
+ # position :integer
72
+ # number :string
73
+ # currently_ends_at :datetime
74
+ # published :boolean default(FALSE)
75
+ # featured :boolean default(FALSE)
76
+ # slug :string
77
+ # contract_number :string
78
+ # commission_in_percent :integer
79
+ # winner_type :string
80
+ # winner_id :bigint(8)
81
+ # applied_bids_count :integer default(0)
82
+ # sold_at :datetime
83
+ # current_winner_type :string
84
+ # current_winner_id :bigint(8)
85
+ #
86
+ # Indexes
87
+ #
88
+ # index_auctify_sales_on_buyer_type_and_buyer_id (buyer_type,buyer_id)
89
+ # index_auctify_sales_on_currently_ends_at (currently_ends_at)
90
+ # index_auctify_sales_on_featured (featured)
91
+ # index_auctify_sales_on_pack_id (pack_id)
92
+ # index_auctify_sales_on_position (position)
93
+ # index_auctify_sales_on_published (published)
94
+ # index_auctify_sales_on_seller_type_and_seller_id (seller_type,seller_id)
95
+ # index_auctify_sales_on_slug (slug) UNIQUE
96
+ # index_auctify_sales_on_winner_type_and_winner_id (winner_type,winner_id)
97
+ #
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Auctify
4
+ class SalesPack < ApplicationRecord
5
+ include Folio::FriendlyId
6
+ include Folio::HasAttachments
7
+ include Folio::Positionable
8
+ include Folio::Publishable::Basic
9
+ include Folio::Sitemap::Base
10
+
11
+ has_many :sales, class_name: "Auctify::Sale::Base", foreign_key: :pack_id, inverse_of: :pack, dependent: :restrict_with_error
12
+ has_many :items, through: :sales
13
+
14
+ validates :title,
15
+ presence: true,
16
+ uniqueness: true
17
+
18
+ validates :start_date,
19
+ :end_date,
20
+ presence: true
21
+
22
+ validates :sales_interval,
23
+ numericality: { greater_than: 0, less_than: 240 }
24
+
25
+ validates :sales_beginning_hour,
26
+ numericality: { greater_than_or_equal: 0, less_than: 24 }
27
+
28
+ validates :sales_beginning_minutes,
29
+ numericality: { greater_than_or_equal: 0, less_than: 60 }
30
+
31
+ validate :validate_start_and_end_dates
32
+
33
+ scope :ordered, -> { order(start_date: :desc, id: :desc) }
34
+
35
+ pg_search_scope :by_query,
36
+ against: %i[title],
37
+ ignoring: :accents,
38
+ using: { tsearch: { prefix: true } }
39
+
40
+ after_initialize :set_commission
41
+
42
+ def to_label
43
+ title
44
+ end
45
+
46
+ def dates_to_label
47
+ if start_date && end_date
48
+ if start_date.year == end_date.year
49
+ if start_date.month == end_date.month
50
+ "#{start_date.strftime('%-d.')}–#{end_date.strftime('%-d. %-m. %y')}"
51
+ else
52
+ "#{start_date.strftime('%-d. %-m.')} – #{end_date.strftime('%-d. %-m. %y')}"
53
+ end
54
+ else
55
+ "#{start_date.strftime('%-d. %-m. %y')} – #{end_date.strftime('%-d. %-m. %y')}"
56
+ end
57
+ end
58
+ end
59
+
60
+ private
61
+ def validate_start_and_end_dates
62
+ if start_date.present? && end_date.present? && start_date > end_date
63
+ errors.add(:end_date, :smaller_than_start_date)
64
+ end
65
+ end
66
+
67
+ def set_commission
68
+ return if self.commission_in_percent.present?
69
+
70
+ self.commission_in_percent = Auctify.configuration.auctioneer_commission_in_percent
71
+ end
72
+ end
73
+ end
74
+
75
+ # == Schema Information
76
+ #
77
+ # Table name: auctify_sales_packs
78
+ #
79
+ # id :bigint(8) not null, primary key
80
+ # title :string
81
+ # description :text
82
+ # position :integer default(0)
83
+ # slug :string
84
+ # place :string
85
+ # published :boolean default(FALSE)
86
+ # created_at :datetime not null
87
+ # updated_at :datetime not null
88
+ # sales_count :integer default(0)
89
+ # start_date :date
90
+ # end_date :date
91
+ # sales_interval :integer default(3)
92
+ # sales_beginning_hour :integer default(20)
93
+ # sales_beginning_minutes :integer default(0)
94
+ # commission_in_percent :integer
95
+ #
96
+ # Indexes
97
+ #
98
+ # index_auctify_sales_packs_on_position (position)
99
+ # index_auctify_sales_packs_on_published (published)
100
+ # index_auctify_sales_packs_on_slug (slug) UNIQUE
101
+ #
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Auctify::Sale::AuctionSerializer
4
+ include FastJsonapi::ObjectSerializer
5
+
6
+ attributes :id,
7
+ :current_price,
8
+ :current_minimal_bid,
9
+ :currently_ends_at,
10
+ :ends_at,
11
+ :open_for_bids?
12
+
13
+ attribute :current_winner do |auction|
14
+ winner = auction.current_winner
15
+ {
16
+ id: winner.id,
17
+ auctify_id: winner.auctify_id,
18
+ to_label: winner.to_label
19
+ }
20
+ end
21
+
22
+
23
+
24
+
25
+
26
+ # assert_equal auction.current_winner.id, json_attributes["current_winner"]["id"]
27
+ # assert_equal auction.current_winner.auctify_id, json_attributes["current_winner"]["auctify_id"]
28
+ # assert_equal auction.current_winner.to_label, json_attributes["current_winner"]["to_label"]
29
+ # assert_equal auction.current_price, json_attributes["current_price"]
30
+ # assert_equal auction.current_minimal_bid, json_attributes["current_minimal_bid"]
31
+ # assert_equal auction.ends_at, json_attributes["ends_at"]
32
+ # assert_equal auction.currently_ends_at, json_attributes["currently_ends_at"]
33
+ # assert_equal auction.open_for_bids?, json_attributes["open_for_bids?"]
34
+
35
+
36
+ # attributes :name, :year
37
+ # has_many :actors
38
+ # belongs_to :owner, record_type: :user
39
+ # belongs_to :movie_ty
40
+ # # link :url do |object|
41
+ # # Rails.application
42
+ # # .routes
43
+ # # .url_helpers
44
+ # # .url_for([object, only_path: true])
45
+ # # end
46
+ end