The satisfaction of Rails

More work on XChain. In some spare hours on the weekend I implemented the basic structure of price catalogues for products. I can’t tell you how long this took when previously doing it in PHP a few years back! (or even worse ASP a few years further back still). I’m sold on BDD, it was so quick to bang this out starting with the spec it first approach, mainly because all you need to do is ‘rake spec’, and bingo your code is tested…

As follows, note code is cut down a little, but you get the picture:

# A product itself does not contain any price information, it has many price's in a 'pricing' model, that is linked
# to price types, eg "Standard Distributor" "Standard Retail"
class Product < ActiveRecord::Base
  has_many :pricings
  has_many :price_types, :through => :pricings
  belongs_to :order_line
end
 
#The pricing table, not only links to a product and price_type, it also has a discount
#model associated with it..
class Pricing < ActiveRecord::Base
  set_table_name 'pricing'
  belongs_to :product
  belongs_to :price_type
  belongs_to :discount
end

 
# discount linked to the pricing, and discount tables to enable volume based discounting.
class Discount < ActiveRecord::Base
  has_many :pricing
  has_many :discount_tables, :order => "qty ASC"
  #note that I don't want to do queries every time I ask get_discount, so I just iterate over the
  # tables to find the discount, rather than doing a find each time.
  def get_discount(qty)
    discount_tables.each do |dt|
      return dt.discount_applied if qty <= dt.qty
    end
    return discount_tables.last.discount_applied
  end
end
 
 
# In order to calculate price, we need to determine the pricing model for the order (taken from price type)
# then look up the unit price for the product according to the price type
# finally get the discount for the volume at that price type.
class OrderLine < ActiveRecord::Base
  belongs_to :order
  belongs_to :product
  def get_price(price_type)
    @pricing = product.get_pricing(price_type)
    price_as_ordered = ( get_unit_price * qty_ordered ) * get_discount
  end
 
  protected
  def get_unit_price
    @pricing.get_unit_price()
  end
 
  def get_discount
    @pricing.discount.get_discount(self.qty_ordered)
  end

You feel like you accomplished something when you sit down to work for a few hours and you get this…

=====================
rowans-computer:~/work/xchain rowan$ rake spec;
(in /Users/rowan/work/xchain)

DiscountTable
- should be valid

Discount when loading existing discount
- should return a max discount of 0.25 for a quantity of 10000
- should return a discount of 1 for a quantity of 20
- should return a discount of 1.5 for a quantity of 5
- should respond to get discount
- should have a discount table
- should have a name
- should belong to a pricing

Order when finding existing order
- should have a customer
- should have a billing address
- should have 3 order lines
- should have a purchase order number
- should have id = 1

Order with a single, invalid order line added
- should after changing the quantity be able to be saved
- should not be able to be saved as it has incorrect quantity
- should calculate to a correct amount

Order new draft order
- should be in the order collection list
- should belong to the correct customer
- should have an associated user who created it
- should be able to have it's address changed
- should be able to be changed to a new status

Order when creating a new order
- should when valid and saved, have one order status history item
- should be able to have an order line added
- should throw an error that it doesn't have line items
- should calculate return 0 dollars
- should have a default price type matching customer price type
- should be able to prefill an address
- should default to draft status
- should be able to instantiate

OrderStatus using a draft order status a super user
- should have a list of all available statuses

OrderStatus using a draft order status with no super user
- should not have all statuses available
- should have a list of next available status, when flow next is false, only including itself and the next higher status

OrderStatus
- should be able to find standard statuses

Product when using Product ID 1
- should be valid

OrderLine with valid order line
- should return correct discount levels (NOT IMPLEMENTED)
- should after changing qty return a different price (NOT IMPLEMENTED)
- should return a price of for x price type and y qty with a discountable price type
- should return a price of for x price type and y qty with a non-discountable price type
- should respond to get_price
- should be valid

Finished in 1.72758 seconds

40 examples, 0 failures, 2 not implemented

2 Comments, Comment or Ping

  1. meekish

    “…all you need to do is ‘rake spec’”

    In case you haven’t already, you should take a look at autotest. It supports Rails out of the box. I find it indespensible in the BDD process.

    XChain is looking pretty sweet.

  2. admin

    Yep I’ve had autotest running, not sure I’m a fan. I prefer the actual thought process of saying ‘right this should work’…

Reply to “The satisfaction of Rails”

About

Rowan is a Director of Technology for a large marketing services company, specialising in architecting, developing and putting web applications into production - in particular Ruby on Rails based apps. He lives in Toronto, Canada but speaks in a funny accent as he's originally from New Zealand. He's been working in the software and web business for over a decade. This blog covers Web Application development and deployment in the real world, dealing with topics from business fundamentals to Ruby on Rails, Merb, PHP, Flex, MySQL, Apache and more.

Read more ...

 

 

View Rowan Hick's profile on LinkedIn

 

Subscribe to my RSS feed