spree_multi_currency 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data.tar.gz.sig +3 -0
  2. data/.gitignore +5 -0
  3. data/Gemfile +11 -0
  4. data/LICENSE +0 -0
  5. data/README.markdown +196 -0
  6. data/Rakefile +28 -0
  7. data/Versionfile +9 -0
  8. data/app/controllers/spree/admin/currencies_controller.rb +11 -0
  9. data/app/controllers/spree/admin/currency_converters_controller.rb +4 -0
  10. data/app/controllers/spree/base_controller_decorator.rb +12 -0
  11. data/app/controllers/spree/currency_controller.rb +16 -0
  12. data/app/helpers/number_helper_decorator.rb +40 -0
  13. data/app/models/spree/adjustment_decorator.rb +4 -0
  14. data/app/models/spree/currency.rb +119 -0
  15. data/app/models/spree/currency_converter.rb +14 -0
  16. data/app/models/spree/line_item_decorator.rb +13 -0
  17. data/app/models/spree/order_decorator.rb +83 -0
  18. data/app/models/spree/variant_decorator.rb +22 -0
  19. data/app/overrides/add_currencies_admin_configurations_menu.rb +10 -0
  20. data/app/views/spree/admin/currencies/_form.html.erb +40 -0
  21. data/app/views/spree/admin/currencies/edit.html.erb +16 -0
  22. data/app/views/spree/admin/currencies/index.html.erb +44 -0
  23. data/app/views/spree/admin/currencies/new.html.erb +16 -0
  24. data/app/views/spree/admin/currency_converters/_form.html.erb +35 -0
  25. data/app/views/spree/admin/currency_converters/edit.html.erb +16 -0
  26. data/app/views/spree/admin/currency_converters/index.html.erb +42 -0
  27. data/app/views/spree/admin/currency_converters/new.html.erb +16 -0
  28. data/config/cucumber.yml +10 -0
  29. data/config/locales/currencies.yml +51 -0
  30. data/config/locales/en_multi_currency.yml +28 -0
  31. data/config/locales/ru_multi_currency.yml +26 -0
  32. data/config/routes.rb +8 -0
  33. data/db/migrate/20101109134351_create_currencies.rb +25 -0
  34. data/db/migrate/20101109134453_create_currency_converters.rb +15 -0
  35. data/db/sample/currencies.yml +1603 -0
  36. data/db/sample/currency_converters.yml +689 -0
  37. data/db/seeds.rb +2 -0
  38. data/features/products.feature +32 -0
  39. data/features/step_definitions/product.rb +124 -0
  40. data/features/step_definitions/ror_ringer.jpeg +0 -0
  41. data/features/support/env.rb +16 -0
  42. data/features/support/paths.rb +42 -0
  43. data/lib/generators/spree_multi_currency/install/install_generator.rb +29 -0
  44. data/lib/spree_multi_currency.rb +40 -0
  45. data/lib/spree_multi_currency/engine.rb +34 -0
  46. data/lib/tasks/spree_multi_currency.rake +99 -0
  47. data/script/rails +5 -0
  48. data/spec/changing_currency_spec.rb +18 -0
  49. data/spec/spec_helper.rb +17 -0
  50. data/spree_multi_currency.gemspec +32 -0
  51. metadata +226 -0
  52. metadata.gz.sig +1 -0
@@ -0,0 +1,14 @@
1
+ module Spree
2
+ class CurrencyConverter < ActiveRecord::Base
3
+ belongs_to :currency
4
+ default_scope :order => "spree_currency_converters.date_req ASC"
5
+
6
+ attr_accessible :currency_id, :nominal, :value, :date_req, :currency
7
+
8
+ class << self
9
+ def add(currency, date, value, nominal)
10
+ create({ :nominal => nominal, :value => value, :date_req => date, :currency => currency})
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ Spree::LineItem.class_eval do
2
+ extend Spree::MultiCurrency
3
+ multi_currency :price
4
+
5
+ def copy_price
6
+ self.price = variant.reade_attribute(:price) if variant && price.nil?
7
+ end
8
+
9
+ def raw_amount
10
+ read_attribute(:price) * self.quantity
11
+ end
12
+
13
+ end
@@ -0,0 +1,83 @@
1
+ Spree::Order.class_eval do
2
+ extend Spree::MultiCurrency
3
+ multi_currency :item_total, :total,
4
+ :rate_at_date => lambda{ |t| t.created_at },
5
+ :only_read => true
6
+
7
+
8
+ def update_totals
9
+ # update_adjustments
10
+ self.payment_total = payments.completed.map(&:amount).sum
11
+ self.item_total = line_items.map(&:raw_amount).sum
12
+ self.adjustment_total = adjustments.map(&:amount).sum
13
+ self.total = read_attribute(:item_total) + adjustment_total
14
+ end
15
+
16
+ def rate_hash
17
+ @rate_hash ||= available_shipping_methods(:front_end).collect do |ship_method|
18
+ next unless cost = ship_method.calculator.compute(self)
19
+ { :id => ship_method.id,
20
+ :shipping_method => ship_method,
21
+ :name => ship_method.name,
22
+ :cost => Spree::Currency.conversion_to_current(cost)
23
+ }
24
+ end.compact.sort_by{|r| r[:cost]}
25
+ end
26
+
27
+ def update!
28
+ update_totals
29
+ update_payment_state
30
+
31
+ # give each of the shipments a chance to update themselves
32
+ shipments.each { |shipment| shipment.update!(self) }#(&:update!)
33
+ update_shipment_state
34
+ update_adjustments
35
+ # update totals a second time in case updated adjustments have an effect on the total
36
+ update_totals
37
+ update_attributes_without_callbacks({
38
+ :payment_state => payment_state,
39
+ :shipment_state => shipment_state,
40
+ :item_total => read_attribute(:item_total),
41
+ :adjustment_total => adjustment_total,
42
+ :payment_total => payment_total,
43
+ :total => read_attribute(:total)
44
+ })
45
+
46
+ #ensure checkout payment always matches order total
47
+ if payment and payment.checkout? and payment.amount != total
48
+ payment.update_attributes_without_callbacks(:amount => total)
49
+ end
50
+
51
+ update_hooks.each { |hook| self.send hook }
52
+ end
53
+
54
+ def add_variant(variant, quantity = 1)
55
+ current_item = contains?(variant)
56
+ if current_item
57
+ current_item.quantity += quantity
58
+ current_item.save
59
+ else
60
+ current_item = Spree::LineItem.new(:quantity => quantity)
61
+ current_item.variant = variant
62
+ current_item.price = variant.read_attribute(:price)
63
+ self.line_items << current_item
64
+ end
65
+
66
+ # populate line_items attributes for additional_fields entries
67
+ # that have populate => [:line_item]
68
+ Spree::Variant.additional_fields.select { |f| !f[:populate].nil? && f[:populate].include?(:line_item) }.each do |field|
69
+ value = ''
70
+
71
+ if field[:only].nil? || field[:only].include?(:variant)
72
+ value = variant.send(field[:name].gsub(' ', '_').downcase)
73
+ elsif field[:only].include?(:product)
74
+ value = variant.product.send(field[:name].gsub(' ', '_').downcase)
75
+ end
76
+ current_item.update_attribute(field[:name].gsub(' ', '_').downcase, value)
77
+ end
78
+
79
+ self.reload
80
+ current_item
81
+ end
82
+
83
+ end
@@ -0,0 +1,22 @@
1
+ Spree::Variant.class_eval do
2
+ extend Spree::MultiCurrency
3
+ multi_currency :price, :cost_price
4
+ def price_in(currency)
5
+ # will use internal currency, parametr will ignored
6
+ currency = Spree::Currency.current
7
+ prices.select{ |price| price.currency == currency }.first || Spree::Price.new(:variant_id => self.id, :currency => currency, :amount => self.cost_price)
8
+ end
9
+ end
10
+
11
+ Spree::Money.class_eval do
12
+ def initialize(amount, options={})
13
+ @money = ::Money.parse([amount, (Spree::Currency.current.char_code)].join)
14
+ @options = {}
15
+ @options[:with_currency] = true if Spree::Config[:display_currency]
16
+ @options[:symbol_position] = Spree::Config[:currency_symbol_position].to_sym
17
+ @options[:no_cents] = true if Spree::Config[:hide_cents]
18
+ @options.merge!(options)
19
+ # Must be a symbol because the Money gem doesn't do the conversion
20
+ @options[:symbol_position] = @options[:symbol_position].to_sym
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ Deface::Override.new(:virtual_path => "spree/admin/shared/_configuration_menu",
2
+ :name => "currencies_admin_configurations_menu",
3
+ :insert_bottom => "ul[data-hook='admin_configurations_sidebar_menu']",
4
+ :disabled => false,
5
+ :text => "
6
+ <% if current_user.has_spree_role?(:admin) %>
7
+ <%= configurations_sidebar_menu_item t(:currency_settings), admin_currencies_path %>
8
+ <%= configurations_sidebar_menu_item t(:currency_converters_settings), admin_currency_converters_path %>
9
+ <% end %>
10
+ ")
@@ -0,0 +1,40 @@
1
+ <table>
2
+ <tr>
3
+ <td><%= t("currency_name") %>: </td>
4
+ <td>
5
+ <%= error_message_on :currency, :name %>
6
+ <%= f.text_field :name %>
7
+ </td>
8
+ </tr>
9
+ <tr>
10
+ <td><%= t("currency_num_code") %>: </td>
11
+ <td>
12
+ <%= error_message_on :currency, :num_code %>
13
+ <%= f.text_field :num_code %>
14
+ </td>
15
+ </tr>
16
+ <tr>
17
+ <td><%= t("currency_char_code") %>: </td>
18
+ <td>
19
+ <%= error_message_on :currency, :char_code %>
20
+ <%= f.text_field :char_code %>
21
+ </td>
22
+ </tr>
23
+
24
+ <tr>
25
+ <td><%= t("currency_basic") %>: </td>
26
+ <td>
27
+ <%= error_message_on :currency, :basic %>
28
+ <%= f.check_box :basic %>
29
+ </td>
30
+ </tr>
31
+ <tr>
32
+ <td><%= t("currency_locale") %>: </td>
33
+ <td>
34
+ <%= error_message_on :currency, :locale %>
35
+ <%= f.select :locale, I18n.available_locales.map{|x| [x,x] }, {}, { :multiple => true, :size => 10 } %>
36
+ </td>
37
+ </tr>
38
+
39
+ </table>
40
+
@@ -0,0 +1,16 @@
1
+ <% content_for :page_title do %>
2
+ <%= t(:editing_currency) %>
3
+ <% end %>
4
+
5
+ <% content_for :page_actions do %>
6
+ <li>
7
+ <%= button_link_to t("back_to_currencies"), collection_url, :icon => 'icon-arrow-left' %>
8
+ </li>
9
+ <% end %>
10
+
11
+ <%= form_for(@currency, :url => object_url, :html => { :method => :put }) do |f| %>
12
+ <fieldset class="no-border-top">
13
+ <%= render "form", :f => f %>
14
+ <%= render :partial => 'spree/admin/shared/edit_resource_links' %>
15
+ </fieldset>
16
+ <% end %>
@@ -0,0 +1,44 @@
1
+ <%= render(:partial => "/spree/admin/shared/configuration_menu") %>
2
+ <% content_for :page_title do %>
3
+ <%= t(:list_currency) %>
4
+ <% end %>
5
+
6
+ <% content_for :page_actions do %>
7
+ <li>
8
+ <%= button_link_to t("add_currency"), new_object_url, :icon => 'icon-plus' %>
9
+ </li>
10
+ <% end %>
11
+
12
+ <table class="index">
13
+ <colgroup>
14
+ <col style="width: 20%">
15
+ <col style="width: 20%">
16
+ <col style="width: 20%">
17
+ <col style="width: 20%">
18
+ <col style="width: 20%">
19
+ </colgroup>
20
+ <thead>
21
+ <tr>
22
+ <th><%= t("currency_name")%></th>
23
+ <th><%= t("currency_code")%></th>
24
+ <th><%= t("currency_locale")%></th>
25
+ <th><%= t("currency_basic")%></th>
26
+ </tr>
27
+ </thead>
28
+ <tbody>
29
+ <% @currencies.each do |currency|%>
30
+ <tr id="<%= dom_id currency %>">
31
+ <td width="350px"><%= currency.name %></td>
32
+ <td>
33
+ <%= currency.num_code %> - <%= currency.char_code %>
34
+ </td>
35
+ <td> <%= currency.locale(false) %></td>
36
+ <td> <%= currency.basic %></td>
37
+ <td class='actions'>
38
+ <%= link_to_edit currency, :no_text => true %>
39
+ <%= link_to_delete currency, :no_text => true %>
40
+ </td>
41
+ </tr>
42
+ <% end %>
43
+ </tbody>
44
+ </table>
@@ -0,0 +1,16 @@
1
+ <% content_for :page_title do %>
2
+ <%= t(:new_currency) %>
3
+ <% end %>
4
+
5
+ <% content_for :page_actions do %>
6
+ <li>
7
+ <%= button_link_to t("back_to_currencies"), collection_url, :icon => 'icon-arrow-left' %>
8
+ </li>
9
+ <% end %>
10
+
11
+ <%= form_for(:currency, :url => collection_url) do |f| %>
12
+ <fieldset class="no-border-top">
13
+ <%= render :partial => "form", :locals => { :f => f } %>
14
+ <%= render :partial => 'spree/admin/shared/new_resource_links' %>
15
+ </fieldset>
16
+ <% end %>
@@ -0,0 +1,35 @@
1
+ <table>
2
+ <tr>
3
+ <td><%= t("currency_converter_currency") %>: </td>
4
+ <td>
5
+ <%= error_message_on :currency_converter, :currency_id %>
6
+ <%= f.select :currency_id, Spree::Currency.all.map{|x| [x.name, x.id]} %>
7
+ </td>
8
+ </tr>
9
+
10
+ <tr>
11
+ <td><%= t("currency_converter_date_req") %>: </td>
12
+ <td>
13
+ <%= error_message_on :currency_converter, :date_req %>
14
+ <%= f.text_field :date_req, :class => 'datepicker' %>
15
+ </td>
16
+ </tr>
17
+
18
+ <tr>
19
+ <td><%= t("currency_converter_nominal") %>: </td>
20
+ <td>
21
+ <%= error_message_on :currency_converter, :nominal %>
22
+ <%= f.text_field :nominal %>
23
+ </td>
24
+ </tr>
25
+
26
+ <tr>
27
+ <td><%= t("currency_converter_value") %>: </td>
28
+ <td>
29
+ <%= error_message_on :currency_converter, :value %>
30
+ <%= f.text_field :value %>
31
+ </td>
32
+ </tr>
33
+
34
+ </table>
35
+
@@ -0,0 +1,16 @@
1
+ <% content_for :page_title do %>
2
+ <%= t(:editing_currency_converter) %>
3
+ <% end %>
4
+
5
+ <% content_for :page_actions do %>
6
+ <li>
7
+ <%= button_link_to t("back_to_currency_converters"), collection_url, :icon => 'icon-arrow-left' %>
8
+ </li>
9
+ <% end %>
10
+
11
+ <%= form_for(:currency_converter, :url => object_url, :html => { :method => :put }) do |f| %>
12
+ <fieldset class="no-border-top">
13
+ <%= render :partial => "form", :locals => { :f => f } %>
14
+ <%= render :partial => 'spree/admin/shared/edit_resource_links' %>
15
+ </fieldset>
16
+ <% end %>
@@ -0,0 +1,42 @@
1
+ <%= render(:partial => "/spree/admin/shared/configuration_menu") %>
2
+ <% content_for :page_title do %>
3
+ <%= t(:currency_converter) %>
4
+ <% end %>
5
+
6
+ <% content_for :page_actions do %>
7
+ <li>
8
+ <%= button_link_to t("add_currency_converter"), new_object_url, :icon => 'icon-plus' %>
9
+ </li>
10
+ <% end %>
11
+
12
+ <table class="index">
13
+ <colgroup>
14
+ <col style="width: 20%">
15
+ <col style="width: 20%">
16
+ <col style="width: 20%">
17
+ <col style="width: 20%">
18
+ <col style="width: 20%">
19
+ </colgroup>
20
+ <thead>
21
+ <tr>
22
+ <th><%= t("currency_converter_date_req") %></th>
23
+ <th><%= t("currency_converter_currency") %></th>
24
+ <th><%= t("currency_converter_nominal") %></th>
25
+ <th><%= t("currency_converter_value") %></th>
26
+ </tr>
27
+ </thead>
28
+ <tbody>
29
+ <% @currency_converters.each do |currency_converter|%>
30
+ <tr id="<%= dom_id currency_converter %>">
31
+ <td><%= currency_converter.date_req %></td>
32
+ <td width="350px"><%= currency_converter.currency.try(:name) %></td>
33
+ <td><%= currency_converter.nominal %></td>
34
+ <td><%= currency_converter.value %></td>
35
+ <td>
36
+ <%= link_to_edit currency_converter %> &nbsp;
37
+ <%= link_to_delete currency_converter %> &nbsp;
38
+ </td>
39
+ </tr>
40
+ <% end %>
41
+ </tbody>
42
+ </table>
@@ -0,0 +1,16 @@
1
+ <% content_for :page_title do %>
2
+ <%= t(:new_currency_converter) %>
3
+ <% end %>
4
+
5
+ <% content_for :page_actions do %>
6
+ <li>
7
+ <%= button_link_to t("back_to_currency_converters"), collection_url, :icon => 'icon-arrow-left' %>
8
+ </li>
9
+ <% end %>
10
+
11
+ <%= form_for(:currency_converter, :url => collection_url) do |f| %>
12
+ <fieldset class="no-border-top">
13
+ <%= render :partial => "form", :locals => { :f => f } %>
14
+ <%= render :partial => 'spree/admin/shared/new_resource_links' %>
15
+ </fieldset>
16
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <%
2
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
+ rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
+ std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} --strict --tags ~@wip"
5
+ ci_opts = "--format progress --strict"
6
+ %>
7
+ default: <%= std_opts %> features
8
+ wip: --tags @wip:3 --wip features
9
+ ci: <%= ci_opts %> features CI=true
10
+ rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
@@ -0,0 +1,51 @@
1
+ currency_USD: &usd
2
+ number:
3
+ currency:
4
+ format:
5
+ format: "%u%n"
6
+ unit: "$"
7
+ separator: "."
8
+ delimiter: ","
9
+ precision: 2
10
+ significant: false
11
+ strip_insignificant_zeros: false
12
+
13
+ currency_RUB:
14
+ number:
15
+ currency:
16
+ format:
17
+ format: "%n %u"
18
+ unit: "руб."
19
+ separator: "."
20
+ delimiter: " "
21
+ precision: 2
22
+
23
+ currency_EUR:
24
+ <<: *usd
25
+ number:
26
+ currency:
27
+ format:
28
+ format: "%u%n"
29
+ unit: "€"
30
+ separator: ","
31
+ delimiter: "."
32
+
33
+ currency_DKK:
34
+ number:
35
+ currency:
36
+ format:
37
+ format: "%n %u"
38
+ unit: "kr."
39
+ separator: ","
40
+ delimiter: "."
41
+ precision: 2
42
+
43
+ currency_GBP:
44
+ number:
45
+ currency:
46
+ format:
47
+ format: "%u%n"
48
+ unit: "£"
49
+ separator: "."
50
+ delimiter: ","
51
+ precision: 2