--- /dev/null
+class BonusPolicyController < ApplicationController
+ layout "admin"
+
+ before_filter :authorize, :except => ['new', 'create', 'edit', 'update', 'destroy']
+ before_filter :manager, :only => ['new', 'create', 'edit', 'update', 'destroy']
+
+ def index
+ list
+ render :action => 'list'
+ end
+
+ # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
+ verify :method => :post, :only => [ :destroy, :create, :update ],
+ :redirect_to => { :action => :list }
+
+ def list
+ @bonus_policy_pages, @bonus_policies = paginate :bonus_policies, :per_page => 10
+ end
+
+ def show
+ @bonus_policy = BonusPolicy.find(params[:id])
+ end
+
+ def new
+ @bonus_policy = BonusPolicy.new
+ end
+
+ def create
+ @bonus_policy = BonusPolicy.new(params[:bonus_policy])
+ if @bonus_policy.save
+ flash[:notice] = 'BonusPolicy was successfully created.'
+ redirect_to :action => 'list'
+ else
+ render :action => 'new'
+ end
+ end
+
+ def edit
+ @bonus_policy = BonusPolicy.find(params[:id])
+ end
+
+ def update
+ @bonus_policy = BonusPolicy.find(params[:id])
+ if @bonus_policy.update_attributes(params[:bonus_policy])
+ flash[:notice] = 'BonusPolicy was successfully updated.'
+ redirect_to :action => 'show', :id => @bonus_policy
+ else
+ render :action => 'edit'
+ end
+ end
+
+ def destroy
+ BonusPolicy.find(params[:id]).destroy
+ redirect_to :action => 'list'
+ end
+end
render :action => 'begin'
session[:total] = 0.00
session[:items] = []
+ session[:bonus] = nil
end
def receipt
@debt = @customer.debt
@total = session[:total] + @debt
@items = session[:items]
+ @bonus = session[:bonus]
@time = Time.now
# Record a Late Fee Payment if we need to
- if @debt
+ if not @debt.zero?
purchase = LateFeePurchase.new
purchase.customer = @customer
purchase.date = Time.now.to_date
session[:customer_id] = nil
session[:total] = nil
session[:items] = nil
+ session[:bonus] = nil
# Show the receipt
render :action => 'receipt'
return
end
+ # Check for a Bonus
+ for bonus in BonusPolicy.find_all_by_bonus_type(@rentable.class.to_s)
+ # Find the earliest the period for this bonus extends
+ since_date = Time.now.advance(:days => (-1 * bonus.days)).to_date
+
+ # Find the date of the latest bonus in this period
+ last_bonus_date = BonusPurchase.last_bonus_date(@customer, @rentable.class, since_date)
+
+ # Find the number of rentals of this type in the period since the last bonus
+ count = 0
+ for rental in RentablePurchase.find_all_by_customer_id(@customer, :conditions => ["date > ?", last_bonus_date])
+ if rental.rentable.class == @rentable.class
+ count += 1
+ end
+ end
+
+ # We are eligible for a bonus!
+ if count >= bonus.number
+
+ # Check out the item
+ checkout = Coitem.new
+ checkout.customer = @customer
+ checkout.rentable = @rentable
+ checkout.out_date = Time.now.to_date
+ checkout.due_date = @rentable.due_date
+ checkout.save!
+
+ # Record the BonusPurchase
+ purchase = BonusPurchase.new
+ purchase.customer = @customer
+ purchase.date = Time.now.to_date
+ purchase.price = @rentable.calculated_price
+ purchase.rentable = @rentable
+ purchase.save!
+
+ # Add to session variables
+ session[:items].push @rentable
+ session[:bonus] = @rentable
+
+ flash[:notice] = "Successfully made bonus purchase"
+ redirect_to :action => :menu
+ return
+ end
+ end
+
# Check out the item
checkout = Coitem.new
checkout.customer = @customer
--- /dev/null
+module BonusPolicyHelper
+end
--- /dev/null
+class BonusPolicy < ActiveRecord::Base
+
+ validates_presence_of :number
+ validates_presence_of :bonus_type
+ validates_presence_of :days
+
+ validates_numericality_of :number
+ validates_numericality_of :days
+
+ def description
+ return "One #{bonus_type} free after #{number} #{bonus_type} rentals in the last #{days} days"
+ end
+
+ protected
+ def validate
+ errors.add(:days, "must be at least 1") if days.nil? || days < 1
+ errors.add(:number, "must be at least 1") if number.nil? || number < 1
+ errors.add(:bonus_type, "must be either Video or Game") unless bonus_type == 'Video' or bonus_type == 'Game'
+ end
+end
--- /dev/null
+class BonusPurchase < Purchase
+ belongs_to :rentable
+ belongs_to :customer
+
+ validates_presence_of :rentable_id
+ validates_numericality_of :rentable_id
+
+ def self.last_bonus_date(customer,bonus_type,since_date)
+ bonuses = BonusPurchase.find_all_by_customer_id(customer, :conditions => ["date >= ?", since_date], :order => 'date DESC')
+ puts "*** BONUSES.length: #{bonuses.length} ***"
+ for bonus in bonuses
+ puts "#{bonus.rentable.class.to_s} == #{bonus_type.to_s} => #{bonus.rentable.class.to_s == bonus_type.to_s}"
+ if bonus.rentable.class.to_s == bonus_type.to_s
+ return bonus.date
+ end
+ end
+
+ # Unable to find a last bonus, no bonuses in period
+ return since_date
+ end
+
+ protected
+ def validate
+ errors.add(:rentable_id, "is not in the database") if rentable.nil?
+ end
+end
+
has_many :coitems
has_many :merchandise_purchases
has_many :rentable_purchases
+ has_many :bonus_purchases
+ has_many :late_fee_purchases
validates_presence_of :name, :email, :phone, :address
validates_numericality_of :debt
validates_numericality_of :price
def title
- if type == MerchandisePurchase
+ if self.class == MerchandisePurchase
return merchandise.title
- elsif type == RentablePurchase
+ elsif self.class == RentablePurchase
+ return rentable.title
+ elsif self.class == BonusPurchase
return rentable.title
else
return 'Late Fees'
protected
def validate
errors.add(:price, "cannot be negative") if price < 0
- errors.add(:price, "cannot be less than $0.01") if price < 0.01
+ # Need to leave this out for bonuses
+ #errors.add(:price, "cannot be less than $0.01") if price < 0.01
errors.add(:customer_id, "does not exist in the database") if customer.nil?
end
end
end
def calculated_price
- # FIXME: generate this based on day of week, newrelease
day_of_week = Time.now.to_date.wday
base_fee = VideoPolicy.find_by_day(day_of_week).fee
end
def due_date
- # FIXME: generate this based on the day of week, newrelease
# NOTE: a Date.wday will tell you the day of week (0-6, meaning Sunday-Saturday)
day_of_week = Time.now.to_date.wday
base_period = VideoPolicy.find_by_day(day_of_week).period
--- /dev/null
+<%= error_messages_for 'bonus_policy' %>
+
+<!--[form:bonus_policy]-->
+<p><label for="bonus_policy_number">Number</label><br/>
+<%= text_field 'bonus_policy', 'number' %></p>
+
+<p><label for="bonus_policy_bonus_type">Type</label><br/>
+<%= select 'bonus_policy', 'bonus_type', [Game, Video] %></p>
+
+<p><label for="bonus_policy_days">Days</label><br/>
+<%= text_field 'bonus_policy', 'days' %></p>
+<!--[eoform:bonus_policy]-->
+
--- /dev/null
+<h1>Editing bonus_policy</h1>
+
+<% form_tag :action => 'update', :id => @bonus_policy do %>
+ <%= render :partial => 'form' %>
+ <%= submit_tag 'Edit' %>
+<% end %>
+
+<%= link_to 'Show', :action => 'show', :id => @bonus_policy %> |
+<%= link_to 'Back', :action => 'list' %>
--- /dev/null
+<h1>Listing bonus_policies</h1>
+
+<table>
+ <tr>
+ <th>Number</th>
+ <th>Bonus Type</th>
+ <th>Days</th>
+ <th>Description</th>
+ </tr>
+
+<% for bonus_policy in @bonus_policies %>
+ <tr>
+ <td><%=h bonus_policy.number %></td>
+ <td><%=h bonus_policy.bonus_type %></td>
+ <td><%=h bonus_policy.days %></td>
+ <td><%=h bonus_policy.description %></td>
+ <td><%= link_to 'Show', :action => 'show', :id => bonus_policy %></td>
+ <td><%= link_to 'Edit', :action => 'edit', :id => bonus_policy %></td>
+ <td><%= link_to 'Destroy', { :action => 'destroy', :id => bonus_policy }, :confirm => 'Are you sure?', :method => :post %></td>
+ </tr>
+<% end %>
+</table>
+
+<%= link_to 'Previous page', { :page => @bonus_policy_pages.current.previous } if @bonus_policy_pages.current.previous %>
+<%= link_to 'Next page', { :page => @bonus_policy_pages.current.next } if @bonus_policy_pages.current.next %>
+
+<br />
+
+<%= link_to 'New bonus_policy', :action => 'new' %>
--- /dev/null
+<h1>New bonus_policy</h1>
+
+<% form_tag :action => 'create' do %>
+ <%= render :partial => 'form' %>
+ <%= submit_tag "Create" %>
+<% end %>
+
+<%= link_to 'Back', :action => 'list' %>
--- /dev/null
+<% for column in BonusPolicy.content_columns %>
+<p>
+ <b><%= column.human_name %>:</b> <%=h @bonus_policy.send(column.name) %>
+</p>
+<% end %>
+
+<%= link_to 'Edit', :action => 'edit', :id => @bonus_policy %> |
+<%= link_to 'Back', :action => 'list' %>
<p><%= link_to "Customer Maintenence", :controller => 'customer', :action => 'index' %></p>
<p><%= link_to "Financial Information", :controller => 'purchase', :action => 'index' %></p>
<p><%= link_to "System Maintenence", :controller => 'login', :action => 'maintenence' %></p>
- <p><%= link_to "Rental Policies and Limits", :controller => 'login', :action => 'limits' %></p>
+ <p><%= link_to "Rental and Bonus Policies", :controller => 'login', :action => 'limits' %></p>
<br/>
<p><%= link_to "Logout", :controller => 'login', :action => 'logout' %></p>
</div>
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <title>BonusPolicy: <%= controller.action_name %></title>
+ <%= stylesheet_link_tag 'scaffold' %>
+</head>
+<body>
+
+<p style="color: green"><%= flash[:notice] %></p>
+
+<%= yield %>
+
+</body>
+</html>
-<h1>Rental Limits and Pricing</h1>
+<h1>Rental and Bonus Policies</h1>
<h3>Actions</h3>
<ul>
<li><%= link_to 'Game Rental Pricing', :controller => 'game_policy', :action => 'index' %></li>
<li><%= link_to 'Video Rental Pricing', :controller => 'video_policy', :action => 'index' %></li>
<li><%= link_to 'Rental Limits', :controller => 'rentable_policy', :action => 'index' %></li>
+ <li><%= link_to 'Bonus Policies', :controller => 'bonus_policy', :action => 'index' %></li>
</ul>
<h1>Employees</h1>
+
+<p>Press the "[X]" next to the username to delete that user</p>
+
<ul>
<% for user in @all_users %>
<li><%=link_to "[X]", { # link_to options
the box below.</p>
<%= start_form_tag :action => 'buy_merch'%>
-<%= text_field 'merchandise_id', nil %>
- <%= submit_tag 'Ok' %></form>
+ <%= text_field 'merchandise_id', nil %>
+ <%= submit_tag 'Ok' %>
<%= end_form_tag %>
+<br/>
+<p><%=link_to 'Check Out', :action => 'receipt' %></p>
<% for purchase in @purchases %>
<tr>
<td><%=link_to purchase.date, :action => 'filterbydate', :id => purchase.date %></td>
- <td><%=link_to purchase.class, :action => 'filterbytype', :id => purchase.type %></td>
+ <td><%=link_to purchase.class, :action => 'filterbytype', :id => purchase.class %></td>
<td><%=h purchase.title %></td>
<td><%=h number_to_currency(purchase.price) %></td>
<td><%=link_to purchase.customer.name, :action => 'filterbycust', :id => purchase.customer_id %></td>
<br/>
<br/>
<br/>
- <li><%=link_to 'End Purchase', :action => 'receipt' %></li>
+ <li><%=link_to 'Checkout', :action => 'receipt' %></li>
</ul>
</tr>
<!-- Debt -->
- <% if @debt %>
+ <% if not @debt.zero? %>
<tr>
<td><b>Overdue Item Fees</b></td>
<td></td>
<td><%=h number_to_currency(item.price) %></td>
<% end %>
</tr>
+<% end %>
+<% if @bonus %>
+ <tr>
+ <td><b>Bonus: </b><%=h @bonus.title %></td>
+ <td></td>
+ <td>- <%= number_to_currency(@bonus.calculated_price) %></td>
+ </tr>
<% end %>
<tr>
<td><b>Total</b></td>
the box below.</p>
<%= start_form_tag :action => 'rent'%>
-<%= text_field 'rentable_id', nil %>
- <%= submit_tag 'Ok' %></form>
+ <%= text_field 'rentable_id', nil %>
+ <%= submit_tag 'Ok' %>
<%= end_form_tag %>
+<br/>
+<p><%=link_to 'Check Out', :action => 'receipt' %></p>
+
--- /dev/null
+class CreateBonusPolicies < ActiveRecord::Migration
+ def self.up
+ create_table :bonus_policies do |t|
+ t.column :number, :integer
+ t.column :bonus_type, :string
+ t.column :days, :integer
+ end
+ end
+
+ def self.down
+ drop_table :bonus_policies
+ end
+end
# migrations feature of ActiveRecord to incrementally modify your database, and
# then regenerate this schema definition.
-ActiveRecord::Schema.define(:version => 32) do
+ActiveRecord::Schema.define(:version => 33) do
+
+ create_table "bonus_policies", :force => true do |t|
+ t.column "number", :integer
+ t.column "bonus_type", :string
+ t.column "days", :integer
+ end
create_table "coitems", :force => true do |t|
t.column "customer_id", :integer
--- /dev/null
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+one:
+ id: 1
+two:
+ id: 2
--- /dev/null
+require File.dirname(__FILE__) + '/../test_helper'
+require 'bonus_policy_controller'
+
+# Re-raise errors caught by the controller.
+class BonusPolicyController; def rescue_action(e) raise e end; end
+
+class BonusPolicyControllerTest < Test::Unit::TestCase
+ fixtures :bonus_policies
+
+ def setup
+ @controller = BonusPolicyController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+
+ @first_id = bonus_policies(:first).id
+ end
+
+ def test_index
+ get :index
+ assert_response :success
+ assert_template 'list'
+ end
+
+ def test_list
+ get :list
+
+ assert_response :success
+ assert_template 'list'
+
+ assert_not_nil assigns(:bonus_policies)
+ end
+
+ def test_show
+ get :show, :id => @first_id
+
+ assert_response :success
+ assert_template 'show'
+
+ assert_not_nil assigns(:bonus_policy)
+ assert assigns(:bonus_policy).valid?
+ end
+
+ def test_new
+ get :new
+
+ assert_response :success
+ assert_template 'new'
+
+ assert_not_nil assigns(:bonus_policy)
+ end
+
+ def test_create
+ num_bonus_policies = BonusPolicy.count
+
+ post :create, :bonus_policy => {}
+
+ assert_response :redirect
+ assert_redirected_to :action => 'list'
+
+ assert_equal num_bonus_policies + 1, BonusPolicy.count
+ end
+
+ def test_edit
+ get :edit, :id => @first_id
+
+ assert_response :success
+ assert_template 'edit'
+
+ assert_not_nil assigns(:bonus_policy)
+ assert assigns(:bonus_policy).valid?
+ end
+
+ def test_update
+ post :update, :id => @first_id
+ assert_response :redirect
+ assert_redirected_to :action => 'show', :id => @first_id
+ end
+
+ def test_destroy
+ assert_nothing_raised {
+ BonusPolicy.find(@first_id)
+ }
+
+ post :destroy, :id => @first_id
+ assert_response :redirect
+ assert_redirected_to :action => 'list'
+
+ assert_raise(ActiveRecord::RecordNotFound) {
+ BonusPolicy.find(@first_id)
+ }
+ end
+end
--- /dev/null
+require File.dirname(__FILE__) + '/../test_helper'
+
+class BonusPolicyTest < Test::Unit::TestCase
+ fixtures :bonus_policies
+
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end