Sterling Rose Design Blog

Calculating Line Item Extensions

84 Comments
Tags: Javascript Rails Prototype AJAX
In my project, I have orders, and each order can have an unlimited number of line_items. Line_items are created by the user clicking on a button, which appends (via RJS) a new row to the line_items tabled form. So far, so good.

But I needed the extended price (quantity * price_per) of each line_item to be calculated every time the user tabbed out or clicked away from the price_per field. Further, I needed the subtotal, tax, total, and balance fields to be automatically re-calculated.

I messed around with it for several hours, trying Javascript, Prototype, and even jQuery, before I finally settled on a Prototype approach that worked. The real struggle was that using Rails 2.3’s nested forms functionality meant that each line_item would have an index key embedded in the middle of the text field’s name and id, and I could not come up with a good way to extract it, to pass it to the Javascript function.

Luckily, the numbering appears to be a 0-based index, so I cheated and used an incrementer.

I know it’s not a perfect solution (it’s obtrusive, it’s probably much more verbose than it needs to be) but it functions.

So, on to the code. Obviously, I’ve snipped out a lot of stuff that doesn’t have anything to do with this example.

/controllers/orders_controller.rb

def new
  @order = Order.new
  @order.line_items.build
  @order.zero_set_amounts
  @colors = Color.unremoved
end

def edit
  @order = Order.new
  @colors = Color.unremoved
end

/models/order.rb

def zero_set_amounts
  self.subtotal = 0
  self.tax = 0
  self.shipping = 0
  self.artwork = 0
  self.setup = 0
  self.printing_charge = 0
  self.misc_charge = 0
  self.total = 0
  self.balance = 0
  self.reorder ||= false
end

/views/layouts/application.html.erb

<head>
  <%= javascript_include_tag :defaults, 'main' %>
</head>

/views/orders/new.html.erb and /views/orders/edit.html.erb

<% form_for(@order) do |f| %>
  <%= render :partial => "form", :locals => {:f => f} %>
<% end %>

/views/orders/_form.html.erb

<div id="order_line_items">
  <%= render :partial => 'line_items', :locals => {:f => f, :order => @order} %>
  <div id="order_summary_fields">
    <div class="left"><%= f.label :subtotal %></div>
    <div class="right"><%= text_field_tag :subtotal, 0, :size => 10, 
      :disabled => true %></div>
    <div class="left"><%= f.label :artwork %></div>
    <div class="right"><%= f.text_field :artwork, :size => 10, :onblur => 
      'recalculateTotals();' %></div>
    <div class="left"><%= f.label :setup %></div>
    <div class="right"><%= f.text_field :setup, :size => 10, :onblur => 
      'recalculateTotals();' %></div>
    <div class="left"><%= f.label :printing_charge, "Printing" %></div>
    <div class="right"><%= f.text_field :printing_charge, :size => 10, :onblur => 
      'recalculateTotals();' %></div>
    <div class="left"><%= f.label :misc_charge, "Miscellaneous" %></div>
    <div class="right"><%= f.text_field :misc_charge, :size => 10, :onblur => 
      'recalculateTotals();' %></div>
    <div class="left"><%= f.label :shipping %></div>
    <div class="right"><%= f.text_field :shipping, :size => 10, :onblur => 
      'recalculateTotals();' %></div>
    <div class="left"><%= f.label :tax %></div>
    <div class="right"><%= text_field_tag :tax, 0, :size => 10, :disabled => true %></div>
    <div class="left"><strong><%= f.label :total %></strong></div>
    <div class="right"><%= text_field_tag :total, 0, :size => 10, 
      :disabled => true %></div>
    <div class="left"><%= f.label :balance %></div>
    <div class="right"><%= text_field_tag :balance, 0, :size => 10, 
      :disabled => true %></div>
    <%= render :partial => "shared/create_or_update", :locals => {:f => f} %>
    <%= f.hidden_field :subtotal %>
    <%= f.hidden_field :tax %>
    <%= f.hidden_field :total %>
    <%= f.hidden_field :balance%>
    <%= f.hidden_field :reorder %>
  </div>  
</div>

/views/order/_line_items.html.erb

<%= button_to_remote 'Add a New Line Item', {:url => new_line_item_path, :method => :get} %>
...
<% i = 0 %>
<% f.fields_for :line_items do |line_items_forms| %>
  <tr>
    <td><%= line_items_forms.text_field :quantity, :size => 5 %></td>
    <td><%= line_items_forms.text_field :description, :size => 30 %></td>
    <td><%= line_items_forms.select :color_id, @colors.map {|c| [c.name, c.id]} %></td>
    <td><%= line_items_forms.text_field :price_per, :size => 10, :onblur => 
      order.new_record? ? 'updateExtendedPrice("order_line_items_attributes_0_quantity", 
      this.id, "order_line_items_attributes_0_price_extended");' : 
      "updateExtendedPrice('order_line_items_attributes_#{i}_quantity', this.id, 
      'order_line_items_attributes_#{i}_price_extended');" %></td>
    <td><%= line_items_forms.text_field :price_extended, :size => 10, :class => 
      'fluffy_bunny' %></td>
   <% i += 1 %>
  </tr>
<% end %>

Yeah, I called my class “fluffy_bunny.” It’s not a class name I was likely to use anywhere else, and fluffy bunnies are cute. :)
/controllers/line_items_controller.rb

def new    
  begin
    @order = Order.find(params[:order_id])
    @line_item = @order.line_items.build
  rescue ActiveRecord::RecordNotFound
    @line_item = LineItem.new
  ensure
    @item_index = @order.nil? ? Time.now.to_i : (@order.line_items.length - 1)
  end

  respond_to do |format|
    format.html
    format.js do        
      @colors = Color.unremoved.collect {|c| [c.name, c.id]}
      @line_id = "order_line_items_attributes_#{@item_index}"
      @line_name = "order[line_items_attributes][#{@item_index}]"
    end
  end
end

/views/line_items/new.js.erb

$('line_item_table').insert(<%=js render(:partial => "new_line_item") %>, 'bottom');

/views/line_items/_new_line_item.html.erb

<tr> 
  <td><%= text_field_tag "#{@line_id}_quantity", '', :name => "#{@line_name}[quantity]", 
    :size => 5 -%></td> 
  <td><%= text_field_tag "#{@line_id}_description", '', :name => 
    "#{@line_name}[description]", :size => 30 -%></td> 
  <td><%= select_tag "#{@line_id}_color_id", options_for_select(@colors), :name => 
    "#{@line_name}[color_id]" -%></td>
  <td><%= text_field_tag "#{@line_id}_price_per", '', :name => 
    "#{@line_name}[price_per]", :size => 10, :onblur => 
    "updateExtendedPrice('order_line_items_attributes_#{@item_index}_quantity', this.id, 
    'order_line_items_attributes_#{@item_index}_price_extended');" -%></td>
  <td><%= text_field_tag "#{@line_id}_price_extended", '', :name => 
    "#{@line_name}[price_extended]", :size => 10, :class => 'fluffy_bunny' -%></td>
</tr>

/public/javascripts/main.js

function updateExtendedPrice(x,y,z) {
  $(z).value=parseFloat($(x).value) * parseFloat($(y).value);
  updateSubtotal();
  recalculateTotals();
}

function updateSubtotal() {
  var subtotal=0;
  var li;
  var line_item_extensions = $$('.fluffy_bunny');
  line_item_extensions.each(function(li) {subtotal += parseFloat(li.value);})
  $('order_subtotal').value=subtotal;
  $('subtotal').value=subtotal;
}

function updateTax() {
  /* Tax rate is 7% */
  var tax = ((parseFloat($('order_subtotal').value) + 
    parseFloat($('order_artwork').value) + parseFloat($('order_setup').value) + 
    parseFloat($('order_shipping').value) + parseFloat($('order_printing_charge').value) 
    + parseFloat($('order_misc_charge').value)) * 0.07).toFixed(2);
  $('order_tax').value=tax;
  $('tax').value=tax;
}

function updateTotal() {
  var total = (parseFloat($('order_subtotal').value) + 
  parseFloat($('order_artwork').value) + parseFloat($('order_setup').value) + 
  parseFloat($('order_tax').value) + parseFloat($('order_shipping').value) + 
  parseFloat($('order_printing_charge').value) + 
    parseFloat($('order_misc_charge').value)).toFixed(2);
  $('order_total').value=total;
  $('total').value=total;
}

function updateBalance() {
  balance = $('order_total').value;
  $('order_balance').value = balance;
  $('balance').value = balance;
}

function recalculateTotals() {
  updateTax();
  updateTotal();
  updateBalance();
}
Comments

It`s easy to make a mistake here!

Yeah) but I guess here it is everything carefully written)

Thank you and looking for more posts. I am really satisfied with this posting that you have given us. This is really a stupendous work done by you.

Personally I like your code – it’s quite accurate!

Your article very interesting, I have introduced a lot of friends look at this article, the content of the articles there will be a lot of attractive people to appreciate, I have to thank you such an article.

Thanks and looking for other messages.



this explanation helped more than any other one essays


I am sure that the idea to write my paper in this key will make it more interesing

It is not easy to find a good term paper for my college! I hope you will help me


These tiny little icons are ubiquitous in web applications. They’re cute and plentiful, and I use them

I am sure that these scripts will help me a lot

I had this problem! Thanks for the script here

SAOMTBHXRP north face uk CXMOGUCLVZ http://northfaceuk.webeden.co.uk/


QSNWWRUHTB ugg boots sale NMRSJPJYVU http://www.littlefitness.com


zFuuXvyXfkFy http://www.andrewsambell.com yHgnXmlYvfIh moncler outlet pQmzUswVbuPp


pByrWsaGx ugg outlet tIotDvdKv http://www.aikidoatbushindojo.com


Such a design stuff, I am only good at dissertation titles writing with its tips on how to write essay.

TXEFNZDHADQAF cheap uggs uk VYYEEHYHZSVIW http://www.djhardyhard.com


xNdmJwtuEuoB north face uk jackets vUoqUzgrAxkX http://www.frcointernational.org fDvoTgnyMbxO


fFufCgvlDaz uggs boots bMccQfcpDmj http://www.littlefitness.com zFtoNtqoHxj


this article explains more thing than any other one

tEkmUrfNw uggs on sale uk kDbkVcqJr http://www.oneribpublications.com/


tEufMhxRn ugg boots iFdsSsdVy http://www.wnyfunrun.org


iYqiSdjbBo cheap uggs for sale kQkjTggwWl http://www.nnmortgage.net fYakSqeiRt


It is very rare these days to find blogs that provide information someone is looking for. I am glad to see that your blog share valued information that can help to many readers. Thanks and keep writing!


nKnkIgiVt uggs slippers on sale kNmeSrgZh http://aussjoacres.com


Hello. And Bye.

uDnvZmzzKp ugg yPrbCmyiFm http://www.soulsituation.com qCheXysdIn


This is a nice web site.  Good fresh interface and nice informative articles. I will be coming back soon, thanks for the great article.


You have completed an amazing job writing the testimony ; I enjoyed what you’ve made a lot

Over the years, I have bookmarked a lot of sites that I find more useful than others in doing the design work

iCcqBpyyWr ugg boot uk sale zOpqIjpyVr http://www.franklinpba.com


fVnmBmofHg ugg boots on sale for women vBfyQdkuId http://mordishe56.xanga.com/757644993/ugg-boots-on-sale-for-women—blank—a-genuine-attack-this-year/


sGifJmkAz uggs on sale hZatEhyLi http://www.hamod.net


tJpzTtnkLp http://uggsonsale27.beep.com/uggbootsclearance.htm xJedDntnOl ugg boots on sale


Such decent article, you’ve made a great work creating it

wKmeVdmpRi ugg boots cheap sCnpThigIx http://ugguk1216.sosblogs.com/ugg-uk-b1/ugg-boots-on-sale-b1-p2.htm


yWatSesTq ugg store bFnkZvwHz http://uggstoreuk.webeden.co.uk

I have been searching out some of your stories and i can state that this one pretty nicely stuff. I have enjoyed your post, which nicely written on interesting story. Thanks for sharing such a great stuff with us. I hope more to come.


Thank you for sharing such a good post!

iL5wQ7mZ6 uggs for sale online rN9jR0tS0 http://www.allmortgagegroup.com


rTekDwzYb ugg boots uk sale xGhaXifVy http://uggbootsuksale.webeden.co.uk

tB canada goose jackets lO http://discountuggs5989.webnode.it/canada-goose-parka/


wA canada goose eE http://www.biblepr.com/canada-goose-253257.html


I even told my friends to take a look at your blog and in fact your blog is already bookmarked on my computer. Hope to see more of this. Great..

xRc replica louis vuitton handbags eXl http://uggbootsuk107.blogcindario.com/2012/01/00008-louis-vuitton-designer-handbags-on-line.html


jR3 cheap ugg boots bX3 http://SunommyfervmoilleLiana.newsvine.com/_news/2012/01/07/10022879-comfort-and-ease-through-popular-all-the-ugg-sale-and-trendy-cheap-ugg-boots


The accuracy of the recipe cost is paramount to ensuring the theoretical is accurate (see our article “Obtaining Accurate Recipe Costs”). In order to gain a theoretical cost extend the cost per plate by the quantity sold. The total of all of the line item extensions is the cost in dollars.


Computer Store Canada


SEEVKBZFBU sale on uggs ONSBRWVYVW http://www.monarchestates.com


The Machine, the Museum of Modern Art’s 1968 exhibit, featured hundreds of artist dealing with the subject of mechanics and technology. Says Cool Hunting of the exhibit’s published "From historical photographic studies of motion to the groundbreaking
Categories

we are waiting patiently for orders, online!Once you handled perfectly engaging yourself in a term paper writing service, be totally prepared for answering a quite few questions that they will likely to inquire you through a comprehensive questionnaire, which enables a term paper service to be aware of all the necessary information of your potential professors’ required.

very informative post, thanks for sharing it with us

anuncios eroticos
This is a nice web site. Good fresh interface and nice informative articles. I will be coming back soon, thanks for the great articleformacion empresas


That is well known that A+ grades are very complicated to have. If you order custom essays writing composed by professionals, you should definitely reach an academic paramount.

The team announced Thursday that Hartford tore his left pectoral muscle in the first quarter of Wednesday night’s game at Indiana.

I’m really appreciate by making my site one of your reference. It’s a good choice or initiative. By keep visiting this site you can have more information about the things that you need. Keep posting

Thanks for the nice blog. It was very useful for me. Keep sharing such ideas in the future as well.Thanks for sharing the such information with us.

I couldn’t leave the website without commenting on this it is a great idea and i checked some other posts on this blog they are great.keep up the good work

I recently came across your blog and have been reading along. I thought I would leave my first comment. I don’t know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.

Very interesting article you have got here. I love reading this kind of stuff. This is truly a great read for me. I hope to see more articles from you

Very interesting article you have got here. I love reading this kind of stuff. This is truly a great read for me. I hope to see more articles from you

Thanks for taking the time to discuss this, I feel strongly about information and love learning more on this. If possible, as you gain expertise, It is extremely helpful for me. would you mind updating your blog with more information

very informative post, thanks for sharing it with us

I came to this page by searching Yahoo. I have found it quite interesting. Thank you for providing this. I will have to visit here again!

Good post. Thanks for sharing this useful information with us.

It is a really great staff for getting knowledge… I am very surprised that I read your great informative and helpful blog… Thanks for a pleasureful blog…

website it is best for me .I thankful to you to you for making this website .I am exceed with all the content of your website and i really like your website Thank you for your information

I really enjoyed this site. Safety wіll аlѕο mean choosing furniture pieces thаt hаνе rounded corners wіth nο sharp objects attached. Whеn looking аt bedroom furniture, look аt thе knobs аnd pulls аnd check thе edges οf thе surface. Your newer posts are simply wonderful compared to your posts in the past. Keep up the good work!

i has created this privacy statement in order to demonstrate our website commitment to privacy. The following discloses the information gathering and dissemination practices for this

Thanks for sharing this, you run a wonderful blog filled with good posts. I have bookmarked it for later use.

FQZOZBFGQE louis vuitton outlet OQKPYBVFXF http://www.redalertmerch.com/member/249795/


KjGF gucci handbags YyQF http://www.tricycle.ie/v2/index.php/member/22771


GaXQ ghd sale JvKY http://mym8.eu/hermesbirkin12/blog/84438/


Good post. Visitors around the world will find it very useful! Thanks.

TEL louis vuitton outlet stores BKL http://louivuittonbags16.webnode.it/louis-vuitton-outlet-expensive/


dvP chanel handbags outlet mmD http://hermtyesbiyui26.webs.com/chanelhandbagsprefer.htm


shoe sale for women in the 2012 spring. There are more new christian louboutin 2012 spring high heel shoes discount on sale with free shipping for everyone

The best university students are able to compose the college essays of great quality. But, very often they are pressured for time for that things. Then they should order religion essay, which supposes to be really bright decision for hard working students.

very grateful for the information material on programming literature is very expensive and mostly translations HELP. thanks for great work

I really enjoyed this site. Safety wіll аlѕο mean choosing furniture pieces thаt hаνе rounded corners wіth nο sharp objects attached. Whеn looking аt bedroom furniture, look аt thе knobs аnd pulls аnd check thе edges οf thе surface. Your newer posts are simply wonderful compared to your posts in the past. Keep up the good work!

A healthy diet is not about strict nutrition philosophies, staying extremely thin, or depriving yourself of foods you love. Rather it is to get that good to have more energy and you keep healthy as possible.

WVUZVLOCQX ugg boots on sale GDJJAUNUKC http://filamentgroup.com/member/29310/


RLLNSAYWXW ugg boots outlet LOXTNXNTVL http://www.metanomics.net/member/63930/


i really enjoyed this site. Safety wіll аlѕο mean choosing furniture pieces thаt hаνе rounded corners wіth nο sharp objects attached. Whеn looking аt bedroom furniture, look аt thе knobs аnd pulls аnd check thе edges οf thе surface. Your newer posts are simply wonderful compared to your posts in the past. Keep up the good work!


Leave a Comment











Copyright 2007-2012, Sterling Rose Design. All rights reserved.