From f0e35d5f9bcabb3c78a3d20257917d254de54d0a Mon Sep 17 00:00:00 2001 From: "Jessie A. Young" Date: Wed, 3 Aug 2016 17:32:21 -0700 Subject: [PATCH] WIP --- Gemfile | 1 + Gemfile.lock | 8 + app/controllers/admin/proposals_controller.rb | 1 + app/models/auction.rb | 1 + app/models/bid_status_presenter_factory.rb | 94 +++++++++++ app/models/c2_status_presenter_factory.rb | 15 ++ app/models/status_presenter_factory.rb | 2 +- .../auction_status_presenter_factory.rb | 157 ------------------ app/presenters/bid_status_flash_factory.rb | 132 --------------- .../available_sealed_user_is_bidder.rb | 15 ++ .../available_user_is_admin.rb | 11 ++ .../available_user_is_guest.rb | 12 ++ .../available_user_is_winning_bidder.rb | 15 ++ app/presenters/bid_status_presenter/base.rb | 27 +++ .../future_user_is_admin.rb | 27 +++ .../future_user_is_guest.rb | 12 ++ .../future_user_is_vendor.rb | 11 ++ .../bid_status_presenter/over_no_bids.rb | 9 + .../over_user_is_bidder.rb | 9 + .../over_user_is_winner.rb | 9 + .../bid_status_presenter/over_with_bids.rb | 5 + .../c2_approval_not_requested.rb | 30 ++++ .../c2_status_presenter/c2_pending.rb | 9 + app/presenters/status_presenter/available.rb | 2 +- app/presenters/status_presenter/base.rb | 39 +++++ app/presenters/status_presenter/future.rb | 2 +- app/presenters/status_presenter/over.rb | 2 +- app/services/check_approval.rb | 2 +- .../admin/auction_show_view_model.rb | 13 +- .../admin/edit_auction_view_model.rb | 2 +- app/view_models/auction_show_view_model.rb | 25 +-- .../auctions/_create_c2_proposal.html.erb | 4 - app/views/admin/auctions/show.html.erb | 5 +- app/views/auctions/_bid_status.html.erb | 2 +- app/views/auctions/_status.html.erb | 9 - app/views/auctions/show.html.erb | 7 +- ...ge_c2_approved_at_to_c2_approval_status.rb | 38 +++++ db/schema.rb | 38 ++--- features/admin_requests_c2_approval.feature | 23 ++- .../step_definitions/auction_create_steps.rb | 4 +- spec/factories/auctions.rb | 2 +- spec/services/check_approval_spec.rb | 5 +- .../admin/auction_show_view_model_spec.rb | 2 +- .../admin/edit_auction_view_model_spec.rb | 8 +- 44 files changed, 475 insertions(+), 371 deletions(-) create mode 100644 app/models/bid_status_presenter_factory.rb create mode 100644 app/models/c2_status_presenter_factory.rb delete mode 100644 app/presenters/auction_status_presenter_factory.rb delete mode 100644 app/presenters/bid_status_flash_factory.rb create mode 100644 app/presenters/bid_status_presenter/available_sealed_user_is_bidder.rb create mode 100644 app/presenters/bid_status_presenter/available_user_is_admin.rb create mode 100644 app/presenters/bid_status_presenter/available_user_is_guest.rb create mode 100644 app/presenters/bid_status_presenter/available_user_is_winning_bidder.rb create mode 100644 app/presenters/bid_status_presenter/base.rb create mode 100644 app/presenters/bid_status_presenter/future_user_is_admin.rb create mode 100644 app/presenters/bid_status_presenter/future_user_is_guest.rb create mode 100644 app/presenters/bid_status_presenter/future_user_is_vendor.rb create mode 100644 app/presenters/bid_status_presenter/over_no_bids.rb create mode 100644 app/presenters/bid_status_presenter/over_user_is_bidder.rb create mode 100644 app/presenters/bid_status_presenter/over_user_is_winner.rb create mode 100644 app/presenters/bid_status_presenter/over_with_bids.rb create mode 100644 app/presenters/c2_status_presenter/c2_approval_not_requested.rb create mode 100644 app/presenters/c2_status_presenter/c2_pending.rb create mode 100644 app/presenters/status_presenter/base.rb delete mode 100644 app/views/admin/auctions/_create_c2_proposal.html.erb delete mode 100644 app/views/auctions/_status.html.erb create mode 100644 db/migrate/20160804230057_change_c2_approved_at_to_c2_approval_status.rb diff --git a/Gemfile b/Gemfile index 41632793..2f36aaba 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,7 @@ source 'https://rubygems.org' ruby '2.3.1' gem 'rails', '4.2.6' +gem 'uswds-rails', github: '18F/uswds-rails-gem', branch: 'jy-add-the-assets' gem 'pg' gem 'sass-rails', '~> 5.0' gem 'uglifier' diff --git a/Gemfile.lock b/Gemfile.lock index f1a3928c..3728c24e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,10 @@ +GIT + remote: git://github.com/18F/uswds-rails-gem.git + revision: 513f5efa242e80cd820250d116f975aa5be0c67a + branch: jy-add-the-assets + specs: + uswds-rails (1.0.0) + GIT remote: git://github.com/18f/c2-api-client-ruby.git revision: 1404abe563c1a1048c91a319a488be5d6a172936 @@ -463,6 +470,7 @@ DEPENDENCIES sinatra timecop uglifier + uswds-rails! validate_url web-console (~> 2.0) webmock diff --git a/app/controllers/admin/proposals_controller.rb b/app/controllers/admin/proposals_controller.rb index 21ffa6a2..41501dbb 100644 --- a/app/controllers/admin/proposals_controller.rb +++ b/app/controllers/admin/proposals_controller.rb @@ -1,6 +1,7 @@ class Admin::ProposalsController < Admin::BaseController def create if should_create_c2_proposal? + auction.update(c2_approval_status: :pending) CreateC2ProposalJob.perform_later(auction.id) flash[:success] = I18n.t('controllers.admin.proposals.create.success') else diff --git a/app/models/auction.rb b/app/models/auction.rb index 15866aa8..3f064aa1 100644 --- a/app/models/auction.rb +++ b/app/models/auction.rb @@ -14,6 +14,7 @@ class Auction < ActiveRecord::Base enum type: { sealed_bid: 0, reverse: 1 } enum published: { unpublished: 0, published: 1 } enum purchase_card: { default: 0, other: 1 } + enum c2_approval_status: { not_requested: 0, pending: 1, pending_approval: 2, approved: 3 } # Disable STI self.inheritance_column = :__disabled diff --git a/app/models/bid_status_presenter_factory.rb b/app/models/bid_status_presenter_factory.rb new file mode 100644 index 00000000..5f9b5282 --- /dev/null +++ b/app/models/bid_status_presenter_factory.rb @@ -0,0 +1,94 @@ +class BidStatusPresenterFactory + attr_reader :auction, :user + + def initialize(auction:, user:) + @auction = auction + @user = user + end + + def create + if future? + future_message + elsif over? + over_message + else + available_message + end + end + + private + + def available_message + if admin? + BidStatusPresenter::AvailableUserIsAdmin.new(auction: auction) + elsif guest? + BidStatusPresenter::AvailableUserIsGuest.new(auction: auction) + elsif auction.type == 'reverse' + BidStatusPresenter::AvailableUserIsWinningBidder.new(bid_amount: lowest_user_bid.try(:amount)) + else # sealed bid, user is bidder + BidStatusPresenter::AvailableSealedUserIsBidder.new(bid: lowest_user_bid) + end + end + + def future_message + if admin? + BidStatusPresenter::FutureUserIsAdmin.new(auction: auction) + elsif guest? + BidStatusPresenter::FutureUserIsGuest.new(auction: auction) + else + BidStatusPresenter::FutureUserIsVendor.new(auction: auction) + end + end + + def over_message + if user_is_winning_bidder? + BidStatusPresenter::OverUserIsWinner.new + elsif user_is_bidder? + BidStatusPresenter::OverUserIsBidder.new + elsif auction.bids.any? + BidStatusPresenter::OverWithBids.new + else + BidStatusPresenter::OverNoBids.new + end + end + + def admin? + user.decorate.admin? + end + + def guest? + user.is_a?(Guest) + end + + def over? + auction_status.over? + end + + def available? + auction_status.available? + end + + def future? + auction_status.future? + end + + def auction_status + AuctionStatus.new(auction) + end + + def user_is_winning_bidder? + user_bids.any? && lowest_user_bid == auction.lowest_bid + end + + def user_is_bidder? + user_bids.any? + end + + def lowest_user_bid + user_bids.order(amount: :asc).first + end + + def user_bids + auction.bids.where(bidder: user) + end +end diff --git a/app/models/c2_status_presenter_factory.rb b/app/models/c2_status_presenter_factory.rb new file mode 100644 index 00000000..0779bea5 --- /dev/null +++ b/app/models/c2_status_presenter_factory.rb @@ -0,0 +1,15 @@ +class C2StatusPresenterFactory + attr_reader :auction + + def initialize(auction:) + @auction = auction + end + + def create + if auction.c2_approval_status == 'not_requested' + C2StatusPresenter::C2ApprovalNotRequested.new(auction: auction) + else + C2StatusPresenter::C2Pending.new + end + end +end diff --git a/app/models/status_presenter_factory.rb b/app/models/status_presenter_factory.rb index eee433d1..094e3879 100644 --- a/app/models/status_presenter_factory.rb +++ b/app/models/status_presenter_factory.rb @@ -6,7 +6,7 @@ def initialize(auction) end def create - "StatusPresenter::#{status_name}".constantize.new(auction) + Object.const_get("StatusPresenter::#{status_name}").new(auction) end private diff --git a/app/presenters/auction_status_presenter_factory.rb b/app/presenters/auction_status_presenter_factory.rb deleted file mode 100644 index 6b43d111..00000000 --- a/app/presenters/auction_status_presenter_factory.rb +++ /dev/null @@ -1,157 +0,0 @@ -class AuctionStatusPresenterFactory - attr_reader :auction, :current_user - - def initialize(auction:, current_user:) - @auction = auction - @current_user = current_user - end - - def create - if available? && admin? - AvailableUserIsAdmin.new(auction: auction) - elsif available? - AvailableUserIsGuest.new(auction: auction) - elsif current_user.is_a?(Guest) - FutureUserIsGuest.new(auction: auction) - elsif admin? - FutureUserIsAdmin.new(auction: auction) - else - FutureUserIsVendor.new(auction: auction) - end - end - - private - - def available? - auction_status.available? - end - - def admin? - current_user.decorate.admin? - end - - def auction_status - AuctionStatus.new(auction) - end -end - -class AvailableUserIsAdmin - attr_reader :auction - - def initialize(auction:) - @auction = auction - end - - def to_s - "This auction is accepting bids until #{end_date}." - end - - private - - def end_date - DcTimePresenter.convert_and_format(auction.ended_at) - end -end - -class AvailableUserIsGuest - attr_reader :auction - - def initialize(auction:) - @auction = auction - end - - def to_s - "This auction is accepting bids until #{end_date}. #{sign_in_link} or - #{sign_up_link} with GitHub to bid." - end - - private - - def end_date - DcTimePresenter.convert_and_format(auction.ended_at) - end - - def sign_in_link - Url.new(link_text: 'Sign in', path_name: 'sign_in') - end - - def sign_up_link - Url.new(link_text: 'sign up', path_name: 'sign_up') - end -end - -class FutureUserIsGuest - attr_reader :auction - - def initialize(auction:) - @auction = auction - end - - def to_s - "This auction starts on #{start_date}. #{sign_in_link} or - #{sign_up_link} with GitHub to bid." - end - - private - - def start_date - DcTimePresenter.convert_and_format(auction.started_at) - end - - def sign_in_link - Url.new(link_text: 'Sign in', path_name: 'sign_in') - end - - def sign_up_link - Url.new(link_text: 'sign up', path_name: 'sign_up') - end -end - -class FutureUserIsVendor - attr_reader :auction - - def initialize(auction:) - @auction = auction - end - - def to_s - "This auction starts on #{start_date}." - end - - private - - def start_date - DcTimePresenter.convert_and_format(auction.started_at) - end -end - -class FutureUserIsAdmin - include Rails.application.routes.url_helpers - include ActionView::Helpers::UrlHelper - attr_reader :auction - - def initialize(auction:) - @auction = auction - end - - def to_s - "This auction is visible to the public but is not currently accepting bids. - It will open on #{start_date}. If you need to take it down for whatever - reason, press the unpublish button below. #{link}" - end - - private - - def link - link_to( - "Un-publish", - admin_auction_published_path(auction), - method: :patch, - class: 'usa-button usa-button-outline auction-button' - ) - end - - def start_date - DcTimePresenter.convert_and_format(auction.started_at) - end -end diff --git a/app/presenters/bid_status_flash_factory.rb b/app/presenters/bid_status_flash_factory.rb deleted file mode 100644 index 058a8e38..00000000 --- a/app/presenters/bid_status_flash_factory.rb +++ /dev/null @@ -1,132 +0,0 @@ -class BidStatusFlashFactory - attr_reader :auction, :user - - def initialize(auction:, user:) - @auction = auction - @user = user - end - - def create - if available? && auction.type == 'reverse' - AvailableUserIsWinningBidder.new(bid_amount: lowest_user_bid.try(:amount)) - elsif available? && auction.type == 'sealed_bid' - AvailableSealedUserIsBidder.new(bid: lowest_user_bid) - else - over_message - end - end - - private - - def over_message - if user_is_winning_bidder? - OverUserIsWinner.new - elsif user_is_bidder? - OverUserIsBidder.new - elsif auction.bids.any? - OverWithBids.new - else - OverNoBids.new - end - end - - def over? - auction_status.over? - end - - def available? - auction_status.available? - end - - def auction_status - AuctionStatus.new(auction) - end - - def user_is_winning_bidder? - user_bids.any? && lowest_user_bid == auction.lowest_bid - end - - def user_is_bidder? - user_bids.any? - end - - def lowest_user_bid - user_bids.order(amount: :asc).first - end - - def user_bids - auction.bids.where(bidder: user) - end -end - -class OverWithBids - def header - 'Auction Now Closed' - end - - def body - '' - end -end - -class OverUserIsWinner - def header - 'You are the winner' - end - - def body - 'Congratulations! We will contact you with further instructions.' - end -end - -class OverUserIsBidder - def header - 'You are not the winner' - end - - def body - 'Someone else placed a lower bid than you.' - end -end - -class OverNoBids - def header - 'Auction Now Closed' - end - - def body - 'This auction ended with no bids.' - end -end - -class AvailableUserIsWinningBidder - attr_reader :bid_amount - - def initialize(bid_amount:) - @bid_amount = bid_amount - end - - def header - 'Bid placed' - end - - def body - "You are currently the low bidder, with a bid of #{Currency.new(bid_amount)}" - end -end - -class AvailableSealedUserIsBidder - attr_reader :bid - - def initialize(bid:) - @bid = bid - end - - def header - '' - end - - def body - "You bid #{Currency.new(bid.amount)} on #{DcTimePresenter.convert_and_format(bid.created_at)}." - end -end diff --git a/app/presenters/bid_status_presenter/available_sealed_user_is_bidder.rb b/app/presenters/bid_status_presenter/available_sealed_user_is_bidder.rb new file mode 100644 index 00000000..fb5e34d9 --- /dev/null +++ b/app/presenters/bid_status_presenter/available_sealed_user_is_bidder.rb @@ -0,0 +1,15 @@ +class BidStatusPresenter::AvailableSealedUserIsBidder < BidStatusPresenter::Base + attr_reader :bid + + def initialize(bid:) + @bid = bid + end + + def header + '' + end + + def body + "You bid #{Currency.new(bid.amount)} on #{DcTimePresenter.convert_and_format(bid.created_at)}." + end +end diff --git a/app/presenters/bid_status_presenter/available_user_is_admin.rb b/app/presenters/bid_status_presenter/available_user_is_admin.rb new file mode 100644 index 00000000..1b33675c --- /dev/null +++ b/app/presenters/bid_status_presenter/available_user_is_admin.rb @@ -0,0 +1,11 @@ +class BidStatusPresenter::AvailableUserIsAdmin < BidStatusPresenter::Base + attr_reader :auction + + def initialize(auction:) + @auction = auction + end + + def body + "This auction is accepting bids until #{end_date}." + end +end diff --git a/app/presenters/bid_status_presenter/available_user_is_guest.rb b/app/presenters/bid_status_presenter/available_user_is_guest.rb new file mode 100644 index 00000000..c61446d8 --- /dev/null +++ b/app/presenters/bid_status_presenter/available_user_is_guest.rb @@ -0,0 +1,12 @@ +class BidStatusPresenter::AvailableUserIsGuest < BidStatusPresenter::Base + attr_reader :auction + + def initialize(auction:) + @auction = auction + end + + def body + "This auction is accepting bids until #{end_date}. #{sign_in_link} or + #{sign_up_link} with GitHub to bid." + end +end diff --git a/app/presenters/bid_status_presenter/available_user_is_winning_bidder.rb b/app/presenters/bid_status_presenter/available_user_is_winning_bidder.rb new file mode 100644 index 00000000..16791620 --- /dev/null +++ b/app/presenters/bid_status_presenter/available_user_is_winning_bidder.rb @@ -0,0 +1,15 @@ +class BidStatusPresenter::AvailableUserIsWinningBidder < BidStatusPresenter::Base + attr_reader :bid_amount + + def initialize(bid_amount:) + @bid_amount = bid_amount + end + + def header + 'Bid placed' + end + + def body + "You are currently the low bidder, with a bid of #{Currency.new(bid_amount)}" + end +end diff --git a/app/presenters/bid_status_presenter/base.rb b/app/presenters/bid_status_presenter/base.rb new file mode 100644 index 00000000..4464c5c5 --- /dev/null +++ b/app/presenters/bid_status_presenter/base.rb @@ -0,0 +1,27 @@ +class BidStatusPresenter::Base + def header + '' + end + + def body + '' + end + + protected + + def end_date + DcTimePresenter.convert_and_format(auction.ended_at) + end + + def start_date + DcTimePresenter.convert_and_format(auction.started_at) + end + + def sign_in_link + Url.new(link_text: 'Sign in', path_name: 'sign_in') + end + + def sign_up_link + Url.new(link_text: 'sign up', path_name: 'sign_up') + end +end diff --git a/app/presenters/bid_status_presenter/future_user_is_admin.rb b/app/presenters/bid_status_presenter/future_user_is_admin.rb new file mode 100644 index 00000000..aa78ade4 --- /dev/null +++ b/app/presenters/bid_status_presenter/future_user_is_admin.rb @@ -0,0 +1,27 @@ +class BidStatusPresenter::FutureUserIsAdmin < BidStatusPresenter::Base + include Rails.application.routes.url_helpers + include ActionView::Helpers::UrlHelper + + attr_reader :auction + + def initialize(auction:) + @auction = auction + end + + def body + "This auction is visible to the public but is not currently accepting bids. + It will open on #{start_date}. If you need to take it down for whatever + reason, press the unpublish button below. #{link}" + end + + private + + def link + link_to( + "Un-publish", + admin_auction_published_path(auction), + method: :patch, + class: 'usa-button usa-button-outline auction-button' + ) + end +end diff --git a/app/presenters/bid_status_presenter/future_user_is_guest.rb b/app/presenters/bid_status_presenter/future_user_is_guest.rb new file mode 100644 index 00000000..2fcceff9 --- /dev/null +++ b/app/presenters/bid_status_presenter/future_user_is_guest.rb @@ -0,0 +1,12 @@ +class BidStatusPresenter::FutureUserIsGuest < BidStatusPresenter::Base + attr_reader :auction + + def initialize(auction:) + @auction = auction + end + + def body + "This auction starts on #{start_date}. #{sign_in_link} or + #{sign_up_link} with GitHub to bid." + end +end diff --git a/app/presenters/bid_status_presenter/future_user_is_vendor.rb b/app/presenters/bid_status_presenter/future_user_is_vendor.rb new file mode 100644 index 00000000..d4dfb3a3 --- /dev/null +++ b/app/presenters/bid_status_presenter/future_user_is_vendor.rb @@ -0,0 +1,11 @@ +class BidStatusPresenter::FutureUserIsVendor < BidStatusPresenter::Base + attr_reader :auction + + def initialize(auction:) + @auction = auction + end + + def body + "This auction starts on #{start_date}." + end +end diff --git a/app/presenters/bid_status_presenter/over_no_bids.rb b/app/presenters/bid_status_presenter/over_no_bids.rb new file mode 100644 index 00000000..bd48adc8 --- /dev/null +++ b/app/presenters/bid_status_presenter/over_no_bids.rb @@ -0,0 +1,9 @@ +class BidStatusPresenter::OverNoBids < BidStatusPresenter::Base + def header + 'Auction Now Closed' + end + + def body + 'This auction ended with no bids.' + end +end diff --git a/app/presenters/bid_status_presenter/over_user_is_bidder.rb b/app/presenters/bid_status_presenter/over_user_is_bidder.rb new file mode 100644 index 00000000..b1a3803d --- /dev/null +++ b/app/presenters/bid_status_presenter/over_user_is_bidder.rb @@ -0,0 +1,9 @@ +class BidStatusPresenter::OverUserIsBidder < BidStatusPresenter::Base + def header + 'You are not the winner' + end + + def body + 'Someone else placed a lower bid than you.' + end +end diff --git a/app/presenters/bid_status_presenter/over_user_is_winner.rb b/app/presenters/bid_status_presenter/over_user_is_winner.rb new file mode 100644 index 00000000..007b162d --- /dev/null +++ b/app/presenters/bid_status_presenter/over_user_is_winner.rb @@ -0,0 +1,9 @@ +class BidStatusPresenter::OverUserIsWinner < BidStatusPresenter::Base + def header + 'You are the winner' + end + + def body + 'Congratulations! We will contact you with further instructions.' + end +end diff --git a/app/presenters/bid_status_presenter/over_with_bids.rb b/app/presenters/bid_status_presenter/over_with_bids.rb new file mode 100644 index 00000000..7af7873a --- /dev/null +++ b/app/presenters/bid_status_presenter/over_with_bids.rb @@ -0,0 +1,5 @@ +class BidStatusPresenter::OverWithBids < BidStatusPresenter::Base + def header + 'Auction Now Closed' + end +end diff --git a/app/presenters/c2_status_presenter/c2_approval_not_requested.rb b/app/presenters/c2_status_presenter/c2_approval_not_requested.rb new file mode 100644 index 00000000..b1388881 --- /dev/null +++ b/app/presenters/c2_status_presenter/c2_approval_not_requested.rb @@ -0,0 +1,30 @@ +class C2StatusPresenter::C2ApprovalNotRequested + include Rails.application.routes.url_helpers + include ActionView::Helpers::UrlHelper + + attr_reader :auction + + def initialize(auction:) + @auction = auction + end + + def header + 'C2 approval required' + end + + def body + "This auction will be paid for using an 18F purchase card, which cannot be + used without first being granted approval in C2. #{link}" + end + + private + + def link + link_to( + 'Request approval', + admin_proposals_path(auction_id: auction.id), + method: :post, + class: 'usa-button usa-button-outline auction-button' + ) + end +end diff --git a/app/presenters/c2_status_presenter/c2_pending.rb b/app/presenters/c2_status_presenter/c2_pending.rb new file mode 100644 index 00000000..e19968aa --- /dev/null +++ b/app/presenters/c2_status_presenter/c2_pending.rb @@ -0,0 +1,9 @@ +class C2StatusPresenter::C2Pending + def header + 'Pending C2 approval' + end + + def body + 'This auction has been sent to C2 for approval.' + end +end diff --git a/app/presenters/status_presenter/available.rb b/app/presenters/status_presenter/available.rb index 58374266..72b7d4af 100644 --- a/app/presenters/status_presenter/available.rb +++ b/app/presenters/status_presenter/available.rb @@ -1,4 +1,4 @@ -class StatusPresenter::Available < Struct.new(:auction) +class StatusPresenter::Available < StatusPresenter::Base def start_label "Bid start time" end diff --git a/app/presenters/status_presenter/base.rb b/app/presenters/status_presenter/base.rb new file mode 100644 index 00000000..7624444b --- /dev/null +++ b/app/presenters/status_presenter/base.rb @@ -0,0 +1,39 @@ +class StatusPresenter::Base + attr_reader :auction + + def initialize(auction) + @auction = auction + end + + def start_label + '' + end + + def deadline_label + '' + end + + def relative_time + '' + end + + def label_class + '' + end + + def label + '' + end + + def tag_data_value_status + '' + end + + def tag_data_label_2 + '' + end + + def tag_data_value_2 + '' + end +end diff --git a/app/presenters/status_presenter/future.rb b/app/presenters/status_presenter/future.rb index 50047573..18e9ef84 100644 --- a/app/presenters/status_presenter/future.rb +++ b/app/presenters/status_presenter/future.rb @@ -1,4 +1,4 @@ -class StatusPresenter::Future < Struct.new(:auction) +class StatusPresenter::Future < StatusPresenter::Base def start_label "Bid start time" end diff --git a/app/presenters/status_presenter/over.rb b/app/presenters/status_presenter/over.rb index cc0265fe..b743b67f 100644 --- a/app/presenters/status_presenter/over.rb +++ b/app/presenters/status_presenter/over.rb @@ -1,4 +1,4 @@ -class StatusPresenter::Over < Struct.new(:auction) +class StatusPresenter::Over < StatusPresenter::Base def start_label "Auction started at" end diff --git a/app/services/check_approval.rb b/app/services/check_approval.rb index 0a14cc75..2261ab41 100644 --- a/app/services/check_approval.rb +++ b/app/services/check_approval.rb @@ -9,7 +9,7 @@ def perform approved_at = find_approval_timestamp(proposal_json(auction)) if approved_at - auction.update(c2_approved_at: DateTime.parse(approved_at)) + auction.update(c2_approval_status: :approved) end end end diff --git a/app/view_models/admin/auction_show_view_model.rb b/app/view_models/admin/auction_show_view_model.rb index 407b5285..2cbdec01 100644 --- a/app/view_models/admin/auction_show_view_model.rb +++ b/app/view_models/admin/auction_show_view_model.rb @@ -14,14 +14,19 @@ def csv_report_partial end end - def create_c2_proposal_partial - if auction.purchase_card == 'default' && auction.c2_proposal_url.blank? - 'admin/auctions/create_c2_proposal' + def c2_approval_partial + if auction.purchase_card == 'default' && + (auction.c2_approval_status == 'not_requested' || auction.c2_approval_status == 'pending') + 'auctions/bid_status' else 'components/null' end end + def c2_proposal_status + C2StatusPresenterFactory.new(auction: auction).create + end + def admin_data { 'Published status' => auction.published, @@ -106,7 +111,7 @@ def c2_fields if auction.purchase_card == 'default' { 'C2 proposal URL' => auction.c2_proposal_url, - 'C2 approved at' => auction.c2_approved_at + 'C2 approval status' => auction.c2_approval_status } else { } diff --git a/app/view_models/admin/edit_auction_view_model.rb b/app/view_models/admin/edit_auction_view_model.rb index 6237eba7..2c301255 100644 --- a/app/view_models/admin/edit_auction_view_model.rb +++ b/app/view_models/admin/edit_auction_view_model.rb @@ -38,7 +38,7 @@ def published end def published_options - if closed? || auction.c2_approved_at.present? + if closed? || auction.c2_approval_status == 'approved' Auction.publisheds.keys.to_a else ['unpublished'] diff --git a/app/view_models/auction_show_view_model.rb b/app/view_models/auction_show_view_model.rb index 703e9f6d..aff3d8eb 100644 --- a/app/view_models/auction_show_view_model.rb +++ b/app/view_models/auction_show_view_model.rb @@ -68,12 +68,13 @@ def bid_form_header end end - def bid_status_class - BidStatusFlashFactory.new(auction: auction, user: current_user).create + def bid_status + BidStatusPresenterFactory.new(auction: auction, user: current_user).create end def bid_status_partial - if reverse_auction_over? || + if !available? || + user_not_vendor? || reverse_auction_available_user_is_winner? || sealed_bid_auction_user_is_bidder? 'auctions/bid_status' @@ -82,19 +83,7 @@ def bid_status_partial end end - def auction_status_partial - if (available? && (current_user.is_a?(Guest) || current_user.decorate.admin?)) || future? - 'auctions/status' - else - 'components/null' - end - end - - def auction_status_presenter - AuctionStatusPresenterFactory.new(auction: auction, current_user: current_user).create - end - - def bid_status + def bid_status_label if over? && auction.bids.any? "Winning bid (#{lowest_bidder_name}): #{highlighted_bid_amount_as_currency}" elsif user_bids.any? @@ -192,8 +181,8 @@ def veiled_bids private - def reverse_auction_over? - auction.type == 'reverse' && over? + def user_not_vendor? + current_user.is_a?(Guest) || current_user.decorate.admin? end def reverse_auction_available_user_is_winner? diff --git a/app/views/admin/auctions/_create_c2_proposal.html.erb b/app/views/admin/auctions/_create_c2_proposal.html.erb deleted file mode 100644 index 9d4e7ebd..00000000 --- a/app/views/admin/auctions/_create_c2_proposal.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -<%= link_to 'Create C2 Proposal', - admin_proposals_path(auction_id: auction.id), - method: :post, - class: 'admin-action-button' %> diff --git a/app/views/admin/auctions/show.html.erb b/app/views/admin/auctions/show.html.erb index 29578b4b..2a1fa4d4 100644 --- a/app/views/admin/auctions/show.html.erb +++ b/app/views/admin/auctions/show.html.erb @@ -13,8 +13,6 @@

<%= @view_model.title %>

<%= render partial: @view_model.admin_edit_auction_partial, locals: { view_model: @view_model } %> - <%= render partial: @view_model.create_c2_proposal_partial, - locals: { auction: @view_model } %> <%= render partial: @view_model.csv_report_partial, locals: { auction: @view_model } %>
@@ -32,6 +30,9 @@
+ <%= render partial: @view_model.c2_approval_partial, + locals: { status: @view_model.c2_proposal_status } %> +
<% @view_model.admin_data.each do |label, data| %> diff --git a/app/views/auctions/_bid_status.html.erb b/app/views/auctions/_bid_status.html.erb index 608c20f7..ad1e2ed0 100644 --- a/app/views/auctions/_bid_status.html.erb +++ b/app/views/auctions/_bid_status.html.erb @@ -2,7 +2,7 @@

<%= status.header %>

-

<%= status.body %>

+

<%= raw status.body %>

diff --git a/app/views/auctions/_status.html.erb b/app/views/auctions/_status.html.erb deleted file mode 100644 index 622827d2..00000000 --- a/app/views/auctions/_status.html.erb +++ /dev/null @@ -1,9 +0,0 @@ -
-
-
-

- <%= view_model.auction_status_presenter.to_s.html_safe %> -

-
-
-
diff --git a/app/views/auctions/show.html.erb b/app/views/auctions/show.html.erb index 214cb642..5495e0ec 100644 --- a/app/views/auctions/show.html.erb +++ b/app/views/auctions/show.html.erb @@ -31,7 +31,7 @@ <%= @view_model.relative_time %>
- <%= @view_model.bid_status %> + <%= @view_model.bid_status_label %>
@@ -45,10 +45,7 @@
<%= render partial: @view_model.bid_status_partial, - locals: { status: @view_model.bid_status_class } %> - - <%= render partial: @view_model.auction_status_partial, - locals: { view_model: @view_model } %> + locals: { status: @view_model.bid_status } %> <%= render partial: @view_model.bid_form_partial, locals: { auction: @view_model } %> diff --git a/db/migrate/20160804230057_change_c2_approved_at_to_c2_approval_status.rb b/db/migrate/20160804230057_change_c2_approved_at_to_c2_approval_status.rb new file mode 100644 index 00000000..1f5cc651 --- /dev/null +++ b/db/migrate/20160804230057_change_c2_approved_at_to_c2_approval_status.rb @@ -0,0 +1,38 @@ +class ChangeC2ApprovedAtToC2ApprovalStatus < ActiveRecord::Migration + def up + add_column :auctions, :c2_approval_status, :integer, null: false, default: 0 + + # 0 no c2 proposal + # 1 no c2 proposal, was requested + # 2 c2 proposal, not approved + # 3 c2 proposal, approved + + execute <<-SQL + UPDATE auctions + SET c2_approval_status = 0 + WHERE c2_approved_at IS NULL + AND c2_proposal_url = ''; + SQL + + execute <<-SQL + UPDATE auctions + SET c2_approval_status = 2 + WHERE c2_approved_at IS NULL + AND c2_proposal_url != ''; + SQL + + execute <<-SQL + UPDATE auctions + SET c2_approval_status = 3 + WHERE c2_approved_at IS NOT NULL + AND c2_proposal_url != ''; + SQL + + remove_column :auctions, :c2_approved_at + end + + def down + add_column :auctions, :c2_approved_at, :datetime + remove_column :auctions, :c2_approval_status, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index c2af67dc..d9b0eeee 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,37 +11,37 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160715201738) do +ActiveRecord::Schema.define(version: 20160804230057) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" create_table "auctions", force: :cascade do |t| - t.string "issue_url", default: "" - t.integer "start_price", default: 3500, null: false - t.datetime "started_at", null: false - t.datetime "ended_at", null: false - t.string "title", null: false - t.text "description", default: "", null: false - t.string "github_repo", default: "" - t.integer "published", default: 0 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.text "summary", default: "", null: false + t.string "issue_url", default: "" + t.integer "start_price", default: 3500, null: false + t.datetime "started_at", null: false + t.datetime "ended_at", null: false + t.string "title", null: false + t.text "description", default: "", null: false + t.string "github_repo", default: "" + t.integer "published", default: 0 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.text "summary", default: "", null: false t.datetime "delivery_due_at" - t.text "notes", default: "" - t.string "billable_to", default: "" - t.integer "result", default: 0 - t.integer "type", default: 0 + t.text "notes", default: "" + t.string "billable_to", default: "" + t.integer "result", default: 0 + t.integer "type", default: 0 t.string "delivery_url" - t.string "c2_proposal_url", default: "" + t.string "c2_proposal_url", default: "" t.integer "user_id" - t.integer "purchase_card", default: 0, null: false + t.integer "purchase_card", default: 0, null: false t.datetime "paid_at" t.datetime "accepted_at" t.datetime "rejected_at" - t.datetime "c2_approved_at" t.integer "customer_id" + t.integer "c2_approval_status", default: 0, null: false end add_index "auctions", ["customer_id"], name: "index_auctions_on_customer_id", using: :btree diff --git a/features/admin_requests_c2_approval.feature b/features/admin_requests_c2_approval.feature index 3b3cc725..678ded1a 100644 --- a/features/admin_requests_c2_approval.feature +++ b/features/admin_requests_c2_approval.feature @@ -2,16 +2,31 @@ Feature: Admin requests C2 approval for an auction As an admin I should be able to request C2 approvalf for an auction - Scenario: Auction does not have a C2 proposal + @background_jobs_off + Scenario: Admin requests C2 approval, C2 proposal pending + Given I am an administrator + And I sign in + And there is an unpublished auction + And the auction does not have a c2 proposal url + When I visit the admin auction page for that auction + Then I should see "This auction will be paid for using an 18F purchase card, which cannot be used without first being granted approval in C2." + + When I click on the "Request approval" button + Then I should see "This auction has been sent to C2 for approval." + And I should see that the auction does not have a C2 Proposal URL + And I should not see a "Request approval" button + + Scenario: Admin requests C2 approval, C2 proposal created Given I am an administrator And I sign in And there is an unpublished auction And the auction does not have a c2 proposal url When I visit the admin auction page for that auction Then I should see that the auction does not have a C2 Proposal URL - When I click on the "Create C2 Proposal" button - Then I should see that the auction has a C2 Proposal URL - And I should not see a "Create C2 Proposal" button + When I click on the "Request approval" button + Then I should see "This auction has been sent to C2 for approval. You can check on the status here." + And I should see that the auction has a C2 Proposal URL + And I should not see a "Request approval" button Scenario: Auction has a C2 proposal Given I am an administrator diff --git a/features/step_definitions/auction_create_steps.rb b/features/step_definitions/auction_create_steps.rb index 017c433a..5e8e3e2c 100644 --- a/features/step_definitions/auction_create_steps.rb +++ b/features/step_definitions/auction_create_steps.rb @@ -134,11 +134,11 @@ end Given(/^the c2 proposal for the auction is approved$/) do - @auction.update(c2_approved_at: Time.current) + @auction.update(c2_approval_status: :approved) end Given(/^the c2 proposal for the auction is not approved$/) do - @auction.update(c2_approved_at: nil) + @auction.update(c2_approval_status: :not_requested) end Given(/^the auction does not have a c2 proposal url$/) do diff --git a/spec/factories/auctions.rb b/spec/factories/auctions.rb index 64b3385d..beacca69 100644 --- a/spec/factories/auctions.rb +++ b/spec/factories/auctions.rb @@ -131,7 +131,7 @@ trait :c2_approved do c2_proposal_url 'https://c2-dev.18f.gov/proposals/2486' - c2_approved_at { Time.current } + c2_approval_status :approved end trait :not_evaluated do diff --git a/spec/services/check_approval_spec.rb b/spec/services/check_approval_spec.rb index 74b98122..77bc1b4e 100644 --- a/spec/services/check_approval_spec.rb +++ b/spec/services/check_approval_spec.rb @@ -30,7 +30,7 @@ CheckApproval.new.perform - expect(auction.reload.c2_approved_at).not_to be_nil + expect(auction.reload.c2_approval_status).to eq 'approved' end end @@ -40,12 +40,13 @@ auction = create( :auction, :unpublished, + c2_approval_status: :pending, c2_proposal_url: "https://c2-dev.18f.gov/#{c2_path}" ) CheckApproval.new.perform - expect(auction.reload.c2_approved_at).to be_nil + expect(auction.reload.c2_approval_status).to eq 'pending' end end diff --git a/spec/view_models/admin/auction_show_view_model_spec.rb b/spec/view_models/admin/auction_show_view_model_spec.rb index 234becde..e60ab485 100644 --- a/spec/view_models/admin/auction_show_view_model_spec.rb +++ b/spec/view_models/admin/auction_show_view_model_spec.rb @@ -10,7 +10,7 @@ data = view_model.admin_data expect(data).to have_key('C2 proposal URL') - expect(data).to have_key('C2 approved at') + expect(data).to have_key('C2 approval status') end end diff --git a/spec/view_models/admin/edit_auction_view_model_spec.rb b/spec/view_models/admin/edit_auction_view_model_spec.rb index 389198ea..c20b2f18 100644 --- a/spec/view_models/admin/edit_auction_view_model_spec.rb +++ b/spec/view_models/admin/edit_auction_view_model_spec.rb @@ -2,10 +2,10 @@ describe Admin::EditAuctionViewModel do describe '#published_options' do - context 'auction does not have c2_approved_at' do + context 'auction does not have c2 approval' do context 'auction is closed' do it 'returns all options' do - auction = create(:auction, :closed, c2_approved_at: nil) + auction = create(:auction, :closed, c2_approval_status: :not_requested) view_model = Admin::EditAuctionViewModel.new(auction) @@ -15,7 +15,7 @@ context 'auction is not closed' do it 'does not return published option' do - auction = create(:auction, :future, c2_approved_at: nil) + auction = create(:auction, :future, c2_approval_status: :not_requested) view_model = Admin::EditAuctionViewModel.new(auction) @@ -26,7 +26,7 @@ context 'auction does have c2_approved_at' do it 'returns all options' do - auction = create(:auction, c2_approved_at: Time.current) + auction = create(:auction, c2_approval_status: :approved) view_model = Admin::EditAuctionViewModel.new(auction)