#--
# Copyright (c) 2007 Robert S. Thau, Smartleaf, Inc.
# 
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
require File.dirname(__FILE__) + '/../test_helper'

class OrderTest < Test::Unit::TestCase

  use_all_fixtures

  def test_validations_and_reqs
    o = Order.new :owner => users(:ethel), :store => stores(:rickys)
    assert_valid o
    assert_equal stores(:rickys).owner_firm, o.owner_firm
    assert_requires( owner_perm( :place, Order, users(:ethel) )) do
      o.save!
    end

    assert_nil o.payment_authenticator
    assert     !o.paid?

    assert_requires( owner_perm( :place, Order, users(:ethel) )) do
      o.pay_with('0123456789')
      assert_equal '0123456789', o.payment_authenticator
      assert                     o.paid?
    end

    assert_requires( owner_perm( :edit, Order, users(:ethel) )) do
      test_validation o, :shipping_address, 
        :invalid => [nil, '', 'foo'],
        :valid   => ['3 cherry tree lane, nowhere, CA, 00000']
    end

    assert_valid o

    assert o.save

    assert_raises( PermissionFailure ) do
      User.as( users(:ethel)) do
        o.destroy
      end
    end
    
  end

  def test_add_item

    order          = orders(:lucys_order)
    offer          = offers(:ricardo_sax)
    initial_nitems = order.line_items.count

    assert_nil order.line_items.detect{ |it| it.offer == offer }

    assert_requires( one_object_perm( :edit, order ) ) do
      order.add_item( offer )
    end

    order.line_items :force_reload
    sax_item = order.line_items.detect{ |it| it.offer == offer }

    order.line_items :force_reload
    assert_equal 1 + initial_nitems, order.line_items.count
    assert_equal 1, sax_item.quantity

    # Note workaround for AR braindeath --- line_item permissions are
    # keyed to the order.  We loaded it through the order, but AR doesn't
    # remember that, and so attempts to reload it.  At least we have the
    # cache, so this is just constructing redundant objects.  Sigh...

    assert_requires( one_object_perm( :edit, order ),
                     one_object_perm( :find, order ) ) do
      order.add_item( offer )
    end

    order.line_items :force_reload
    sax_item.reload
    assert_equal 1 + initial_nitems, order.line_items.count
    assert_equal 2, sax_item.quantity

  end

  def test_update_attributes_good

    order = orders(:lucys_order)
    perms = [one_object_perm( :edit, order ),
             one_object_perm( :find, order ),
             one_object_perm( :administer, order )]

    assert_requires(*perms) do

      assert order.update_attributes( 
        :notes => 'drizzle drizzle',
        :line_item => { 
          line_items(:lucy_order_clarinet).id.to_s => { :quantity => '53' },
          line_items(:lucy_order_bassoon).id.to_s  => { :quantity => '0'  }
        })

      order.reload
      assert_equal 'drizzle drizzle', order.notes

    end

    line_items(:lucy_order_clarinet).reload
    assert_equal 53, line_items(:lucy_order_clarinet).quantity

    assert_nil LineItem.find_by_id( line_items(:lucy_order_bassoon).id )

    assert_requires(*perms) do
      assert order.update_attributes( 
        :notes => 'rain rain',
        :line_item => { 
          line_items(:lucy_order_clarinet).id.to_s => { :quantity => ' ' },
        })

      order.reload
      assert_equal 'rain rain', order.notes
      assert_nil LineItem.find_by_id( line_items(:lucy_order_clarinet).id )

    end

  end

  def test_update_attributes_bad_order

    order = orders(:lucys_order)

    assert_requires( one_object_perm( :place, order) ) do
      order.pay_with( 'a' )
      assert !order.valid?
    end

    perms = [one_object_perm( :edit,  order ),
             one_object_perm( :find,  order ),
             one_object_perm( :place, order )
            ]
    
    assert_requires(*perms) do
      assert !order.update_attributes( 
        :payment_authenticator => 'b',
        :line_item => { 
          line_items(:lucy_order_clarinet).id.to_s => { :quantity => '53' },
          line_items(:lucy_order_bassoon).id.to_s  => { :quantity => '0'  }
        })
    end

    clarinet_item = order.line_items.detect do |it| 
      it.id == line_items(:lucy_order_clarinet).id
    end

    bassoon_item = order.line_items.detect do |it| 
      it.id == line_items(:lucy_order_bassoon).id
    end

    assert_equal 'b',  order.payment_authenticator
    assert_equal '53', clarinet_item.quantity_before_type_cast
    assert_equal '0',  bassoon_item.quantity_before_type_cast

    assert_requires( one_object_perm( :find, order )) do
      assert_nil      order.reload.payment_authenticator
      assert_equal 2, clarinet_item.reload.quantity
      assert_equal 5, bassoon_item.reload.quantity
    end

  end

  def test_update_attributes_bad_item

    order = orders(:lucys_order)
    perms = [one_object_perm( :edit,       order ),
             one_object_perm( :find,       order ),
             one_object_perm( :administer, order)]

    assert_requires(*perms) do
      assert !order.update_attributes( 
        :notes => 'note note',
        :line_item => { 
          line_items(:lucy_order_clarinet).id.to_s => { :quantity => '-1' },
          line_items(:lucy_order_bassoon).id.to_s  => { :quantity => '0'  }
        })
    end

    clarinet_item = order.line_items.detect do |it| 
      it.id == line_items(:lucy_order_clarinet).id
    end

    bassoon_item = order.line_items.detect do |it| 
      it.id == line_items(:lucy_order_bassoon).id
    end

    assert_equal 'note note', order.notes
    assert_equal '-1',        clarinet_item.quantity_before_type_cast
    assert_equal '0',         bassoon_item.quantity_before_type_cast

    assert_requires( one_object_perm( :find, order )) do
      assert_nil      order.reload.notes
      assert_equal 2, clarinet_item.reload.quantity
      assert_equal 5, bassoon_item.reload.quantity
    end

  end

end

