multi_currencies 1.0.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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