smartkiosk-client 0.0.1

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 (75) hide show
  1. data/Gemfile +5 -0
  2. data/Gemfile.lock +176 -0
  3. data/Rakefile +4 -0
  4. data/app/controllers/banners.rb +14 -0
  5. data/app/controllers/collections.rb +10 -0
  6. data/app/controllers/config.rb +23 -0
  7. data/app/controllers/payments.rb +30 -0
  8. data/app/controllers/receipts.rb +13 -0
  9. data/app/controllers/terminal.rb +104 -0
  10. data/app/models/admin.rb +3 -0
  11. data/app/models/banner.rb +5 -0
  12. data/app/models/collection.rb +53 -0
  13. data/app/models/customer.rb +3 -0
  14. data/app/models/group.rb +37 -0
  15. data/app/models/order.rb +25 -0
  16. data/app/models/payment.rb +80 -0
  17. data/app/models/phone_range.rb +3 -0
  18. data/app/models/promotion.rb +11 -0
  19. data/app/models/provider.rb +42 -0
  20. data/app/models/receipt.rb +21 -0
  21. data/app/models/receipt_template.rb +5 -0
  22. data/app/models/terminal.rb +152 -0
  23. data/app/uploaders/icon_uploader.rb +9 -0
  24. data/app/views/banners.haml +50 -0
  25. data/app/workers/orders/acknowledge_worker.rb +22 -0
  26. data/app/workers/orders/complete_worker.rb +20 -0
  27. data/app/workers/orders/disable_worker.rb +16 -0
  28. data/app/workers/orders/enable_worker.rb +16 -0
  29. data/app/workers/orders/reboot_worker.rb +18 -0
  30. data/app/workers/orders/reload_worker.rb +18 -0
  31. data/app/workers/orders/upgrade_worker.rb +108 -0
  32. data/app/workers/payments/check_worker.rb +35 -0
  33. data/app/workers/payments/collect_worker.rb +23 -0
  34. data/app/workers/payments/pay_worker.rb +21 -0
  35. data/app/workers/ping_worker.rb +180 -0
  36. data/app/workers/startup_worker.rb +11 -0
  37. data/app/workers/sync/icons_worker.rb +20 -0
  38. data/app/workers/sync/receipt_templates_worker.rb +27 -0
  39. data/config/boot.rb +104 -0
  40. data/config/services/application.yml +4 -0
  41. data/config/services/database.yml +17 -0
  42. data/config/services/database.yml.sample +33 -0
  43. data/config/services/smartware.yml +28 -0
  44. data/config/services/smartware.yml.sample +13 -0
  45. data/config/sidekiq.yml +12 -0
  46. data/db/development.sqlite3 +0 -0
  47. data/db/migrate/20121230080152_create_customers.rb +8 -0
  48. data/db/migrate/20121230080159_create_admins.rb +11 -0
  49. data/db/migrate/20130106150707_create_orders.rb +14 -0
  50. data/db/migrate/20130106155321_create_providers.rb +19 -0
  51. data/db/migrate/20130106160834_create_groups.rb +11 -0
  52. data/db/migrate/20130106181512_create_receipt_templates.rb +9 -0
  53. data/db/migrate/20130106181548_create_payments.rb +26 -0
  54. data/db/migrate/20130106181729_create_collections.rb +10 -0
  55. data/db/migrate/20130106181803_create_receipts.rb +15 -0
  56. data/db/migrate/20130106181844_create_phone_ranges.rb +14 -0
  57. data/db/migrate/20130108110546_create_promotions.rb +9 -0
  58. data/db/migrate/20130110025256_create_banners.rb +12 -0
  59. data/init.rb +1 -0
  60. data/lib/pinger.rb +22 -0
  61. data/lib/sidekiq.rb +20 -0
  62. data/lib/smartkiosk/client/version.rb +7 -0
  63. data/lib/smartkiosk/client.rb +1 -0
  64. data/lib/smartkiosk/config/chunk.rb +7 -0
  65. data/lib/smartkiosk/config/yaml.rb +26 -0
  66. data/lib/tasks/db.rb +15 -0
  67. data/lib/tasks/pack.rb +27 -0
  68. data/lib/tasks/scheduler.rb +27 -0
  69. data/lib/tasks/services.rb +20 -0
  70. data/server.rb +11 -0
  71. data/smartkiosk-client.gemspec +55 -0
  72. data/tmp/pids/.gitkeep +0 -0
  73. data/tmp/pids/sidekiq.pid +1 -0
  74. data/vendor/assets/javascripts/jquery.js +9555 -0
  75. metadata +444 -0
@@ -0,0 +1,152 @@
1
+ require 'smartware'
2
+ require 'socket'
3
+ require 'redis'
4
+ require 'redis/objects'
5
+
6
+ Application.load 'lib/smartkiosk/config/yaml'
7
+
8
+ class Terminal
9
+ include Redis::Objects
10
+
11
+ value :state, :global => true
12
+ value :started_at, :global => true, :marshal => true
13
+ value :modified_at, :global => true, :marshal => true
14
+ value :payment_in_progress, :global => true
15
+
16
+ value :support_phone, :global => true
17
+ value :providers_updates, :global => true, :marshal => true
18
+
19
+ def self.smartguard
20
+ DRbObject.new_with_uri(Terminal.config.smartguard_host)
21
+ end
22
+
23
+ #
24
+ # STATES
25
+ #
26
+ def self.enable
27
+ self.state = 'active'
28
+ end
29
+
30
+ def self.disable
31
+ self.state = 'disabled'
32
+ end
33
+
34
+ def self.payment_in_progress?
35
+ self.payment_in_progress.value == "true"
36
+ end
37
+
38
+ def self.actual_state
39
+ self.state.value || 'active'
40
+ end
41
+
42
+ def self.actual_modified_at
43
+ self.modified_at.value || DateTime.now
44
+ end
45
+
46
+ def self.providers_updated_at
47
+ self.providers_updates[self.config.host] rescue nil
48
+ end
49
+
50
+ def self.providers_updated_at=(value)
51
+ self.providers_updates = {self.config.host => value}
52
+ end
53
+
54
+ #
55
+ # ACTIONS
56
+ #
57
+ def self.ping
58
+ PingWorker.perform_async
59
+ end
60
+
61
+ def self.reload
62
+ smartguard.restart_async
63
+ end
64
+
65
+ def self.reboot
66
+ self.state = 'rebooting'
67
+ StartupWorker.perform_async self.name, :enable
68
+
69
+ smartguard.reboot_async
70
+ end
71
+
72
+ #
73
+ # CONDITON
74
+ #
75
+ def self.config
76
+ @config ||= Smartkiosk::Config::YAML.new(Application.root.join 'config/services/application.yml')
77
+ end
78
+
79
+ def self.keyword
80
+ config.keyword
81
+ end
82
+
83
+ def self.enabled?
84
+ self.actual_state == 'active'
85
+ end
86
+
87
+ def self.version
88
+ '0.1'
89
+ end
90
+
91
+ def self.ip
92
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
93
+
94
+ UDPSocket.open do |s|
95
+ s.connect '64.233.187.99', 1
96
+ s.addr.last
97
+ end
98
+ rescue
99
+ '0.0.0.0'
100
+ ensure
101
+ Socket.do_not_reverse_lookup = orig
102
+ end
103
+
104
+ def self.as_json
105
+ {
106
+ :started_at => Terminal.started_at.value,
107
+ :modified_at => Terminal.actual_modified_at,
108
+ :keyword => Terminal.keyword,
109
+ :support_phone => Terminal.support_phone.value,
110
+ :groups => Group.all.map{|x| x.as_json},
111
+ :providers => Provider.active.map{|x| x.as_json},
112
+ :promotions => Promotion.order(:priority).limit(6).map{|x| x.provider_id}
113
+ }
114
+ end
115
+
116
+ def self.condition
117
+ {
118
+ :ip => ip,
119
+ :state => Terminal.actual_state,
120
+ :banknotes => Payment.merge_banknotes(Payment.uncollected),
121
+ :cash => Payment.merge_cash(Payment.uncollected),
122
+ :providers => {
123
+ :updated_at => Terminal.providers_updated_at,
124
+ :ids => Provider.select(:foreign_id).map{|x| x.foreign_id} || []
125
+ },
126
+ :queues => {
127
+ :payments => Sidekiq::Queue.new('payments').size,
128
+ :pings => Sidekiq::Queue.new('pings').size,
129
+ :orders => Sidekiq::Queue.new('orders').size,
130
+ :sync => Sidekiq::Queue.new('sync').size
131
+ },
132
+ :cash_acceptor => {
133
+ :error => Smartware.cash_acceptor.error,
134
+ :model => Smartware.cash_acceptor.model,
135
+ :version => Smartware.cash_acceptor.version
136
+ },
137
+ :printer => {
138
+ :error => Smartware.printer.error,
139
+ :model => Smartware.printer.model,
140
+ :version => Smartware.printer.version
141
+ },
142
+ :modem => {
143
+ :error => Smartware.modem.error,
144
+ :signal_level => Smartware.modem.signal_level,
145
+ :balance => Smartware.modem.balance,
146
+ :model => Smartware.modem.model,
147
+ :version => Smartware.modem.version
148
+ },
149
+ :version => Terminal.version
150
+ }
151
+ end
152
+ end
@@ -0,0 +1,9 @@
1
+ require 'carrierwave'
2
+
3
+ class IconUploader < CarrierWave::Uploader::Base
4
+ storage :file
5
+
6
+ def store_dir
7
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
8
+ end
9
+ end
@@ -0,0 +1,50 @@
1
+ !!!
2
+ %html{:lang => "ru"}
3
+ %head
4
+ %meta{:charset => "utf-8"}
5
+ %meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}
6
+ %title banners
7
+ %script{:type => 'text/javascript', :src => '/assets/jquery.js'}
8
+
9
+ :javascript
10
+ var playBanner;
11
+
12
+ playBanner = function(prev) {
13
+ if (prev == null) {
14
+ prev = 0;
15
+ }
16
+ return $.get("/banners/playlist?prev=" + prev, function(banner) {
17
+ var playNext,
18
+ _this = this;
19
+ if (banner.filename.substr(banner.filename.length-4) === '.swf') {
20
+ $('video').hide();
21
+ $('video').attr('src', '');
22
+ $('object').show();
23
+ $('object').attr('data', banner.filename);
24
+ $('object > embed').attr('src', banner.filename);
25
+ return playNext = setTimeout(function() {
26
+ return playBanner(banner.playorder);
27
+ }, parseInt(parseFloat(banner.duration) * 1000));
28
+ } else {
29
+ $('object').hide();
30
+ $('object').attr('data', '');
31
+ $('object > embed').attr('src', '');
32
+ $('video').show();
33
+ $('video').attr('src', banner.filename);
34
+ $('video')[0].play();
35
+ return playNext = setTimeout(function() {
36
+ $('video')[0].pause();
37
+ return playBanner(banner.playorder);
38
+ }, parseInt(parseFloat(banner.duration) * 1000));
39
+ }
40
+ });
41
+ };
42
+
43
+ playBanner();
44
+
45
+
46
+ %body{:style => 'margin: 0; padding: 0;'}
47
+ %video{:width => "1280", :height => "1024", :type => 'video/webm', :style => "max-height: 1019px; max-width: 1280px;" }
48
+ %object{:height => '1019', :width => '1280', :type => "application/x-shockwave-flash" }
49
+ %param{:name => "autoplay", :value => "true"}
50
+ %embed{:height => '1019', :width => '1280' }
@@ -0,0 +1,22 @@
1
+ require 'rest-client'
2
+
3
+ Application.load 'lib/sidekiq'
4
+
5
+ module Orders
6
+ class AcknowledgeWorker
7
+ include Sidekiq::Worker
8
+
9
+ sidekiq_options :queue => :orders
10
+
11
+ def perform(order_id, error=nil, percent=nil)
12
+ order = Order.find(order_id)
13
+
14
+ response = RestClient.post "#{Terminal.config.host}/terminal_orders/#{order.foreign_id}/acknowledge",
15
+ :terminal => Terminal.keyword,
16
+ :error => error,
17
+ :percent => percent
18
+
19
+ order.acknowledged!
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ require 'rest-client'
2
+
3
+ Application.load 'lib/sidekiq'
4
+
5
+ module Orders
6
+ class CompleteWorker
7
+ include Sidekiq::Worker
8
+
9
+ sidekiq_options :queue => :orders
10
+
11
+ def perform(order_id)
12
+ order = Order.find(order_id)
13
+
14
+ response = RestClient.post "#{Terminal.config.host}/terminal_orders/#{order.foreign_id}/complete",
15
+ :terminal => Terminal.keyword
16
+
17
+ Terminal.ping
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ Application.load 'lib/sidekiq'
2
+
3
+ module Orders
4
+ class DisableWorker
5
+ include Sidekiq::Worker
6
+
7
+ sidekiq_options :queue => :orders
8
+
9
+ def perform(order_id)
10
+ order = Order.find(order_id)
11
+
12
+ Terminal.disable
13
+ order.complete
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ Application.load 'lib/sidekiq'
2
+
3
+ module Orders
4
+ class EnableWorker
5
+ include Sidekiq::Worker
6
+
7
+ sidekiq_options :queue => :orders
8
+
9
+ def perform(order_id)
10
+ order = Order.find(order_id)
11
+
12
+ Terminal.enable
13
+ order.complete
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ Application.load 'lib/sidekiq'
2
+
3
+ module Orders
4
+ class RebootWorker
5
+ include Sidekiq::Worker
6
+
7
+ sidekiq_options :queue => :orders
8
+
9
+ def perform(order_id)
10
+ StartupWorker.perform_async self.class.name, :finish, [order_id]
11
+ Terminal.reboot
12
+ end
13
+
14
+ def self.finish(order_id)
15
+ Order.find(order_id).complete
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ Application.load 'lib/sidekiq'
2
+
3
+ module Orders
4
+ class ReloadWorker
5
+ include Sidekiq::Worker
6
+
7
+ sidekiq_options :queue => :orders
8
+
9
+ def perform(order_id)
10
+ StartupWorker.perform_async self.class.name, :finish, [order_id]
11
+ Terminal.reload
12
+ end
13
+
14
+ def self.finish(order_id)
15
+ Order.find(order_id).complete
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,108 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+ require 'fileutils'
4
+
5
+ Application.load 'lib/sidekiq'
6
+
7
+ module Orders
8
+ class UpgradeWorker
9
+ include Sidekiq::Worker
10
+
11
+ sidekiq_options :queue => :orders
12
+
13
+ def perform(order_id)
14
+ order = Order.find(order_id)
15
+
16
+ @order_id = order_id
17
+ @build_version = Gem::Version.new order.args[1]
18
+ @build_id = order.args[0]
19
+ @base_url = URI.parse(order.args[3]).scheme.nil? ? "#{Terminal.config.host}#{order.args[3]}"
20
+ : order.args[3]
21
+
22
+ @releases_pathname = Terminal.smartguard.releases_path
23
+ @build_pathname = @releases_pathname.join @build_version.to_s
24
+
25
+ self.sync!
26
+ Terminal.smartguard.switch_release @build_version.to_s.to_sym do
27
+ order.complete
28
+ end
29
+ end
30
+
31
+ def files!
32
+ FileUtils.mkdir_p @releases_pathname
33
+
34
+ nearest_less_release = Dir.glob(@releases_pathname.join('*.*')).select do |v|
35
+ Gem::Version.new(File.basename(v)) < @build_version
36
+ end.max
37
+
38
+ if !File.directory?(@build_pathname)
39
+ if nearest_less_release.blank?
40
+ FileUtils.mkdir_p @build_pathname
41
+ else
42
+ FileUtils.cp_r nearest_less_release, @build_pathname
43
+ end
44
+ end
45
+
46
+ remotes = JSON.parse(RestClient.get "#{Terminal.config.host}/terminal_builds/#{@build_id}/hashes")
47
+ locals = Dir[File.join(@build_pathname, '**/**')].select{|x| File.file?(x)}.map{|x|
48
+ Pathname.new(x).relative_path_from(@build_pathname).to_s
49
+ }
50
+
51
+ download = {}
52
+ remove = []
53
+
54
+ remotes.each do |remote, data|
55
+ local = @build_pathname.join(remote)
56
+
57
+ if !File.file?(local) || Digest::MD5.file(local).hexdigest != data[0]
58
+ download[remote] = data[1]
59
+ end
60
+ end
61
+
62
+ locals.each do |local, hash|
63
+ remove << local if remotes[local].blank?
64
+ end
65
+
66
+ {:download => download, :remove => remove}
67
+ end
68
+
69
+ def sync!
70
+ diff = files!
71
+
72
+ total_transfer_size = diff[:download].values.inject(0){|sum,x|(sum+=x) unless x.nil?; sum }.to_f
73
+
74
+ diff[:download].each do |key, value|
75
+ uri = URI.parse(URI.encode("#{@base_url}/#{key}"))
76
+ path = @build_pathname.join key
77
+ FileUtils.mkdir_p File.dirname(path)
78
+
79
+ File.open(path, "wb") do |f|
80
+ Net::HTTP.start(uri.host, uri.port) do |http|
81
+ http.request_get(uri.path) do |resp|
82
+ resp.read_body do |segment|
83
+ f.write(segment)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ diff[:download][key] = 0
90
+
91
+ delta_transfer_size = diff[:download].values.inject(0){|sum,x| (sum+=x) unless x.nil?; sum}.to_f
92
+
93
+ current_percentage = (100.0 - (delta_transfer_size / total_transfer_size * 100.0)).round(2)
94
+ if current_percentage > (@percentage ||= 0) + 5 || current_percentage == 100
95
+ @percentage = current_percentage
96
+ AcknowledgeWorker.perform_async(@order_id, nil, @percentage)
97
+ end
98
+
99
+ end
100
+
101
+ diff[:remove].each do |file|
102
+ fullpath = @build_pathname.join file
103
+ File.delete(fullpath) if File.exist?(fullpath)
104
+ end
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,35 @@
1
+ require 'rest-client'
2
+
3
+ Application.load 'lib/sidekiq'
4
+
5
+ module Payments
6
+ class CheckWorker
7
+ include Sidekiq::Worker
8
+
9
+ sidekiq_options :queue => :payments
10
+
11
+ def perform(payment_id)
12
+ payment = Payment.find(payment_id)
13
+ response = RestClient.post "#{Terminal.config.host}/payments",
14
+ :provider => payment.provider.keyword,
15
+ :terminal => Terminal.config.keyword,
16
+ :payment => {
17
+ :account => payment.account,
18
+ :fields => payment.fields,
19
+ :session_id => payment.id
20
+ }
21
+
22
+ answer = JSON.parse(response.to_s, :symbolize_names => true)
23
+
24
+ unless answer[:id].nil?
25
+ payment.update_attributes :foreign_id => answer[:id],
26
+ :limit => answer[:limits].sort_by(&:weight).last,
27
+ :commissions => (answer[:commissions].empty? ? nil : answer[:commissions]),
28
+ :receipt_template => answer[:receipt_template],
29
+ :checked => true
30
+ end
31
+ rescue => e
32
+ Payment.find(payment_id).update_attributes :error => true
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ Application.load 'lib/sidekiq'
2
+
3
+ module Payments
4
+ class CollectWorker
5
+ include Sidekiq::Worker
6
+
7
+ sidekiq_options :queue => :payments
8
+
9
+ def perform(collection_id)
10
+ collection = Collection.find(collection_id)
11
+
12
+ response = RestClient.post "#{Terminal.config.host}/collections",
13
+ :terminal => Terminal.config.keyword,
14
+ :collection => {
15
+ :banknotes => collection.banknotes,
16
+ :collected_at => collection.created_at,
17
+ :session_ids => collection.payment_ids
18
+ }
19
+
20
+ collection.update_attribute(:reported_at, DateTime.now)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require 'rest-client'
2
+
3
+ Application.load 'lib/sidekiq'
4
+
5
+ module Payments
6
+ class PayWorker
7
+ include Sidekiq::Worker
8
+
9
+ sidekiq_options :queue => :payments
10
+
11
+ def perform(payment_id)
12
+ payment = Payment.find(payment_id)
13
+ response = RestClient.post "#{Terminal.config.host}/payments/#{payment.foreign_id}/pay",
14
+ :provider => payment.provider.keyword,
15
+ :terminal => Terminal.config.keyword,
16
+ :payment => { :paid_amount => payment.paid_amount }
17
+ Sidekiq::Logging.logger.debug "Pay response: #{response.to_s}"
18
+ payment.update_attributes(:processed => true) if response
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,180 @@
1
+ require 'rest-client'
2
+
3
+ Application.load 'lib/sidekiq'
4
+
5
+ class PingWorker
6
+ include Sidekiq::Worker
7
+
8
+ sidekiq_options :retry => false, :queue => :pings
9
+
10
+ SEMAPHORE = ConnectionPool.new(:size => 1, :timeout => 5) { true }
11
+
12
+ def perform
13
+ begin
14
+ SEMAPHORE.with do |glory|
15
+ condition = Terminal.condition
16
+
17
+ Sidekiq::Logging.logger.info "Requesting with updated_at: #{Terminal.providers_updated_at}"
18
+
19
+ begin
20
+ response = RestClient::Request.execute(
21
+ :method => :post,
22
+ :url => "#{Terminal.config.host}/terminal_pings",
23
+ :timeout => 40,
24
+ :open_timeout => 60,
25
+ :payload => {
26
+ :terminal => Terminal.keyword,
27
+ :terminal_ping => condition
28
+ }
29
+ )
30
+ rescue Exception => e
31
+ Sidekiq::Logging.logger.warn e.to_s
32
+ return
33
+ end
34
+
35
+ begin
36
+ response = JSON.parse(response.to_s, :symbolize_names => true)
37
+ rescue Exception => e
38
+ Sidekiq::Logging.logger.warn "Unable to parse JSON: #{e.to_s}"
39
+ return
40
+ end
41
+
42
+ unless Terminal.support_phone.value == response[:support_phone]
43
+ Terminal.support_phone = response[:support_phone]
44
+ Terminal.modified_at = DateTime.now
45
+ end
46
+
47
+ Sidekiq::Logging.logger.info "Response: #{response.inspect}"
48
+
49
+ #
50
+ # ORDERS
51
+ #
52
+ response[:orders].each do |order|
53
+ next unless Order.find_by_foreign_id(order[:id]).blank?
54
+
55
+ order[:foreign_id] = order.delete(:id)
56
+ order = Order.create!(order)
57
+
58
+ order.acknowledge
59
+ order.perform
60
+ end
61
+
62
+ #
63
+ # PROVIDERS
64
+ #
65
+ unless response[:providers].blank?
66
+ syncs = []
67
+
68
+ Provider.transaction do
69
+ #
70
+ # GROUPS
71
+ #
72
+ unless response[:providers][:groups].nil?
73
+ remote = response[:providers][:groups]
74
+ remote_ids = response[:providers][:groups].map{|x| x[:id]}
75
+ local = Group.all
76
+
77
+ local.select{|x| !remote_ids.include?(x.id)}.each do |x|
78
+ Sidekiq::Logging.logger.info "Group removal: ##{x.id}, #{x.title}"
79
+ x.destroy
80
+ end
81
+
82
+ remote.each do |r|
83
+ entry = local.find{|x| x.id == r[:id]}
84
+ entry ||= Group.new :foreign_id => r[:id]
85
+
86
+ entry.title = r[:title]
87
+ entry.priority = r[:priority]
88
+ entry.group_id = r[:parent_id]
89
+
90
+ Sidekiq::Logging.logger.info "Group replace: #{entry.title}"
91
+
92
+ entry.save!
93
+
94
+ unless r[:icon].blank?
95
+ syncs << ['Group', entry.id, r[:icon]]
96
+ end
97
+ end
98
+ end
99
+
100
+ #
101
+ # PROVIDERS REMOVAL
102
+ #
103
+ unless response[:providers][:remove].blank?
104
+ Sidekiq::Logging.logger.info "Providers removal: #{response[:providers][:remove]}"
105
+ Provider.where(:foreign_id => response[:providers][:remove]).destroy_all
106
+ end
107
+
108
+ #
109
+ # PROVIDERS UPDATES
110
+ #
111
+ unless response[:providers][:updated_at].blank?
112
+ response[:providers][:update].each do |provider|
113
+ local = Provider.find_or_initialize_by_foreign_id(provider[:id])
114
+
115
+ attributes = {
116
+ :title => provider[:title],
117
+ :keyword => provider[:keyword],
118
+ :priority => provider[:priority],
119
+ :fields => provider[:fields],
120
+ :group_id => provider[:group_id],
121
+ :requires_print => provider[:requires_print]
122
+ }
123
+
124
+ if provider[:icon].blank?
125
+ attributes[:icon] = nil
126
+ end
127
+
128
+ local.assign_attributes attributes
129
+
130
+ Sidekiq::Logging.logger.info "Provider replace: #{local.keyword}"
131
+
132
+ local.save!
133
+
134
+ unless provider[:icon].blank?
135
+ syncs << ['Provider', local.id, provider[:icon]]
136
+ end
137
+ end
138
+ end
139
+
140
+ #
141
+ # PROMOTIONS
142
+ #
143
+ unless response[:providers][:promotions].nil?
144
+ providers = Provider.to_hash(:foreign_id, response[:providers][:promotions], :invert => true)
145
+ remote = response[:providers][:promotions].map{|x| providers[x]}.compact
146
+ local = Promotion.all
147
+
148
+ local.select{|x| !remote.include?(x.provider_id)}.each do |x|
149
+ Sidekiq::Logging.logger.info "Promotion removal: #{x.provider_id}"
150
+ x.destroy
151
+ end
152
+
153
+ remote.each_with_index do |r, i|
154
+ entry = local.find{|x| x.provider_id == r}
155
+ entry ||= Promotion.new :provider_id => r
156
+
157
+ Sidekiq::Logging.logger.info "Promotion replace: #{r}"
158
+
159
+ entry.priority = i
160
+ entry.save!
161
+ end
162
+ end
163
+ end
164
+
165
+ unless response[:providers][:updated_at].blank?
166
+ Terminal.providers_updated_at = response[:providers][:updated_at]
167
+ end
168
+
169
+ Sidekiq::Logging.logger.info "Icons to sync: #{syncs}"
170
+
171
+ syncs.each do |args|
172
+ Sync::IconsWorker.perform_async *args
173
+ end
174
+ end
175
+ end
176
+ rescue Timeout::Error => e
177
+ Sidekiq::Logging.logger.warn "Semaphore timeout. #{e.to_s}"
178
+ end
179
+ end
180
+ end