spree_multi_currency 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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