multi_currencies 1.0.0 → 1.0.2

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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in spree-multi-currency.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,77 @@
1
+ = Multi Currency
2
+
3
+ Support different currency and recalculate price from one to another
4
+ ===========================================
5
+ Installation
6
+ ---------
7
+ Add to Gemfile
8
+ gem "multi_currencies", :git => "git://github.com/pronix/spree-multi-currency.git"
9
+
10
+ Run
11
+ ---
12
+ rake multi_currencies:install:migrations
13
+ rake db:migrate
14
+
15
+ Load currencies:
16
+ ---------------
17
+ rake multi_currencies:currency:iso4217 # Load currency ISO4217 http://en.wikipedia.org/wiki/ISO_4217
18
+ rake multi_currencies:currency:okv # Общероссийский классификатор валют...
19
+
20
+ Load rates:
21
+ ----------
22
+ rake multi_currencies:rates:cbr # Курс Сбербанка РФ http://www.cbr.ru
23
+ rake "multi_currencies:rates:ecb[load_currencies]" # Rates from European Central Bank
24
+ rake "multi_currencies:rates:google[currency,load_currencies]" # Rates from Google
25
+
26
+
27
+ Settings
28
+ ---------
29
+ In admin block, configuration menu add two tables currency and currency conversion rate
30
+ In reference currency enters the list of currencies, indicate if one of the major currencies (in the currency keeps all prices). Each currency assign corresponding locale.
31
+ In Exchange Rates, provides information on the price of the currency on a specified date to the basic currency(from russian central bank).
32
+ In the exchange rates set date, currency, and face value of the currency in the base currency.
33
+ To fill in the exchange rate, you can use task for download exchange rates from the site of the Central Bank (http://www.cbr.ru):
34
+ rake multi_currencies:rates:cbr, as in this problem, loading the list of currencies.
35
+
36
+ В справочнике Валюты заносим список валют, указываем одну из валют основной (в этой валюте хранятся все цены). Каждой валюте назначаем соответствующую локаль.
37
+ В справчнике Курсы валют, содержиться информация о цене валюты на определенную дату к основной валюте.
38
+ В курсе валют указываеться дата, валюта, номинал и стоимость валюты в основной валюте.
39
+ Для заполнения курса валют, можно воспользоватьбся задачей загрузки курса валют с сайта ЦБ(http://www.cbr.ru):
40
+ rake multi_currencies:rates:cbr, так же в этой задаче идет загрузка списка валют.
41
+
42
+ Смена валюты
43
+ -------------
44
+ По умолчанию валюта выбирается от текущей локали сайта.
45
+ Так же можно сменить локаль по адресу http://[domain]/currency/[isocode], <%= link_to "eur", currency_path(:eur) %>
46
+
47
+ isocode: eur, usd, rub (цифровой код прописанные в справочнике валюты)
48
+ После смены валюты через url перестает работать смена валюты на основание текущей локали.
49
+
50
+ Формат вывода валюты
51
+ --------------------
52
+ Формат для валюты прописан в локализации, для каждой валюты нужно описать свою локализацию (прописаны eur, usd, rub):
53
+ Пример для usd, eur
54
+ ---
55
+ currency_USD: &usd
56
+ number:
57
+ currency:
58
+ format:
59
+ format: "%u%n"
60
+ unit: "$"
61
+ separator: "."
62
+ delimiter: ","
63
+ precision: 2
64
+ significant: false
65
+ strip_insignificant_zeros: false
66
+
67
+ currency_EUR:
68
+ <<: *usd
69
+ number:
70
+ currency:
71
+ format:
72
+ format: "%u%n"
73
+ unit: "€"
74
+
75
+
76
+
77
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,14 @@
1
+ class CurrencyController < Spree::BaseController
2
+
3
+ def set
4
+ if @currency = Currency.find_by_char_code(params[:id].to_s.upcase)
5
+ session[:currency_id] = params[:id].to_s.upcase.to_sym
6
+ Currency.current!(@currency)
7
+ flash.notice = t(:currency_changed)
8
+ else
9
+ flash[:error] = t(:currency_not_found)
10
+ end
11
+
12
+ redirect_back_or_default(root_path)
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ Spree::BaseController.class_eval do
2
+ before_filter :set_currency
3
+
4
+ private
5
+
6
+ def set_currency
7
+ if session[:currency_id].present? && (@currency = Currency.find_by_char_code(session[:currency_id]))
8
+ Currency.current!(@currency)
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,9 @@
1
+ LineItem.class_eval do
2
+ extend MultiCurrency
3
+ multi_currency :price
4
+
5
+ def raw_amount
6
+ read_attribute(:price) * self.quantity
7
+ end
8
+
9
+ end
@@ -0,0 +1,45 @@
1
+ Order.class_eval do
2
+ extend 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
+
17
+ def update!
18
+ update_totals
19
+ update_payment_state
20
+
21
+ # give each of the shipments a chance to update themselves
22
+ shipments.each { |shipment| shipment.update!(self) }#(&:update!)
23
+ update_shipment_state
24
+ update_adjustments
25
+ # update totals a second time in case updated adjustments have an effect on the total
26
+ update_totals
27
+ update_attributes_without_callbacks({
28
+ :payment_state => payment_state,
29
+ :shipment_state => shipment_state,
30
+ :item_total => read_attribute(:item_total),
31
+ :adjustment_total => adjustment_total,
32
+ :payment_total => payment_total,
33
+ :total => read_attribute(:total)
34
+ })
35
+
36
+ #ensure checkout payment always matches order total
37
+ if payment and payment.checkout? and payment.amount != total
38
+ payment.update_attributes_without_callbacks(:amount => total)
39
+ end
40
+
41
+ update_hooks.each { |hook| self.send hook }
42
+ end
43
+
44
+
45
+ end
@@ -0,0 +1,4 @@
1
+ Variant.class_eval do
2
+ extend MultiCurrency
3
+ multi_currency :price
4
+ end
@@ -0,0 +1,41 @@
1
+ module ActionView
2
+ module Helpers
3
+ module NumberHelper
4
+
5
+ def number_to_currency(number, options = {})
6
+ return nil if number.nil?
7
+
8
+ options.symbolize_keys!
9
+ options[:locale] = "currency_#{Currency.current.char_code}"
10
+ defaults = I18n.translate('number.format', :locale => options[:locale], :default => {})
11
+ currency = I18n.translate('number.currency.format', :locale => options[:locale], :default => {})
12
+ defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency)
13
+ defaults[:negative_format] = "-" + options[:format] if options[:format]
14
+ options = defaults.merge!(options)
15
+
16
+ unit = options.delete(:unit)
17
+ format = options.delete(:format)
18
+
19
+ if number.to_f < 0
20
+ format = options.delete(:negative_format)
21
+ number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '')
22
+ end
23
+
24
+ begin
25
+ value = number_with_precision(number, options.merge(:raise => true))
26
+ format.gsub(/%n/, value).gsub(/%u/, unit).html_safe
27
+ rescue InvalidNumberError => e
28
+ if options[:raise]
29
+ raise
30
+ else
31
+ formatted_number = format.gsub(/%n/, e.number).gsub(/%u/, unit)
32
+ e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+
39
+ end
40
+ end
41
+ end
@@ -1,43 +1,96 @@
1
+ require "money"
1
2
  class Currency < ActiveRecord::Base
2
- has_many :currency_converters
3
+
4
+ has_many :currency_converters do
5
+ def get_rate(date)
6
+ last(:conditions => ["date_req <= ?", date])
7
+ end
8
+ end
9
+
10
+ default_scope :order => "currencies.locale"
11
+ scope :locale, lambda{|str| where("locale like ?", "%#{str}%")}
12
+ after_save :reset_basic_currency
13
+
14
+ def basic!
15
+ self.class.update_all(:basic => false) && update_attribute(:basic, true)
16
+ end
17
+
18
+ def locale=(locales)
19
+ write_attribute(:locale, [locales].flatten.compact.join(','))
20
+ end
21
+
22
+ def locale(need_split = true)
23
+ need_split ? read_attribute(:locale).to_s.split(',') : read_attribute(:locale).to_s
24
+ end
25
+
26
+ # Сбрасываем для всех валют флаг "основная", кроме текущей если она установлена как основная
27
+ #
28
+ def reset_basic_currency
29
+ self.class.where("id != ?", self.id).update_all(:basic => false) if self.basic?
30
+ end
31
+
3
32
  class << self
4
- # Текущая валюта определенная по текущей локали
5
- def current(_locale=I18n.locale)
6
- find_by_locale(_locale.to_s)
33
+
34
+ # Текущая валюта
35
+ #
36
+ def current(current_locale = I18n.locale )
37
+ @current ||= locale(current_locale).first
38
+ @current
39
+ end
40
+
41
+ def current!(current_locale = nil )
42
+ @current = current_locale.is_a?(Currency) ? current_locale : locale(current_locale||I18n.locale).first
43
+ end
44
+
45
+ def load_rate(options= {})
46
+ current(options[:locale] || I18n.locale)
47
+ basic
48
+
49
+ if @rate = @current.currency_converters.get_rate(options[:date] || Time.now)
50
+ add_rate(@basic.char_code, @current.char_code, @rate.nominal/@rate.value.to_f)
51
+ add_rate(@current.char_code, @basic.char_code, @rate.value.to_f)
52
+ end
53
+
54
+ end
55
+
56
+ def convert(value, from, to)
57
+ ( Money.new(value.to_f * 10000, from).exchange_to(to).to_f / 100).round(2)
7
58
  end
8
59
 
9
60
  # Конвертируем сумму к валюте текущей локале
10
61
  # Если валюта или локаль не найдена то возвращается та же сумма
11
- #
12
- def conversion_to_current(price, options = { })
13
- _locale = options[:locale] || I18n.locale
14
- _date = options[:date] || Time.now
15
- return price if current(_locale).nil? || current(_locale).basic?
16
- current_currency = current(_locale).currency_converters.last(:conditions => ["date_req <= ?", _date])
17
- return price if current_currency.blank?
18
- (price / current_currency.value.to_f) * current_currency.nominal.to_i
62
+ # Money.new(value.to_f, "Основаня").exchange_to("К Текущей").to_f
63
+ #Currency.conversion_to_current(100, :locale => "ru")
64
+ def conversion_to_current(value, options = { })
65
+ load_rate(options)
66
+ convert(value, @basic.char_code, @current.char_code)
19
67
  end
20
68
 
21
69
  # Конвертируем значение из валюты текущей локали к основной валюте
22
70
  # в параметрах можно указать локаль из которой можно делать конвертацияю :locale
23
71
  # и дату курса :date, курс берется последний найденный до указанной даты
24
- #
72
+ #Currency.conversion_from_current(100, :locale => "ru")
25
73
  def conversion_from_current(value, options={})
26
- _locale = options[:locale] || I18n.locale
27
- _date = options[:date] || Time.now
28
- return value if current(_locale).nil? || current(_locale).basic?
29
- current_currency = current(_locale).currency_converters.last(:conditions => ["date_req <= ?", _date])
30
- return value if current_currency.blank?
31
- return (value/current_currency.nominal.to_f)*current_currency.value
74
+ load_rate(options)
75
+ convert(value, @current.char_code, @basic.char_code)
32
76
  end
33
77
 
78
+
34
79
  # Основная валюта
35
80
  def basic
36
- first(:conditions => { :basic => true })
37
- end
81
+ @basic ||= first(:conditions => { :basic => true })
82
+ end
38
83
 
39
84
  def get(num_code, options ={ })
40
85
  find_by_num_code(num_code) || create(options)
41
86
  end
42
- end
87
+
88
+ private
89
+
90
+ def add_rate(from, to, rate)
91
+ Money.add_rate(from, to, rate.to_f ) unless Money.default_bank.get_rate(from, to)
92
+ end
93
+
94
+ end # end class << self
95
+
43
96
  end
@@ -32,7 +32,7 @@
32
32
  <td><%= t("currency_locale") %>: </td>
33
33
  <td>
34
34
  <%= error_message_on :currency, :locale %>
35
- <%= f.select :locale, I18n.available_locales.map{|x| [x,x] } %>
35
+ <%= f.select :locale, I18n.available_locales.map{|x| [x,x] }, {}, { :multiple => true, :size => 10 } %>
36
36
  </td>
37
37
  </tr>
38
38
 
@@ -25,7 +25,7 @@
25
25
  <td>
26
26
  <%= currency.num_code %> - <%= currency.char_code %>
27
27
  </td>
28
- <td> <%= currency.locale %></td>
28
+ <td> <%= currency.locale(false) %></td>
29
29
  <td> <%= currency.basic %></td>
30
30
  <td>
31
31
  <%= link_to_edit currency %> &nbsp;
@@ -11,7 +11,7 @@
11
11
  <td><%= t("currency_converter_date_req") %>: </td>
12
12
  <td>
13
13
  <%= error_message_on :currency_converter, :date_req %>
14
- <%= f.datetime_select :date_req %>
14
+ <%= f.spree_date_picker :date_req %>
15
15
  </td>
16
16
  </tr>
17
17
 
@@ -0,0 +1,10 @@
1
+ ---
2
+ currency_RUB:
3
+ number:
4
+ currency:
5
+ format:
6
+ format: "%n %u"
7
+ unit: "руб."
8
+ separator: "."
9
+ delimiter: " "
10
+ precision: 2
@@ -0,0 +1,21 @@
1
+ ---
2
+ currency_USD: &usd
3
+ number:
4
+ currency:
5
+ format:
6
+ format: "%u%n"
7
+ unit: "$"
8
+ separator: "."
9
+ delimiter: ","
10
+ precision: 2
11
+ significant: false
12
+ strip_insignificant_zeros: false
13
+
14
+ currency_EUR:
15
+ <<: *usd
16
+ number:
17
+ currency:
18
+ format:
19
+ format: "%u%n"
20
+ unit: "€"
21
+
@@ -0,0 +1,26 @@
1
+ ---
2
+ en:
3
+ currency_changed: Currency changed
4
+ currency_not_found: Currency not found
5
+ currency_settings: Currency Settings
6
+ currency_converters_settings: Currency Converters
7
+ currency_description: Reference Currency
8
+ currency_converters_description: Currency Exchange Rates
9
+ add_currency_converter: Add currency exchange rate
10
+ currency_converter: Currency Converter
11
+ currency_converter_date_req: Date
12
+ currency_converter_currency: Currency
13
+ currency_converter_nominal: Nominal
14
+ currency_converter_value: Value
15
+ new_currency_converter: New
16
+ editing_currency_converter: Edit
17
+ add_currency: Add currency
18
+ list_currency: List of currencies
19
+ currency_name: Currency
20
+ currency_code: Code
21
+ currency_num_code: ISO number code
22
+ currency_char_code: ISO char code
23
+ currency_locale: Locale
24
+ currency_basic: Basic currency
25
+ editing_currency: Edit
26
+ new_currency: Add
@@ -0,0 +1,26 @@
1
+ ---
2
+ ru:
3
+ currency_changed: Валюта изменена
4
+ currency_not_found: Валюта не найдена
5
+ currency_settings: Валюты
6
+ currency_converters_settings: Курсы валют
7
+ currency_description: Настройка справочника валют
8
+ currency_converters_description: Настройка справочника курса валют
9
+ add_currency_converter: Добавить курс
10
+ currency_converter: Курсы валют
11
+ currency_converter_date_req: Дата
12
+ currency_converter_currency: Валюта
13
+ currency_converter_nominal: Номинал
14
+ currency_converter_value: Значение
15
+ new_currency_converter: Новый курс валюты
16
+ editing_currency_converter: Редактирование курса валюты
17
+ add_currency: Добавить валюту
18
+ list_currency: Список валют
19
+ currency_name: Валюта
20
+ currency_code: Код
21
+ currency_num_code: Цифровой код
22
+ currency_char_code: Строковый код
23
+ currency_locale: Локаль
24
+ currency_basic: Основная
25
+ editing_currency: Редактирование валюты
26
+ new_currency: Добавление валюты
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ # Put your extension routes here.
2
+ Rails.application.routes.draw do
3
+ match "currency/:id" => "currency#set", :as => :currency
4
+ namespace :admin do
5
+ resources :currencies
6
+ resources :currency_converters
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ class CreateCurrencies < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :currencies do |t|
4
+ t.string :num_code, :null => false
5
+ t.string :char_code, :null => false
6
+ t.string :name, :null => false
7
+ t.boolean :basic, :default => false
8
+ t.string :locale
9
+ t.timestamps
10
+ end
11
+ end
12
+
13
+ def self.down
14
+ drop_table :currencies
15
+ end
16
+ end
17
+
18
+ # <Valute ID="R01235">
19
+ # <NumCode>840</NumCode>
20
+ # <CharCode>USD</CharCode>
21
+ # <Nominal>1</Nominal>
22
+ # <Name>Доллар США</Name>
23
+ # <Value>30,8612</Value>
24
+ # </Valute>
@@ -0,0 +1,15 @@
1
+ class CreateCurrencyConverters < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :currency_converters do |t|
4
+ t.integer :currency_id, :null => false
5
+ t.datetime :date_req, :null => false
6
+ t.float :nominal, :null => false, :default => 1
7
+ t.float :value, :null => false
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :currency_converters
14
+ end
15
+ end
data/db/seeds.rb ADDED
@@ -0,0 +1,2 @@
1
+ # Use this file to load your own seed data from extensions.
2
+ # See the db/seeds.rb file in the Spree core for some ideas on what you can do here.
@@ -10,63 +10,6 @@ module MultiCurrencies
10
10
  Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
11
11
  Rails.env.production? ? require(c) : load(c)
12
12
  end
13
- Variant.class_eval do
14
-
15
- def price
16
- Currency.conversion_to_current(read_attribute(:price))
17
- end
18
-
19
- def price=(value)
20
- conversion_value = Currency.conversion_from_current(value)
21
- write_attribute(:price, conversion_value)
22
- end
23
-
24
- end
25
-
26
-
27
-
28
- Order.class_eval do
29
- def total
30
- Currency.conversion_to_current(read_attribute(:total))
31
- end
32
-
33
- def total=(value)
34
- conversion_value = Currency.conversion_from_current(value)
35
- write_attribute(:total, conversion_value)
36
- end
37
-
38
- def item_total
39
- Currency.conversion_to_current(read_attribute(:item_total))
40
- end
41
-
42
- def item_total=(value)
43
- conversion_value = Currency.conversion_from_current(value)
44
- write_attribute(:item_total, conversion_value)
45
- end
46
-
47
- def credit_total
48
- Currency.conversion_to_current(read_attribute(:credit_total))
49
- end
50
-
51
- def credit_total=(value)
52
- conversion_value = Currency.conversion_from_current(value)
53
- write_attribute(:credit_total, conversion_value)
54
- end
55
-
56
-
57
- end
58
-
59
- LineItem.class_eval do
60
- def price
61
- Currency.conversion_to_current(read_attribute(:price))
62
- end
63
-
64
- def price=(value)
65
- conversion_value = Currency.conversion_from_current(value)
66
- write_attribute(:price, conversion_value)
67
- end
68
- end
69
-
70
13
  end
71
14
 
72
15
  config.to_prepare &method(:activate).to_proc
@@ -0,0 +1,33 @@
1
+ module MultiCurrency
2
+
3
+ # Order.class_eval do
4
+ # extend MultiCurrency
5
+ # multi_currency :item_total, :total,
6
+ # :rate_at_date => lambda{ |t| t.created_at },
7
+ # :only_read => true
8
+ # only_read - выполнять перевод из одной валюты в другую только для вывода
9
+ # rate_at_date - использовать курс валюты на дату
10
+ def multi_currency(*args)
11
+ options = args.extract_options!
12
+ [args].flatten.compact.each do |number_field|
13
+
14
+ define_method(number_field.to_sym) do
15
+ if options.has_key?(:rate_at_date) && options[:rate_at_date].is_a?(Proc)
16
+ Currency.conversion_to_current(read_attribute(number_field.to_sym),
17
+ { :date => options[:rate_at_date].call(self) })
18
+ else
19
+ Currency.conversion_to_current(read_attribute(number_field.to_sym))
20
+ end
21
+ end
22
+
23
+ unless options[:only_read]
24
+ define_method(:"#{number_field}=") do |value|
25
+ write_attribute(number_field.to_sym, Currency.conversion_from_current(value))
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
33
+
@@ -1,20 +1,96 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
1
3
  # add custom rake tasks here
2
4
  namespace :multi_currencies do
3
- desc "Получение валют Сбербанк РФ"
4
- task :currency_sb => :environment do
5
- require 'open-uri'
6
- doc = Nokogiri::XML.parse(open("http://www.cbr.ru/scripts/XML_daily.asp?date_req=#{Time.now.strftime('%d/%m/%Y')}"))
7
- date = Date.strptime(doc.xpath("//ValCurs").attr("Date").to_s, '%d/%m/%Y')
8
- doc.xpath("//ValCurs/Valute").each do |valute|
9
- char_code = valute.xpath("./CharCode").text.to_s
10
- num_code = valute.xpath("./NumCode").text.to_s
11
-
12
- name = valute.xpath("./Name").text.to_s
13
- value = valute.xpath("./Value").text.gsub(',','.').to_f
14
- nominal = valute.xpath("./Nominal").text
15
- currency = Currency.get(num_code, { :num_code => num_code, :char_code => char_code, :name => name})
16
- currency && CurrencyConverter.add(currency, date, value, nominal)
5
+
6
+ namespace :currency do
7
+ desc "Общероссийский классификатор валют (сокращ. ОКВ) - http://ru.wikipedia.org/wiki/Общероссийский_классификатор_валют"
8
+
9
+ task :okv => :environment do
10
+ url = "http://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%89%D0%B5%D1%80%D0%BE%D1%81%D1%81%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%82%D0%BE%D1%80_%D0%B2%D0%B0%D0%BB%D1%8E%D1%82"
11
+ data = Nokogiri::HTML.parse(open(url))
12
+ keys = [:char_code, :num_code, :discharge, :name, :countries ]
13
+ data.css("table:first tr")[1..-1].map{ |d|
14
+ Hash[*keys.zip(d.css("td").map {|x| x.text.strip }).flatten]
15
+ }.each { |n|
16
+ Currency.find_by_num_code(n[:num_code]) || Currency.create(n.except(:discharge).except(:countries))
17
+ }
18
+
19
+ end
20
+
21
+ desc "Load currency ISO4217 http://en.wikipedia.org/wiki/ISO_4217"
22
+ task :iso4217 => :environment do
23
+ url = "http://en.wikipedia.org/wiki/ISO_4217"
24
+ data = Nokogiri::HTML.parse(open(url))
25
+ keys = [:char_code, :num_code, :discharge, :name, :countries ]
26
+ data.css("table:eq(2) tr")[1..-1].map{|d|
27
+ Hash[*keys.zip(d.css("td").map {|x| x.text.strip }).flatten]
28
+ }.each { |n|
29
+ Currency.find_by_num_code(n[:num_code]) || Currency.create(n.except(:discharge).except(:countries))
30
+ }
17
31
  end
32
+
18
33
  end
19
34
 
35
+ namespace :rates do
36
+ desc "Курс Сбербанка РФ http://www.cbr.ru"
37
+ task :cbr => :environment do
38
+ rub = Currency.get("643", { :num_code => "643", :char_code => "RUB", :name => "Российский рубль"})
39
+ rub.basic!
40
+ url = "http://www.cbr.ru/scripts/XML_daily.asp?date_req=#{Time.now.strftime('%d/%m/%Y')}"
41
+ data = Nokogiri::XML.parse(open(url))
42
+ date_str = data.xpath("//ValCurs").attr("Date").to_s
43
+ date = Date.strptime(date_str, (date_str =~ /\./ ? '%d.%m.%Y' : '%d/%m/%y'))
44
+ data.xpath("//ValCurs/Valute").each do |valute|
45
+ char_code = valute.xpath("./CharCode").text.to_s
46
+ num_code = valute.xpath("./NumCode").text.to_s
47
+ name = valute.xpath("./Name").text.to_s
48
+ value = valute.xpath("./Value").text.gsub(',','.').to_f
49
+ nominal = valute.xpath("./Nominal").text
50
+ currency = Currency.get(num_code, { :num_code => num_code, :char_code => char_code, :name => name})
51
+ currency && CurrencyConverter.add(currency, date, value, nominal)
52
+ end
53
+ end
54
+
55
+ desc "Rates from European Central Bank"
56
+ task :ecb, [:load_currencies] => :environment do |t, args|
57
+ Rake::Task["multi_currencies:currency:iso4217"].invoke if args.load_currencies
58
+ euro = Currency.get("978", { :num_code => "978", :char_code => "EUR", :name => "Euro"})
59
+ euro.basic!
60
+ url = 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml'
61
+ data = Nokogiri::XML.parse(open(url))
62
+ date = Date.strptime(data.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube').attr("time").to_s, "%Y-%m-%d")
63
+ data.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube//xmlns:Cube').each do |exchange_rate|
64
+ char_code = exchange_rate.attribute("currency").value.to_s.strip
65
+ value, nimonal = exchange_rate.attribute("rate").value.to_f, 1
66
+ currency = Currency.find_by_char_code(char_code)
67
+ currency && CurrencyConverter.add(currency, date, value, nominal)
68
+ end
69
+
70
+ end
71
+
72
+ desc "Rates from Google"
73
+ task :google, [:currency, :load_currencies] => :environment do |t, args|
74
+ Rake::Task["multi_currencies:currency:iso4217"].invoke if args.load_currencies
75
+ default_currency = Currency.where(" char_code = :currency_code or num_code = :currency_code",
76
+ :currency_code => args.currency || 978).first ||
77
+ Currency.get("978", { :num_code => "978", :char_code => "EUR", :name => "Euro"})
78
+ default_currency.basic!
79
+ date = Time.now
80
+ Currency.all.each { |currency|
81
+ unless currency == default_currency
82
+ url = "http://www.google.com/ig/calculator?hl=en&q=1#{ currency.char_code }%3D%3F#{ default_currency.char_code }"
83
+ @data = JSON.parse(open(url).read.gsub(/lhs:|rhs:|error:|icc:/){ |x| "\"#{x[0..-2]}\":"})
84
+ if @data["error"].blank?
85
+ @value = BigDecimal(@data["rhs"].split(' ')[0])
86
+ CurrencyConverter.add(currency, date, @value, 1)
87
+ end
88
+ end
89
+ }
90
+ end
91
+ end
92
+
93
+
94
+
20
95
  end
96
+
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.platform = Gem::Platform::RUBY
6
+ s.name = 'multi_currencies'
7
+ s.version = '1.0.2'
8
+ s.summary = 'Add gem summary here'
9
+ s.required_ruby_version = '>= 1.8.7'
10
+ s.authors = ["Maxim"]
11
+ s.email = ["parallel588@gmail.com"]
12
+ s.homepage = ""
13
+ s.summary = %q{spree-multi-currency}
14
+ s.description = %q{spree-multi-currency}
15
+
16
+ s.rubyforge_project = "spree-multi-currency"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+
22
+ s.require_path = ['lib']
23
+
24
+
25
+ s.add_dependency('spree_core', '>= 0.30.0')
26
+ s.add_dependency('nokogiri', '>= 1.4.4')
27
+ s.add_dependency('money', '>= 3.6.1')
28
+ s.add_dependency('json', '>= 1.5.1')
29
+
30
+ s.add_development_dependency("rspec", ">= 2.5.0")
31
+ end
@@ -0,0 +1,31 @@
1
+ # This file is copied to ~/spec when you run 'ruby script/generate rspec'
2
+ # from the project root directory.
3
+ ENV["RAILS_ENV"] ||= 'test'
4
+ require File.expand_path("../../../config/environment", __FILE__)
5
+ require 'rspec/rails'
6
+ require 'fabrication'
7
+
8
+ # Requires supporting files with custom matchers and macros, etc,
9
+ # in ./support/ and its subdirectories.
10
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ # == Mock Framework
14
+ #
15
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
16
+ #
17
+ # config.mock_with :mocha
18
+ # config.mock_with :flexmock
19
+ # config.mock_with :rr
20
+ config.mock_with :rspec
21
+
22
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
23
+
24
+ #config.include Devise::TestHelpers, :type => :controller
25
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
26
+ # examples within a transaction, comment the following line or assign false
27
+ # instead of true.
28
+ config.use_transactional_fixtures = true
29
+ end
30
+
31
+ @configuration ||= AppConfiguration.find_or_create_by_name("Default configuration")
metadata CHANGED
@@ -1,21 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi_currencies
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
5
- prerelease: false
4
+ hash: 19
5
+ prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 0
10
- version: 1.0.0
9
+ - 2
10
+ version: 1.0.2
11
11
  platform: ruby
12
- authors: []
13
-
12
+ authors:
13
+ - Maxim
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-14 00:00:00 +03:00
18
+ date: 2011-04-24 00:00:00 +04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -42,17 +42,65 @@ dependencies:
42
42
  requirements:
43
43
  - - ">="
44
44
  - !ruby/object:Gem::Version
45
- hash: 113
45
+ hash: 15
46
46
  segments:
47
47
  - 1
48
48
  - 4
49
+ - 4
50
+ version: 1.4.4
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: money
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 29
62
+ segments:
49
63
  - 3
64
+ - 6
50
65
  - 1
51
- version: 1.4.3.1
66
+ version: 3.6.1
52
67
  type: :runtime
53
- version_requirements: *id002
54
- description:
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: json
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 1
78
+ segments:
79
+ - 1
80
+ - 5
81
+ - 1
82
+ version: 1.5.1
83
+ type: :runtime
84
+ version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: rspec
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 27
94
+ segments:
95
+ - 2
96
+ - 5
97
+ - 0
98
+ version: 2.5.0
99
+ type: :development
100
+ version_requirements: *id005
101
+ description: spree-multi-currency
55
102
  email:
103
+ - parallel588@gmail.com
56
104
  executables: []
57
105
 
58
106
  extensions: []
@@ -60,35 +108,54 @@ extensions: []
60
108
  extra_rdoc_files: []
61
109
 
62
110
  files:
63
- - README.md
111
+ - .gitignore
112
+ - Gemfile
64
113
  - LICENSE
65
- - lib/multi_currencies_hooks.rb
66
- - lib/multi_currencies.rb
67
- - lib/tasks/multi_currencies.rake
68
- - lib/tasks/install.rake
69
- - app/helpers/admin/currencies_helper.rb
114
+ - README.markdown
115
+ - Rakefile
116
+ - app/controllers/admin/currencies_controller.rb
117
+ - app/controllers/admin/currency_converters_controller.rb
118
+ - app/controllers/currency_controller.rb
119
+ - app/controllers/spree/base_controller_decorator.rb
120
+ - app/decorators/line_item_decorator.rb
121
+ - app/decorators/order_decorator.rb
122
+ - app/decorators/variant_decorator.rb
70
123
  - app/helpers/admin/currency_converters_helper.rb
124
+ - app/helpers/number_helper_decorator.rb
71
125
  - app/models/currency.rb
72
126
  - app/models/currency_converter.rb
127
+ - app/views/admin/currencies/_form.html.erb
73
128
  - app/views/admin/currencies/edit.html.erb
74
129
  - app/views/admin/currencies/index.html.erb
75
- - app/views/admin/currencies/_form.html.erb
76
130
  - app/views/admin/currencies/new.html.erb
131
+ - app/views/admin/currency_converters/_form.html.erb
77
132
  - app/views/admin/currency_converters/edit.html.erb
78
133
  - app/views/admin/currency_converters/index.html.erb
79
- - app/views/admin/currency_converters/_form.html.erb
80
134
  - app/views/admin/currency_converters/new.html.erb
81
- - app/controllers/admin/currency_converters_controller.rb
82
- - app/controllers/admin/currencies_controller.rb
135
+ - config/locales/currency_rub.yml
136
+ - config/locales/currency_usd.yml
137
+ - config/locales/en_multi_currency.yml
138
+ - config/locales/ru_multi_currency.yml
139
+ - config/routes.rb
140
+ - db/migrate/20101109134351_create_currencies.rb
141
+ - db/migrate/20101109134453_create_currency_converters.rb
142
+ - db/seeds.rb
143
+ - lib/multi_currencies.rb
144
+ - lib/multi_currencies_hooks.rb
145
+ - lib/multi_currency.rb
146
+ - lib/tasks/install.rake
147
+ - lib/tasks/multi_currencies.rake
148
+ - multi_currencies.gemspec
149
+ - spec/spec_helper.rb
83
150
  has_rdoc: true
84
- homepage:
151
+ homepage: ""
85
152
  licenses: []
86
153
 
87
154
  post_install_message:
88
155
  rdoc_options: []
89
156
 
90
157
  require_paths:
91
- - lib
158
+ - - lib
92
159
  required_ruby_version: !ruby/object:Gem::Requirement
93
160
  none: false
94
161
  requirements:
@@ -109,12 +176,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
176
  segments:
110
177
  - 0
111
178
  version: "0"
112
- requirements:
113
- - none
114
- rubyforge_project:
115
- rubygems_version: 1.3.7
179
+ requirements: []
180
+
181
+ rubyforge_project: spree-multi-currency
182
+ rubygems_version: 1.4.2
116
183
  signing_key:
117
184
  specification_version: 3
118
- summary: Add gem summary here
119
- test_files: []
120
-
185
+ summary: spree-multi-currency
186
+ test_files:
187
+ - spec/spec_helper.rb
data/README.md DELETED
@@ -1,13 +0,0 @@
1
- MultiCurrencies
2
- ===============
3
-
4
- Introduction goes here.
5
-
6
-
7
- Example
8
- =======
9
-
10
- Example goes here.
11
-
12
-
13
- Copyright (c) 2010 [name of extension creator], released under the New BSD License
@@ -1,2 +0,0 @@
1
- module Admin::CurrenciesHelper
2
- end