caboose-rets 0.0.52 → 0.0.53

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NzFmZTA4NTZmNTY4Nzg4NWU5MTYzZWRjMzFhMGQ0MzQ2Zjk3MjMwYg==
4
+ MTBjMzMwZDYzNDkzMTQ3M2U3NTdkMjQ4MDc4OTZmMzk4YjlhM2Q2Yg==
5
5
  data.tar.gz: !binary |-
6
- N2FmZDFjOTBmZmFhMjk0ZmM3NmFiZWM2NGFlOWE4MGQzYTJkNzc4Zg==
6
+ NmYyMWM1YmRjYjUwZjg0NWMxODk1NGVmNDUwMzQyMjBjZGJlNTFmZg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- MGIwM2M3NWI3YzAyN2MyMzczODM2MzRiYWI2NzNjZjIwOGU0MzI5M2ZhYzk1
10
- OTgwYjdjYTdkNTQyOTk3YzQ4YzJlZDA1ZjgxNTQ0NDkzYjk5MjViZjQ0Nzk0
11
- MWY2MjllN2QyMzNiYmJiODdkNzA2YmM4NWUzOGNlNWY0MDg1MmM=
9
+ ZDQ4NWYwYjQ3MGU5NTFlZWRlM2ZmMWEwZjhkODllN2QwZDRjN2FiMmNlZjBk
10
+ MGIxNDNhOGY3YmRjYzUwMzY4MTAzZDQzNDE0ZTE0ZjVhZjgxNWI2NmY5YTU2
11
+ MjI1MDVhNmVmNTVkMGZjMGZiMzM0ZWNkNDgwZWQxZWFhODQwODg=
12
12
  data.tar.gz: !binary |-
13
- YzcyNDJlNTc1OWQxZDY3YjkzMThkNjZjMzk2YzhjN2Q4NzlmMzkxNzAwYWVh
14
- YWE1MDUzYWFmZDVjMzZmN2FhNjc2Mzc1OGVmOWI4YzkxMjQ4OWYxZGNhMzA1
15
- NDFhZmQ1YjVhYjI0MGNhOTU3NjJmMzEwYmZhNDFmYmYyZWJhMzY=
13
+ OGJmNTRiZjE3ZjUzYjE0ODFmNTg4ODY1YTllZGQ2MzQyYTVkMmQ3MjFjNGZl
14
+ ZGFhYzAyYWVjNGNkM2UxY2NiYjIyN2Y4OTRjZDZlODkxZWYwZmRiZWY3Nzkz
15
+ ZmIwNjJmZmY5MzFlOTg2YTc0OTRhYjRiODcyOGM1MGIzYTczNWY=
@@ -110,11 +110,9 @@ module CabooseRets
110
110
  # GET /admin/residential/:mls_acct/refresh
111
111
  def admin_refresh
112
112
  return if !user_is_allowed('properties', 'edit')
113
-
113
+
114
114
  p = ResidentialProperty.find(params[:mls_acct])
115
- p.delay.refresh_from_mls
116
- #RetsImporter.import("(MLS_ACCT=#{p.mls_acct})", 'Property', 'RES')
117
- #RetsImporter.download_property_images(p)
115
+ p.delay.refresh_from_mls
118
116
 
119
117
  resp = Caboose::StdClass.new
120
118
  resp.success = "The property's info is being updated from MLS. This may take a few minutes depending on how many images it has."
@@ -12,8 +12,8 @@ module CabooseRets
12
12
  def admin_import
13
13
  return if !user_is_allowed('properties', 'edit')
14
14
 
15
- mls_acct = params[:mls_acct].to_i
16
- ResidentialProperty.delay.import_from_mls(mls_acct)
15
+ mls_acct = params[:mls_acct].to_i
16
+ CabooseRets::RetsImporter.delay.import_property(mls_acct)
17
17
 
18
18
  resp = Caboose::StdClass.new
19
19
  resp.success = "The property is being imported from MLS. This may take a few minutes depending on how many images it has."
@@ -30,6 +30,16 @@ class CabooseRets::Agent < ActiveRecord::Base
30
30
  self.last_name[2] = self.last_name[2].upcase
31
31
  end
32
32
  end
33
+
34
+ def refresh_from_mls
35
+ CabooseRets::RetsImporter.import("(MLS_ACCT=#{self.mls_acct})", 'Property', 'RES')
36
+ CabooseRets::RetsImporter.download_property_images(self)
37
+ end
38
+
39
+ def self.refresh_from_mls(la_code)
40
+ CabooseRets::RetsImporter.import("(LA_LA_CODE=#{la_code})", 'Agent', 'AGT')
41
+ CabooseRets::RetsImporter.import_property(mls_acct)
42
+ end
33
43
 
34
44
  def parse(data)
35
45
  self.beeper_phone = data['LA_BEEPER_PHONE']
@@ -14,16 +14,11 @@ class CabooseRets::CommercialProperty < ActiveRecord::Base
14
14
  return media.url
15
15
  end
16
16
  def self.geolocatable() all(conditions: "latitude IS NOT NULL AND longitude IS NOT NULL") end
17
-
18
- def refresh_from_mls
19
- CabooseRets::RetsImporter.import("(MLS_ACCT=#{self.mls_acct})", 'Property', 'COM')
20
- CabooseRets::RetsImporter.download_property_images(self)
21
- end
22
17
 
23
- def self.import_from_mls(mls_acct)
24
- CabooseRets::RetsImporter.import_property(mls_acct)
18
+ def refresh_from_mls
19
+ CabooseRets::RetsImporter.import_commercial_property(self.mls_acct)
25
20
  end
26
-
21
+
27
22
  def parse(data)
28
23
  self.acreage = data['ACREAGE']
29
24
  self.adjoining_land_use = data['ADJOINING_LAND_USE']
@@ -15,13 +15,8 @@ class CabooseRets::LandProperty < ActiveRecord::Base
15
15
  end
16
16
  def self.geolocatable() all(conditions: "latitude IS NOT NULL AND longitude IS NOT NULL") end
17
17
 
18
- def refresh_from_mls
19
- CabooseRets::RetsImporter.import("(MLS_ACCT=#{self.mls_acct})", 'Property', 'LND')
20
- CabooseRets::RetsImporter.download_property_images(self)
21
- end
22
-
23
- def self.import_from_mls(mls_acct)
24
- CabooseRets::RetsImporter.import_property(mls_acct)
18
+ def refresh_from_mls
19
+ CabooseRets::RetsImporter.import_land_property(self.mls_acct)
25
20
  end
26
21
 
27
22
  def parse(data)
@@ -16,12 +16,7 @@ class CabooseRets::MultiFamilyProperty < ActiveRecord::Base
16
16
  def self.geolocatable() all(conditions: "latitude IS NOT NULL AND longitude IS NOT NULL") end
17
17
 
18
18
  def refresh_from_mls
19
- CabooseRets::RetsImporter.import("(MLS_ACCT=#{self.mls_acct})", 'Property', 'MUL')
20
- CabooseRets::RetsImporter.download_property_images(self)
21
- end
22
-
23
- def self.import_from_mls(mls_acct)
24
- CabooseRets::RetsImporter.import_property(mls_acct)
19
+ CabooseRets::RetsImporter.import_multi_family_property(self.mls_acct)
25
20
  end
26
21
 
27
22
  def parse(data)
@@ -1,6 +1,13 @@
1
1
 
2
2
  class CabooseRets::Office < ActiveRecord::Base
3
3
  self.table_name = "rets_offices"
4
+ has_attached_file :image,
5
+ :path => 'rets/offices/:lo_code_:style.:extension',
6
+ :styles => {
7
+ :thumb => '100x150>',
8
+ :large => '200x300>'
9
+ }
10
+ do_not_validate_attachment_file_type :image
4
11
  attr_accessible :id, :name, :lo_code
5
12
 
6
13
  def parse(data)
@@ -16,14 +16,9 @@ class CabooseRets::ResidentialProperty < ActiveRecord::Base
16
16
  def self.geolocatable() all(conditions: "latitude IS NOT NULL AND longitude IS NOT NULL") end
17
17
 
18
18
  def refresh_from_mls
19
- CabooseRets::RetsImporter.import("(MLS_ACCT=#{self.mls_acct})", 'Property', 'RES')
20
- CabooseRets::RetsImporter.download_property_images(self)
19
+ CabooseRets::RetsImporter.import_residential_property(self.mls_acct)
21
20
  end
22
-
23
- def self.import_from_mls(mls_acct)
24
- CabooseRets::RetsImporter.import_property(mls_acct)
25
- end
26
-
21
+
27
22
  #=============================================================================
28
23
 
29
24
  # Assume this is running in a worker dyno
@@ -8,41 +8,7 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base
8
8
 
9
9
  @@rets_client = nil
10
10
  @@config = nil
11
- @@object_types = {
12
- 'OpenHouse' => ['OPH'],
13
- 'Media' => ['GFX'],
14
- 'Property' => ['COM', 'LND', 'MUL', 'RES'],
15
- 'Agent' => ['AGT'],
16
- 'Office' => ['OFF']
17
- }
18
- @@key_fields = {
19
- 'OpenHouse' => 'ID',
20
- 'Media' => 'MEDIA_ID',
21
- 'Property' => 'MLS_ACCT',
22
- 'Agent' => 'LA_LA_CODE',
23
- 'Office' => 'LO_LO_CODE'
24
- }
25
- @@models = {
26
- 'OPH' => 'CabooseRets::OpenHouse',
27
- 'GFX' => 'CabooseRets::Media',
28
- 'COM' => 'CabooseRets::CommercialProperty',
29
- 'LND' => 'CabooseRets::LandProperty',
30
- 'MUL' => 'CabooseRets::MultiFamilyProperty',
31
- 'RES' => 'CabooseRets::ResidentialProperty',
32
- 'AGT' => 'CabooseRets::Agent',
33
- 'OFF' => 'CabooseRets::Office'
34
- }
35
- @@date_modified_fields = {
36
- 'OPH' => 'DATE_MODIFIED',
37
- 'GFX' => 'DATE_MODIFIED',
38
- 'COM' => 'DATE_MODIFIED',
39
- 'LND' => 'DATE_MODIFIED',
40
- 'MUL' => 'DATE_MODIFIED',
41
- 'RES' => 'DATE_MODIFIED',
42
- 'AGT' => 'LA_DATE_MODIFIED',
43
- 'OFF' => 'LO_DATE_MODIFIED'
44
- }
45
-
11
+
46
12
  def self.config
47
13
  return @@config
48
14
  end
@@ -52,8 +18,6 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base
52
18
  'url' => nil, # URL to the RETS login
53
19
  'username' => nil,
54
20
  'password' => nil,
55
- 'limit' => nil, # How many records to limit per request
56
- 'days_per_batch' => nil, # When performing a large property import, how many days to search on per batch
57
21
  'temp_path' => nil,
58
22
  'log_file' => nil,
59
23
  'media_base_url' => nil
@@ -77,37 +41,83 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base
77
41
  end
78
42
 
79
43
  #=============================================================================
80
- # Main updater
44
+ # Import method
81
45
  #=============================================================================
82
46
 
83
- def self.update_after(date_modified)
84
- self.update_data_after(date_modified)
85
- self.update_images_after(date_modified)
86
- end
87
-
88
- def self.update_data_after(date_modified)
89
- self.get_config if @@config.nil? || @@config['url'].nil?
90
- self.import_modified_after(date_modified, 'Agent' , 'AGT')
91
- self.import_modified_after(date_modified, 'Office' , 'OFF')
92
- self.import_modified_after(date_modified, 'OpenHouse' , 'OPH')
93
- #self.import_modified_after(date_modified, 'Property' , 'COM')
94
- self.import_modified_after(date_modified, 'Property' , 'LND')
95
- self.import_modified_after(date_modified, 'Property' , 'MUL')
96
- self.import_modified_after(date_modified, 'Property' , 'RES')
47
+ def self.import(query, search_type, class_type)
48
+ self.log("Importing #{search_type}:#{class_type} with query #{query}...")
49
+ self.get_config if @@config.nil? || @@config['url'].nil?
50
+ params = {
51
+ :search_type => search_type,
52
+ :class => class_type,
53
+ :query => query,
54
+ :limit => -1,
55
+ :timeout => -1
56
+ }
57
+ obj = nil
58
+ self.client.search(params) do |data|
59
+ obj = self.get_instance_with_id(class_type, data)
60
+ if obj.nil?
61
+ self.log("Error: object is nil")
62
+ self.log(data.inspect)
63
+ next
64
+ end
65
+ obj.parse(data)
66
+ obj.save
67
+ end
97
68
  end
98
69
 
99
- def self.update_images_after(date_modified)
100
- self.get_config if @@config.nil? || @@config['url'].nil?
101
- self.download_agent_images_modified_after(date_modified)
102
- self.download_property_images_modified_after(date_modified)
70
+ def self.get_instance_with_id(class_type, data)
71
+ obj = nil
72
+ m = case class_type
73
+ when 'OPH' then CabooseRets::OpenHouse
74
+ when 'GFX' then CabooseRets::Media
75
+ when 'COM' then CabooseRets::CommercialProperty
76
+ when 'LND' then CabooseRets::LandProperty
77
+ when 'MUL' then CabooseRets::MultiFamilyProperty
78
+ when 'RES' then CabooseRets::ResidentialProperty
79
+ when 'AGT' then CabooseRets::Agent
80
+ when 'OFF' then CabooseRets::Office
81
+ end
82
+ obj = case class_type
83
+ when 'OPH' then m.where(:id => data['ID'].to_i ).exists? ? m.where(:id => data['ID'].to_i ).first : m.new(:id => data['ID'].to_i )
84
+ when 'GFX' then m.where(:media_id => data['MEDIA_ID'] ).exists? ? m.where(:media_id => data['MEDIA_ID'] ).first : m.new(:media_id => data['MEDIA_ID'] )
85
+ when 'COM' then m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
86
+ when 'LND' then m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
87
+ when 'MUL' then m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
88
+ when 'RES' then m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
89
+ when 'AGT' then m.where(:la_code => data['LA_LA_CODE'] ).exists? ? m.where(:la_code => data['LA_LA_CODE'] ).first : m.new(:la_code => data['LA_LA_CODE'] )
90
+ when 'OFF' then m.where(:lo_code => data['LO_LO_CODE'] ).exists? ? m.where(:lo_code => data['LO_LO_CODE'] ).first : m.new(:lo_code => data['LO_LO_CODE'] )
91
+ end
92
+ return obj
103
93
  end
104
94
 
105
95
  #=============================================================================
106
- # Data
96
+ # Main updater
107
97
  #=============================================================================
108
-
109
- def self.import_property(mls_acct)
98
+
99
+ def self.update_after(date_modified)
100
+ self.update_residential_properties_modified_after(date_modified)
101
+ self.update_commercial_properties_modified_after(date_modified)
102
+ self.update_land_properties_modified_after(date_modified)
103
+ self.update_multi_family_properties_modified_after(date_modified)
104
+ self.update_offices_modified_after(date_modified)
105
+ self.update_agents_modified_after(date_modified)
106
+ self.update_open_houses_modified_after(date_modified)
107
+ end
108
+ def self.update_residential_properties_modified_after(date_modified) self.client.search({ :search_type => 'Property' , :class => 'RES', :select => ['MLS_ACCT'] , :query => "(DATE_MODIFIED=#{date_modified.strftime("%FT%T")}+)" , :standard_names_only => true, :timeout => -1 }) { |data| self.delay.import_residential_property data['MLS_ACCT' ] } end
109
+ def self.update_commercial_properties_modified_after(date_modified) self.client.search({ :search_type => 'Property' , :class => 'COM', :select => ['MLS_ACCT'] , :query => "(DATE_MODIFIED=#{date_modified.strftime("%FT%T")}+)" , :standard_names_only => true, :timeout => -1 }) { |data| self.delay.import_commercial_property data['MLS_ACCT' ] } end
110
+ def self.update_land_properties_modified_after(date_modified) self.client.search({ :search_type => 'Property' , :class => 'LND', :select => ['MLS_ACCT'] , :query => "(DATE_MODIFIED=#{date_modified.strftime("%FT%T")}+)" , :standard_names_only => true, :timeout => -1 }) { |data| self.delay.import_land_property data['MLS_ACCT' ] } end
111
+ def self.update_multi_family_properties_modified_after(date_modified) self.client.search({ :search_type => 'Property' , :class => 'MUL', :select => ['MLS_ACCT'] , :query => "(DATE_MODIFIED=#{date_modified.strftime("%FT%T")}+)" , :standard_names_only => true, :timeout => -1 }) { |data| self.delay.import_multi_family_property data['MLS_ACCT' ] } end
112
+ def self.update_offices_modified_after(date_modified) self.client.search({ :search_type => 'Office' , :class => 'OFF', :select => ['LO_LO_CODE'] , :query => "(LO_DATE_MODIFIED=#{date_modified.strftime("%FT%T")}+)", :standard_names_only => true, :timeout => -1 }) { |data| self.delay.import_office data['LO_LO_CODE'] } end
113
+ def self.update_agents_modified_after(date_modified) self.client.search({ :search_type => 'Agent' , :class => 'AGT', :select => ['LA_LA_CODE'] , :query => "(LA_DATE_MODIFIED=#{date_modified.strftime("%FT%T")}+)", :standard_names_only => true, :timeout => -1 }) { |data| self.delay.import_agent data['LA_LA_CODE'] } end
114
+ def self.update_open_houses_modified_after(date_modified) self.client.search({ :search_type => 'OpenHouse', :class => 'OPH', :select => ['ID'] , :query => "(DATE_MODIFIED=#{date_modified.strftime("%FT%T")}+)" , :standard_names_only => true, :timeout => -1 }) { |data| self.delay.import_open_house data['ID' ] } end
110
115
 
116
+ #=============================================================================
117
+ # Single model import methods (called from a worker dyno)
118
+ #=============================================================================
119
+
120
+ def self.import_property(mls_acct)
111
121
  self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'RES')
112
122
  p = CabooseRets::ResidentialProperty.where(:id => mls_acct.to_i).first
113
123
  if p.nil?
@@ -126,143 +136,53 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base
126
136
  self.download_property_images(p)
127
137
  end
128
138
 
129
- def self.import_modified_after(date_modified, search_type = nil, class_type = nil)
130
- self.get_config if @@config.nil? || @@config['url'].nil?
131
-
132
- d = date_modified
133
- date_modified_field = @@date_modified_fields[class_type]
134
-
135
- while d.strftime('%FT%T') <= DateTime.now.strftime('%FT%T') do
136
- break if d.nil?
137
-
138
- d2 = d.strftime('%FT%T')
139
- d2 << "-"
140
- d2 << (d+@@config['days_per_batch']).strftime('%FT%T')
141
-
142
- query = "(#{date_modified_field}=#{d2})"
143
- self.import(query, search_type, class_type)
144
-
145
- d = d + @@config['days_per_batch']
146
- end
139
+ def self.import_residential_property(mls_acct)
140
+ self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'RES')
141
+ p = CabooseRets::ResidentialProperty.where(:id => mls_acct.to_i).first
142
+ self.download_property_images(p)
143
+ self.update_coords(p)
147
144
  end
148
145
 
149
- def self.import(query, search_type, class_type)
150
- # See how many records we have
151
- self.client.search(
152
- :search_type => search_type,
153
- :class => class_type,
154
- :query => query,
155
- :count_mode => :only,
156
- :timeout => -1,
157
- )
158
- # Return if no records found
159
- if (self.client.rets_data[:code] == "20201")
160
- self.log "No #{search_type}:#{class_type} records found for query: #{query}"
161
- return
162
- else
163
- count = self.client.rets_data[:count]
164
- self.log "Importing #{count} #{search_type}:#{class_type} record" + (count == 1 ? "" : "s") + "..."
165
- end
166
-
167
- count = self.client.rets_data[:count]
168
- batch_count = (count.to_f/@@config['limit'].to_f).ceil
169
-
170
- (0...batch_count).each do |i|
171
- params = {
172
- :search_type => search_type,
173
- :class => class_type,
174
- :query => query,
175
- :limit => @@config['limit'],
176
- :offset => @@config['limit'] * i,
177
- :timeout => -1
178
- }
179
- obj = nil
180
- self.client.search(params) do |data|
181
- m = @@models[class_type]
182
- #key_field = @@key_fields[search_type]
183
- #id = data[key_field].to_i
184
- #obj = m.exists?(id) ? m.find(id) : m.new
185
- obj = self.get_instance_with_id(m, data)
186
- if obj.nil?
187
- puts "Error: object is nil"
188
- puts m.inspect
189
- puts data.inspect
190
- next
191
- end
192
- obj.parse(data)
193
- #obj.id = id
194
- obj.save
195
- end
196
-
197
- case obj
198
- when CabooseRets::CommercialProperty, CabooseRets::LandProperty, CabooseRets::MultiFamilyProperty, CabooseRets::ResidentialProperty
199
- self.update_coords(obj)
200
- end
201
- end
146
+ def self.import_commercial_property(mls_acct)
147
+ self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'COM')
148
+ p = CabooseRets::CommercialProperty.where(:id => mls_acct.to_i).first
149
+ self.download_property_images(p)
150
+ self.update_coords(p)
202
151
  end
203
152
 
204
- def self.get_instance_with_id(model, data)
205
- obj = nil
206
- m = model.constantize
207
- case model
208
- when 'CabooseRets::OpenHouse' then obj = m.where(:id => data['ID'].to_i ).exists? ? m.where(:id => data['ID'].to_i ).first : m.new(:id => data['ID'].to_i )
209
- when 'CabooseRets::Media' then obj = m.where(:media_id => data['MEDIA_ID'] ).exists? ? m.where(:media_id => data['MEDIA_ID'] ).first : m.new(:media_id => data['MEDIA_ID'] )
210
- when 'CabooseRets::CommercialProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
211
- when 'CabooseRets::LandProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
212
- when 'CabooseRets::MultiFamilyProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
213
- when 'CabooseRets::ResidentialProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
214
- when 'CabooseRets::Agent' then obj = m.where(:la_code => data['LA_LA_CODE'] ).exists? ? m.where(:la_code => data['LA_LA_CODE'] ).first : m.new(:la_code => data['LA_LA_CODE'] )
215
- when 'CabooseRets::Office' then obj = m.where(:lo_code => data['LO_LO_CODE'] ).exists? ? m.where(:lo_code => data['LO_LO_CODE'] ).first : m.new(:lo_code => data['LO_LO_CODE'] )
216
- end
217
- return obj
153
+ def self.import_land_property(mls_acct)
154
+ self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'LND')
155
+ p = CabooseRets::LandProperty.where(:id => mls_acct.to_i).first
156
+ self.download_property_images(p)
157
+ self.update_coords(p)
218
158
  end
219
159
 
220
- #=============================================================================
221
- # Agent Images
222
- #=============================================================================
160
+ def self.import_multi_family_property(mls_acct)
161
+ self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'MUL')
162
+ p = CabooseRets::MultiFamilyProperty.where(:id => mls_acct.to_i).first
163
+ self.download_property_images(p)
164
+ self.update_coords(p)
165
+ end
223
166
 
224
- def self.download_agent_images_modified_after(date_modified, agent = nil)
225
- if agent.nil?
226
- CabooseRets::Agent.where('photo_date_modified > ?', date_modified.strftime('%FT%T')).reorder('last_name, first_name').all.each do |a|
227
- self.download_agent_images_modified_after(date_modified, a)
228
- end
229
- return
230
- end
231
- self.download_agent_images(agent)
167
+ def self.import_office(lo_code)
168
+ self.import("(LO_LO_CODE=*#{lo_code}*)", 'Office', 'OFF')
169
+ office = CabooseRets::Office.where(:lo_code => lo_code.to_s).first
170
+ self.download_office_image(office)
232
171
  end
233
172
 
234
- def self.download_agent_images(agent)
235
- a = agent
236
- self.log "Saving image for #{a.first_name} #{a.last_name}..."
237
- begin
238
- self.client.get_object(:resource => :Agent, :type => :Photo, :location => true, :id => a.la_code) do |headers, content|
239
- a.image = URI.parse(headers['location'])
240
- a.save
241
- end
242
- rescue RETS::APIError => err
243
- self.log "No image for #{a.first_name} #{a.last_name}."
244
- end
173
+ def self.import_agent(la_code)
174
+ self.import("(LA_LA_CODE=*#{la_code}*)", 'Agent', 'AGT')
175
+ a = CabooseRets::Agent.where(:la_code => la_code.to_s).first
176
+ self.download_agent_image(a)
245
177
  end
246
178
 
179
+ def self.import_open_house(id)
180
+ self.import("(ID=*#{id}*)", 'OpenHouse', 'OPH')
181
+ end
182
+
247
183
  #=============================================================================
248
- # Property Images
184
+ # Images
249
185
  #=============================================================================
250
-
251
- def self.download_property_images_modified_after(date_modified)
252
- models = [CabooseRets::CommercialProperty, CabooseRets::LandProperty, CabooseRets::MultiFamilyProperty, CabooseRets::ResidentialProperty]
253
- names = ["commercial", "land", "multi-family", "residential"]
254
- i = 0
255
- models.each do |model|
256
- count = model.where("photo_date_modified > ?", date_modified.strftime('%FT%T')).count
257
- j = 1
258
- model.where("photo_date_modified > ?", date_modified.strftime('%FT%T')).reorder(:mls_acct).each do |p|
259
- self.log("Downloading images for #{j} of #{count} #{names[i]} properties...")
260
- self.download_property_images(p)
261
- j = j + 1
262
- end
263
- i = i + 1
264
- end
265
- end
266
186
 
267
187
  def self.download_property_images(p)
268
188
  self.refresh_property_media(p)
@@ -311,115 +231,29 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base
311
231
  end
312
232
  end
313
233
 
314
- def self.refresh_all_virtual_tours
315
- # See how many records we have
316
- self.client.search(
317
- :search_type => 'Media',
318
- :class => 'GFX',
319
- :query => "(MEDIA_TYPE=|V)",
320
- :count_mode => :only,
321
- :timeout => -1
322
- )
323
- # Return if no records found
324
- if (self.client.rets_data[:code] == "20201")
325
- self.log "No virtual tours found."
326
- return
327
- else
328
- count = self.client.rets_data[:count]
329
- self.log "Importing #{count} virtual tours..."
330
- end
331
-
332
- count = self.client.rets_data[:count]
333
- batch_count = (count.to_f/@@config['limit'].to_f).ceil
334
-
335
- (0...batch_count).each do |i|
336
- params = {
337
- :search_type => 'Media',
338
- :class => 'GFX',
339
- :query => "(MEDIA_TYPE=|V)",
340
- :limit => @@config['limit'],
341
- :offset => @@config['limit'] * i,
342
- :timeout => -1
343
- }
344
- obj = nil
345
- self.client.search(params) do |data|
346
- mls_acct = data['MLS_ACCT'].to_i
347
- m = CabooseRets::Media.exists?("mls_acct = '#{mls_acct}' and media_type = 'Virtual Tour'") ? CabooseRets::Media.where("mls_acct = '#{mls_acct}' and media_type = 'Virtual Tour'").first : CabooseRets::Media.new
348
- m.parse(data)
349
- m.save
350
- end
351
- end
234
+ def self.download_agent_image(agent)
235
+ self.log "Saving image for #{agent.first_name} #{agent.last_name}..."
236
+ begin
237
+ self.client.get_object(:resource => :Agent, :type => :Photo, :location => true, :id => agent.la_code) do |headers, content|
238
+ agent.image = URI.parse(headers['location'])
239
+ agent.save
240
+ end
241
+ rescue RETS::APIError => err
242
+ self.log "No image for #{agent.first_name} #{agent.last_name}."
243
+ end
352
244
  end
353
245
 
354
- def self.refresh_virtual_tours(p)
355
- self.log("-- Deleting images and metadata for #{p.mls_acct}...")
356
- CabooseRets::Media.where(:mls_acct => p.mls_acct, :media_type => 'Photo').destroy_all
357
-
358
- self.log("-- Downloading image metadata for #{p.mls_acct}...")
359
- params = {
360
- :search_type => 'Media',
361
- :class => 'GFX',
362
- #:query => "(MLS_ACCT=*#{p.id}*),(MEDIA_TYPE=|I)",
363
- :query => "(MLS_ACCT=*#{p.id}*)",
364
- :timeout => -1
365
- }
366
- self.client.search(params) do |data|
367
- m = CabooseRets::Media.new
368
- m.parse(data)
369
- #m.id = m.media_id
370
- m.save
371
- end
246
+ def self.download_office_image(office)
247
+ self.log "Saving image for #{office.lo_name}..."
248
+ begin
249
+ self.client.get_object(:resource => :Office, :type => :Photo, :location => true, :id => office.lo_code) do |headers, content|
250
+ office.image = URI.parse(headers['location'])
251
+ office.save
252
+ end
253
+ rescue RETS::APIError => err
254
+ self.log "No image for #{office.lo_name}."
255
+ end
372
256
  end
373
-
374
- #def self.download_property_images(p)
375
- #
376
- # self.log("-- Deleting images and metadata for #{p.mls_acct}...")
377
- # CabooseRets::Media.where(:mls_acct => p.mls_acct, :media_type => 'Photo').destroy_all
378
- #
379
- # self.log("-- Downloading image metadata for #{p.mls_acct}...")
380
- # params = {
381
- # :search_type => 'Media',
382
- # :class => 'GFX',
383
- # :query => "(MLS_ACCT=*#{p.id}*),(MEDIA_TYPE=|I)",
384
- # :timeout => -1
385
- # }
386
- # puts "Before search #{p.id}"
387
- # self.client.search(params) do |data|
388
- # puts "download_property_images self.client.search #{p.id}"
389
- # #m = CabooseRets::Media.new
390
- # #m.parse(data)
391
- # #m.id = m.media_id
392
- # #m.save
393
- # self.download_property_images2(p)
394
- # end
395
- # puts "After search #{p.id}"
396
- #end
397
- #
398
- #def self.download_property_images2(p)
399
- # puts "download_property_images2 #{p.id}"
400
- # sleep(1)
401
- #
402
- # #self.log("-- Downloading images and resizing for #{p.mls_acct}")
403
- # #media = []
404
- # #self.client.get_object(:resource => :Property, :type => :Photo, :location => true, :id => p.id) do |headers, content|
405
- # #
406
- # ## Find the associated media record for the image
407
- # #filename = File.basename(headers['location'])
408
- # #m = CabooseRets::Media.where(:mls_acct => p.mls_acct, :file_name => filename).first
409
- # #
410
- # #if m.nil?
411
- # # self.log("Can't find media record for #{p.mls_acct} #{filename}.")
412
- # #else
413
- # # m.image = URI.parse(headers['location'])
414
- # # media << m
415
- # # #m.save
416
- # #end
417
- # #
418
- # #self.log("-- Uploading images to S3 for #{p.mls_acct}")
419
- # #media.each do |m|
420
- # # m.save
421
- # #end
422
- #end
423
257
 
424
258
  #=============================================================================
425
259
  # GPS
@@ -0,0 +1,512 @@
1
+ require 'ruby-rets'
2
+ require 'httparty'
3
+ require 'json'
4
+
5
+ # http://rets.solidearth.com/ClientHome.aspx
6
+
7
+ class CabooseRets::RetsImporter # < ActiveRecord::Base
8
+
9
+ @@rets_client = nil
10
+ @@config = nil
11
+ @@object_types = {
12
+ 'OpenHouse' => ['OPH'],
13
+ 'Media' => ['GFX'],
14
+ 'Property' => ['COM', 'LND', 'MUL', 'RES'],
15
+ 'Agent' => ['AGT'],
16
+ 'Office' => ['OFF']
17
+ }
18
+ @@key_fields = {
19
+ 'OpenHouse' => 'ID',
20
+ 'Media' => 'MEDIA_ID',
21
+ 'Property' => 'MLS_ACCT',
22
+ 'Agent' => 'LA_LA_CODE',
23
+ 'Office' => 'LO_LO_CODE'
24
+ }
25
+ @@models = {
26
+ 'OPH' => 'CabooseRets::OpenHouse',
27
+ 'GFX' => 'CabooseRets::Media',
28
+ 'COM' => 'CabooseRets::CommercialProperty',
29
+ 'LND' => 'CabooseRets::LandProperty',
30
+ 'MUL' => 'CabooseRets::MultiFamilyProperty',
31
+ 'RES' => 'CabooseRets::ResidentialProperty',
32
+ 'AGT' => 'CabooseRets::Agent',
33
+ 'OFF' => 'CabooseRets::Office'
34
+ }
35
+ @@date_modified_fields = {
36
+ 'OPH' => 'DATE_MODIFIED',
37
+ 'GFX' => 'DATE_MODIFIED',
38
+ 'COM' => 'DATE_MODIFIED',
39
+ 'LND' => 'DATE_MODIFIED',
40
+ 'MUL' => 'DATE_MODIFIED',
41
+ 'RES' => 'DATE_MODIFIED',
42
+ 'AGT' => 'LA_DATE_MODIFIED',
43
+ 'OFF' => 'LO_DATE_MODIFIED'
44
+ }
45
+
46
+ def self.config
47
+ return @@config
48
+ end
49
+
50
+ def self.get_config
51
+ @@config = {
52
+ 'url' => nil, # URL to the RETS login
53
+ 'username' => nil,
54
+ 'password' => nil,
55
+ 'limit' => nil, # How many records to limit per request
56
+ 'days_per_batch' => nil, # When performing a large property import, how many days to search on per batch
57
+ 'temp_path' => nil,
58
+ 'log_file' => nil,
59
+ 'media_base_url' => nil
60
+ }
61
+ config = YAML::load(File.open("#{Rails.root}/config/rets_importer.yml"))
62
+ config = config[Rails.env]
63
+ config.each { |key,val| @@config[key] = val }
64
+ end
65
+
66
+ def self.client
67
+ self.get_config if @@config.nil? || @@config['url'].nil?
68
+
69
+ if (@@rets_client.nil?)
70
+ @@rets_client = RETS::Client.login(
71
+ :url => @@config['url'],
72
+ :username => @@config['username'],
73
+ :password => @@config['password']
74
+ )
75
+ end
76
+ return @@rets_client
77
+ end
78
+
79
+ #=============================================================================
80
+ # Main updater
81
+ #=============================================================================
82
+
83
+ def self.update_after(date_modified)
84
+ self.update_data_after(date_modified)
85
+ self.update_images_after(date_modified)
86
+ end
87
+
88
+ def self.update_data_after(date_modified)
89
+ self.get_config if @@config.nil? || @@config['url'].nil?
90
+ self.import_modified_after(date_modified, 'Agent' , 'AGT')
91
+ self.import_modified_after(date_modified, 'Office' , 'OFF')
92
+ self.import_modified_after(date_modified, 'OpenHouse' , 'OPH')
93
+ #self.import_modified_after(date_modified, 'Property' , 'COM')
94
+ self.import_modified_after(date_modified, 'Property' , 'LND')
95
+ self.import_modified_after(date_modified, 'Property' , 'MUL')
96
+ self.import_modified_after(date_modified, 'Property' , 'RES')
97
+ end
98
+
99
+ def self.update_images_after(date_modified)
100
+ self.get_config if @@config.nil? || @@config['url'].nil?
101
+ self.download_agent_images_modified_after(date_modified)
102
+ self.download_property_images_modified_after(date_modified)
103
+ end
104
+
105
+ #=============================================================================
106
+ # Data
107
+ #=============================================================================
108
+
109
+ def self.import_property(mls_acct)
110
+
111
+ self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'RES')
112
+ p = CabooseRets::ResidentialProperty.where(:id => mls_acct.to_i).first
113
+ if p.nil?
114
+ self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'COM')
115
+ p = CabooseRets::CommercialProperty.where(:id => mls_acct.to_i).first
116
+ if p.nil?
117
+ self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'LND')
118
+ p = CabooseRets::LandProperty.where(:id => mls_acct.to_i).first
119
+ if p.nil?
120
+ self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'MUL')
121
+ p = CabooseRets::MultiFamilyProperty.where(:id => mls_acct.to_i).first
122
+ return if p.nil?
123
+ end
124
+ end
125
+ end
126
+ self.download_property_images(p)
127
+ end
128
+
129
+ def self.import_modified_after(date_modified, search_type = nil, class_type = nil)
130
+ self.get_config if @@config.nil? || @@config['url'].nil?
131
+
132
+ d = date_modified
133
+ date_modified_field = @@date_modified_fields[class_type]
134
+
135
+ while d.strftime('%FT%T') <= DateTime.now.strftime('%FT%T') do
136
+ break if d.nil?
137
+
138
+ d2 = d.strftime('%FT%T')
139
+ d2 << "-"
140
+ d2 << (d+@@config['days_per_batch']).strftime('%FT%T')
141
+
142
+ query = "(#{date_modified_field}=#{d2})"
143
+ self.import(query, search_type, class_type)
144
+
145
+ d = d + @@config['days_per_batch']
146
+ end
147
+ end
148
+
149
+ def self.import(query, search_type, class_type)
150
+ # See how many records we have
151
+ self.client.search(
152
+ :search_type => search_type,
153
+ :class => class_type,
154
+ :query => query,
155
+ :count_mode => :only,
156
+ :timeout => -1,
157
+ )
158
+ # Return if no records found
159
+ if (self.client.rets_data[:code] == "20201")
160
+ self.log "No #{search_type}:#{class_type} records found for query: #{query}"
161
+ return
162
+ else
163
+ count = self.client.rets_data[:count]
164
+ self.log "Importing #{count} #{search_type}:#{class_type} record" + (count == 1 ? "" : "s") + "..."
165
+ end
166
+
167
+ count = self.client.rets_data[:count]
168
+ batch_count = (count.to_f/@@config['limit'].to_f).ceil
169
+
170
+ (0...batch_count).each do |i|
171
+ params = {
172
+ :search_type => search_type,
173
+ :class => class_type,
174
+ :query => query,
175
+ :limit => @@config['limit'],
176
+ :offset => @@config['limit'] * i,
177
+ :timeout => -1
178
+ }
179
+ obj = nil
180
+ self.client.search(params) do |data|
181
+ m = @@models[class_type]
182
+ #key_field = @@key_fields[search_type]
183
+ #id = data[key_field].to_i
184
+ #obj = m.exists?(id) ? m.find(id) : m.new
185
+ obj = self.get_instance_with_id(m, data)
186
+ if obj.nil?
187
+ puts "Error: object is nil"
188
+ puts m.inspect
189
+ puts data.inspect
190
+ next
191
+ end
192
+ obj.parse(data)
193
+ #obj.id = id
194
+ obj.save
195
+ end
196
+
197
+ case obj
198
+ when CabooseRets::CommercialProperty, CabooseRets::LandProperty, CabooseRets::MultiFamilyProperty, CabooseRets::ResidentialProperty
199
+ self.update_coords(obj)
200
+ end
201
+ end
202
+ end
203
+
204
+ def self.get_instance_with_id(model, data)
205
+ obj = nil
206
+ m = model.constantize
207
+ case model
208
+ when 'CabooseRets::OpenHouse' then obj = m.where(:id => data['ID'].to_i ).exists? ? m.where(:id => data['ID'].to_i ).first : m.new(:id => data['ID'].to_i )
209
+ when 'CabooseRets::Media' then obj = m.where(:media_id => data['MEDIA_ID'] ).exists? ? m.where(:media_id => data['MEDIA_ID'] ).first : m.new(:media_id => data['MEDIA_ID'] )
210
+ when 'CabooseRets::CommercialProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
211
+ when 'CabooseRets::LandProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
212
+ when 'CabooseRets::MultiFamilyProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
213
+ when 'CabooseRets::ResidentialProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
214
+ when 'CabooseRets::Agent' then obj = m.where(:la_code => data['LA_LA_CODE'] ).exists? ? m.where(:la_code => data['LA_LA_CODE'] ).first : m.new(:la_code => data['LA_LA_CODE'] )
215
+ when 'CabooseRets::Office' then obj = m.where(:lo_code => data['LO_LO_CODE'] ).exists? ? m.where(:lo_code => data['LO_LO_CODE'] ).first : m.new(:lo_code => data['LO_LO_CODE'] )
216
+ end
217
+ return obj
218
+ end
219
+
220
+ #=============================================================================
221
+ # Agent Images
222
+ #=============================================================================
223
+
224
+ def self.download_agent_images_modified_after(date_modified, agent = nil)
225
+ if agent.nil?
226
+ CabooseRets::Agent.where('photo_date_modified > ?', date_modified.strftime('%FT%T')).reorder('last_name, first_name').all.each do |a|
227
+ self.download_agent_images_modified_after(date_modified, a)
228
+ end
229
+ return
230
+ end
231
+ self.download_agent_images(agent)
232
+ end
233
+
234
+ def self.download_agent_images(agent)
235
+ a = agent
236
+ self.log "Saving image for #{a.first_name} #{a.last_name}..."
237
+ begin
238
+ self.client.get_object(:resource => :Agent, :type => :Photo, :location => true, :id => a.la_code) do |headers, content|
239
+ a.image = URI.parse(headers['location'])
240
+ a.save
241
+ end
242
+ rescue RETS::APIError => err
243
+ self.log "No image for #{a.first_name} #{a.last_name}."
244
+ end
245
+ end
246
+
247
+ #=============================================================================
248
+ # Property Images
249
+ #=============================================================================
250
+
251
+ def self.download_property_images_modified_after(date_modified)
252
+ models = [CabooseRets::CommercialProperty, CabooseRets::LandProperty, CabooseRets::MultiFamilyProperty, CabooseRets::ResidentialProperty]
253
+ names = ["commercial", "land", "multi-family", "residential"]
254
+ i = 0
255
+ models.each do |model|
256
+ count = model.where("photo_date_modified > ?", date_modified.strftime('%FT%T')).count
257
+ j = 1
258
+ model.where("photo_date_modified > ?", date_modified.strftime('%FT%T')).reorder(:mls_acct).each do |p|
259
+ self.log("Downloading images for #{j} of #{count} #{names[i]} properties...")
260
+ self.download_property_images(p)
261
+ j = j + 1
262
+ end
263
+ i = i + 1
264
+ end
265
+ end
266
+
267
+ def self.download_property_images(p)
268
+ self.refresh_property_media(p)
269
+
270
+ self.log("-- Downloading images and resizing for #{p.mls_acct}")
271
+ media = []
272
+ self.client.get_object(:resource => :Property, :type => :Photo, :location => true, :id => p.id) do |headers, content|
273
+
274
+ # Find the associated media record for the image
275
+ filename = File.basename(headers['location'])
276
+ m = CabooseRets::Media.where(:mls_acct => p.mls_acct, :file_name => filename).first
277
+
278
+ if m.nil?
279
+ self.log("Can't find media record for #{p.mls_acct} #{filename}.")
280
+ else
281
+ m.image = URI.parse(headers['location'])
282
+ media << m
283
+ #m.save
284
+ end
285
+ end
286
+
287
+ self.log("-- Uploading images to S3 for #{p.mls_acct}")
288
+ media.each do |m|
289
+ m.save
290
+ end
291
+ end
292
+
293
+ def self.refresh_property_media(p)
294
+ self.log("-- Deleting images and metadata for #{p.mls_acct}...")
295
+ #CabooseRets::Media.where(:mls_acct => p.mls_acct, :media_type => 'Photo').destroy_all
296
+ CabooseRets::Media.where(:mls_acct => p.mls_acct).destroy_all
297
+
298
+ self.log("-- Downloading image metadata for #{p.mls_acct}...")
299
+ params = {
300
+ :search_type => 'Media',
301
+ :class => 'GFX',
302
+ #:query => "(MLS_ACCT=*#{p.id}*),(MEDIA_TYPE=|I)",
303
+ :query => "(MLS_ACCT=*#{p.id}*)",
304
+ :timeout => -1
305
+ }
306
+ self.client.search(params) do |data|
307
+ m = CabooseRets::Media.new
308
+ m.parse(data)
309
+ #m.id = m.media_id
310
+ m.save
311
+ end
312
+ end
313
+
314
+ def self.refresh_all_virtual_tours
315
+ # See how many records we have
316
+ self.client.search(
317
+ :search_type => 'Media',
318
+ :class => 'GFX',
319
+ :query => "(MEDIA_TYPE=|V)",
320
+ :count_mode => :only,
321
+ :timeout => -1
322
+ )
323
+ # Return if no records found
324
+ if (self.client.rets_data[:code] == "20201")
325
+ self.log "No virtual tours found."
326
+ return
327
+ else
328
+ count = self.client.rets_data[:count]
329
+ self.log "Importing #{count} virtual tours..."
330
+ end
331
+
332
+ count = self.client.rets_data[:count]
333
+ batch_count = (count.to_f/@@config['limit'].to_f).ceil
334
+
335
+ (0...batch_count).each do |i|
336
+ params = {
337
+ :search_type => 'Media',
338
+ :class => 'GFX',
339
+ :query => "(MEDIA_TYPE=|V)",
340
+ :limit => @@config['limit'],
341
+ :offset => @@config['limit'] * i,
342
+ :timeout => -1
343
+ }
344
+ obj = nil
345
+ self.client.search(params) do |data|
346
+ mls_acct = data['MLS_ACCT'].to_i
347
+ m = CabooseRets::Media.exists?("mls_acct = '#{mls_acct}' and media_type = 'Virtual Tour'") ? CabooseRets::Media.where("mls_acct = '#{mls_acct}' and media_type = 'Virtual Tour'").first : CabooseRets::Media.new
348
+ m.parse(data)
349
+ m.save
350
+ end
351
+ end
352
+ end
353
+
354
+ def self.refresh_virtual_tours(p)
355
+ self.log("-- Deleting images and metadata for #{p.mls_acct}...")
356
+ CabooseRets::Media.where(:mls_acct => p.mls_acct, :media_type => 'Photo').destroy_all
357
+
358
+ self.log("-- Downloading image metadata for #{p.mls_acct}...")
359
+ params = {
360
+ :search_type => 'Media',
361
+ :class => 'GFX',
362
+ #:query => "(MLS_ACCT=*#{p.id}*),(MEDIA_TYPE=|I)",
363
+ :query => "(MLS_ACCT=*#{p.id}*)",
364
+ :timeout => -1
365
+ }
366
+ self.client.search(params) do |data|
367
+ m = CabooseRets::Media.new
368
+ m.parse(data)
369
+ #m.id = m.media_id
370
+ m.save
371
+ end
372
+ end
373
+
374
+ #def self.download_property_images(p)
375
+ #
376
+ # self.log("-- Deleting images and metadata for #{p.mls_acct}...")
377
+ # CabooseRets::Media.where(:mls_acct => p.mls_acct, :media_type => 'Photo').destroy_all
378
+ #
379
+ # self.log("-- Downloading image metadata for #{p.mls_acct}...")
380
+ # params = {
381
+ # :search_type => 'Media',
382
+ # :class => 'GFX',
383
+ # :query => "(MLS_ACCT=*#{p.id}*),(MEDIA_TYPE=|I)",
384
+ # :timeout => -1
385
+ # }
386
+ # puts "Before search #{p.id}"
387
+ # self.client.search(params) do |data|
388
+ # puts "download_property_images self.client.search #{p.id}"
389
+ # #m = CabooseRets::Media.new
390
+ # #m.parse(data)
391
+ # #m.id = m.media_id
392
+ # #m.save
393
+ # self.download_property_images2(p)
394
+ # end
395
+ # puts "After search #{p.id}"
396
+ #end
397
+ #
398
+ #def self.download_property_images2(p)
399
+ # puts "download_property_images2 #{p.id}"
400
+ # sleep(1)
401
+ #
402
+ # #self.log("-- Downloading images and resizing for #{p.mls_acct}")
403
+ # #media = []
404
+ # #self.client.get_object(:resource => :Property, :type => :Photo, :location => true, :id => p.id) do |headers, content|
405
+ # #
406
+ # ## Find the associated media record for the image
407
+ # #filename = File.basename(headers['location'])
408
+ # #m = CabooseRets::Media.where(:mls_acct => p.mls_acct, :file_name => filename).first
409
+ # #
410
+ # #if m.nil?
411
+ # # self.log("Can't find media record for #{p.mls_acct} #{filename}.")
412
+ # #else
413
+ # # m.image = URI.parse(headers['location'])
414
+ # # media << m
415
+ # # #m.save
416
+ # #end
417
+ # #
418
+ # #self.log("-- Uploading images to S3 for #{p.mls_acct}")
419
+ # #media.each do |m|
420
+ # # m.save
421
+ # #end
422
+ #end
423
+
424
+ #=============================================================================
425
+ # GPS
426
+ #=============================================================================
427
+
428
+ def self.update_coords(p = nil)
429
+ if p.nil?
430
+ models = [CabooseRets::CommercialProperty, CabooseRets::LandProperty, CabooseRets::MultiFamilyProperty, CabooseRets::ResidentialProperty]
431
+ names = ["commercial", "land", "multi-family", "residential"]
432
+ i = 0
433
+ models.each do |model|
434
+ self.log "Updating coords #{names[i]} properties..."
435
+ model.where(:latitude => nil).reorder(:mls_acct).each do |p|
436
+ self.update_coords(p)
437
+ end
438
+ i = i + 1
439
+ end
440
+ return
441
+ end
442
+
443
+ self.log "Getting coords for mls_acct #{p.mls_acct}..."
444
+ coords = self.coords_from_address(CGI::escape "#{p.street_num} #{p.street_name}, #{p.city}, #{p.state} #{p.zip}")
445
+ return if coords.nil? || coords == false
446
+
447
+ p.latitude = coords['lat']
448
+ p.longitude = coords['lng']
449
+ p.save
450
+ end
451
+
452
+ def self.coords_from_address(address)
453
+ begin
454
+ uri = "https://maps.googleapis.com/maps/api/geocode/json?address=#{address}&sensor=false"
455
+ uri.gsub!(" ", "+")
456
+ resp = HTTParty.get(uri)
457
+ json = JSON.parse(resp.body)
458
+ return json['results'][0]['geometry']['location']
459
+ rescue
460
+ self.log "Error: #{uri}"
461
+ sleep(2)
462
+ return false
463
+ end
464
+ end
465
+
466
+ #=============================================================================
467
+ # Logging
468
+ #=============================================================================
469
+
470
+ def self.log(msg)
471
+ #puts "[rets_importer] #{msg}"
472
+ Rails.logger.info("[rets_importer] #{msg}")
473
+ end
474
+
475
+ #=============================================================================
476
+ # Locking update task
477
+ #=============================================================================
478
+
479
+ def self.last_updated
480
+ if !Caboose::Setting.exists?(:name => 'rets_last_updated')
481
+ Caboose::Setting.create(:name => 'rets_last_updated', :value => '2013-08-06T00:00:01')
482
+ end
483
+ s = Caboose::Setting.where(:name => 'rets_last_updated').first
484
+ return DateTime.parse(s.value)
485
+ end
486
+
487
+ def self.save_last_updated(d)
488
+ s = Caboose::Setting.where(:name => 'rets_last_updated').first
489
+ s.value = d.strftime('%FT%T')
490
+ s.save
491
+ end
492
+
493
+ def self.task_is_locked
494
+ return Caboose::Setting.exists?(:name => 'rets_update_running')
495
+ end
496
+
497
+ def self.lock_task
498
+ d = DateTime.now.utc - 5.hours
499
+ Caboose::Setting.create(:name => 'rets_update_running', :value => d.strftime('%F %T'))
500
+ return d
501
+ end
502
+
503
+ def self.unlock_task
504
+ Caboose::Setting.where(:name => 'rets_update_running').first.destroy
505
+ end
506
+
507
+ def self.unlock_task_if_last_updated(d)
508
+ setting = Caboose::Setting.where(:name => 'rets_update_running').first
509
+ self.unlock_task if setting && d.strftime('%F %T') == setting.value
510
+ end
511
+
512
+ end
@@ -1,3 +1,3 @@
1
1
  module CabooseRets
2
- VERSION = '0.0.52'
2
+ VERSION = '0.0.53'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caboose-rets
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.52
4
+ version: 0.0.53
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Barry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-11 00:00:00.000000000 Z
11
+ date: 2014-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: caboose-cms
@@ -55,6 +55,7 @@ files:
55
55
  - app/models/caboose_rets/open_house.rb
56
56
  - app/models/caboose_rets/residential_property.rb
57
57
  - app/models/caboose_rets/rets_importer.rb
58
+ - app/models/caboose_rets/rets_importer_bak.rb
58
59
  - app/models/caboose_rets/rets_plugin.rb
59
60
  - app/models/caboose_rets/saved_property.rb
60
61
  - app/models/caboose_rets/saved_search.rb