caboose-rets 0.0.62 → 0.0.63
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 +8 -8
- data/app/models/caboose_rets/rets_importer.rb +217 -171
- data/lib/caboose_rets/version.rb +1 -1
- metadata +1 -1
    
        checksums.yaml
    CHANGED
    
    | @@ -1,15 +1,15 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            !binary "U0hBMQ==":
         | 
| 3 3 | 
             
              metadata.gz: !binary |-
         | 
| 4 | 
            -
                 | 
| 4 | 
            +
                MDA2YWIxNjM3YWYyYmYwYjNjNGNkZDQ1YThmMGI3MDU4ZDFjYzYzZQ==
         | 
| 5 5 | 
             
              data.tar.gz: !binary |-
         | 
| 6 | 
            -
                 | 
| 6 | 
            +
                NmMyNTFkYWE1NjBlYWZkNzNlNDk2ZDg0MGQyOGYxYmEwYmVlYTIzYg==
         | 
| 7 7 | 
             
            SHA512:
         | 
| 8 8 | 
             
              metadata.gz: !binary |-
         | 
| 9 | 
            -
                 | 
| 10 | 
            -
                 | 
| 11 | 
            -
                 | 
| 9 | 
            +
                ODhkYWYyOWJhZmQyNzczNzQ1N2UzZTAwZTVkZGJmNDY4MjlmZGM3ODY0ZjI3
         | 
| 10 | 
            +
                ZGMwNTkxODk5NWNiZWM5MWE2Y2VhYTc1OTBhYmUyN2Q1Y2IzYjVlYjNmYmI5
         | 
| 11 | 
            +
                MWY5YTY0YmJlNWFjOTMwMjc3ZWY0MjIyYWE3MWViMGQxYTRjOGQ=
         | 
| 12 12 | 
             
              data.tar.gz: !binary |-
         | 
| 13 | 
            -
                 | 
| 14 | 
            -
                 | 
| 15 | 
            -
                 | 
| 13 | 
            +
                NmE1YTVkMWI2OTU2Nzg2MDhiMTM0ZDgyYTIwOTNmM2RlZDM0MmI1MTZmMDc4
         | 
| 14 | 
            +
                ZTc1YWVmNDhiYWZkNmViNmI0MzQ1YzA5NmY0NWVjNzVkZjkyNmJkMTYxNWEy
         | 
| 15 | 
            +
                NWQ0OTVmZGUxY2NlNGI4MzBkZWIwNGE2MDYzZGM2MjI0MmJlN2E=
         | 
| @@ -14,14 +14,14 @@ require 'json' | |
| 14 14 | 
             
            # http://rets.solidearth.com/ClientHome.aspx
         | 
| 15 15 |  | 
| 16 16 | 
             
            class CabooseRets::RetsImporter # < ActiveRecord::Base
         | 
| 17 | 
            -
             | 
| 17 | 
            +
             | 
| 18 18 | 
             
              @@rets_client = nil
         | 
| 19 19 | 
             
              @@config = nil
         | 
| 20 | 
            -
             | 
| 20 | 
            +
             | 
| 21 21 | 
             
              def self.config
         | 
| 22 22 | 
             
                return @@config
         | 
| 23 23 | 
             
              end
         | 
| 24 | 
            -
             | 
| 24 | 
            +
             | 
| 25 25 | 
             
              def self.get_config
         | 
| 26 26 | 
             
                @@config = {
         | 
| 27 27 | 
             
                  'url'                 => nil, # URL to the RETS login
         | 
| @@ -35,11 +35,11 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base | |
| 35 35 | 
             
                config = config[Rails.env]
         | 
| 36 36 | 
             
                config.each { |key,val| @@config[key] = val }
         | 
| 37 37 | 
             
              end
         | 
| 38 | 
            -
             | 
| 38 | 
            +
             | 
| 39 39 | 
             
              def self.client
         | 
| 40 40 | 
             
                self.get_config if @@config.nil? || @@config['url'].nil?
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                if  | 
| 41 | 
            +
             | 
| 42 | 
            +
                if @@rets_client.nil?
         | 
| 43 43 | 
             
                  @@rets_client = RETS::Client.login(
         | 
| 44 44 | 
             
                    :url      => @@config['url'],
         | 
| 45 45 | 
             
                    :username => @@config['username'],
         | 
| @@ -48,35 +48,49 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base | |
| 48 48 | 
             
                end
         | 
| 49 49 | 
             
                return @@rets_client
         | 
| 50 50 | 
             
              end
         | 
| 51 | 
            -
             | 
| 51 | 
            +
             | 
| 52 | 
            +
              def self.meta(class_type)
         | 
| 53 | 
            +
                case class_type
         | 
| 54 | 
            +
                  when 'RES' then Caboose::StdClass.new({ :search_type => 'Property'  , :remote_key_field => 'MLS_ACCT'   , :local_key_field => 'mls_acct' , :local_table => 'rets_residential'  , :date_modified_field => 'DATE_MODIFIED'    })
         | 
| 55 | 
            +
                  when 'COM' then Caboose::StdClass.new({ :search_type => 'Property'  , :remote_key_field => 'MLS_ACCT'   , :local_key_field => 'mls_acct' , :local_table => 'rets_commercial'   , :date_modified_field => 'DATE_MODIFIED'    })
         | 
| 56 | 
            +
                  when 'LND' then Caboose::StdClass.new({ :search_type => 'Property'  , :remote_key_field => 'MLS_ACCT'   , :local_key_field => 'mls_acct' , :local_table => 'rets_land'         , :date_modified_field => 'DATE_MODIFIED'    })
         | 
| 57 | 
            +
                  when 'MUL' then Caboose::StdClass.new({ :search_type => 'Property'  , :remote_key_field => 'MLS_ACCT'   , :local_key_field => 'mls_acct' , :local_table => 'rets_multi_family' , :date_modified_field => 'DATE_MODIFIED'    })
         | 
| 58 | 
            +
                  when 'OFF' then Caboose::StdClass.new({ :search_type => 'Office'    , :remote_key_field => 'LO_LO_CODE' , :local_key_field => 'lo_code'  , :local_table => 'rets_offices'      , :date_modified_field => 'LO_DATE_MODIFIED' })
         | 
| 59 | 
            +
                  when 'AGT' then Caboose::StdClass.new({ :search_type => 'Agent'     , :remote_key_field => 'LA_LA_CODE' , :local_key_field => 'la_code'  , :local_table => 'rets_agents'       , :date_modified_field => 'LA_DATE_MODIFIED' })
         | 
| 60 | 
            +
                  when 'OPH' then Caboose::StdClass.new({ :search_type => 'OpenHouse' , :remote_key_field => 'ID'         , :local_key_field => 'id'       , :local_table => 'rets_open_houses'  , :date_modified_field => 'DATE_MODIFIED'    })
         | 
| 61 | 
            +
                  when 'GFX' then Caboose::StdClass.new({ :search_type => 'Media'     , :remote_key_field => 'MEDIA_ID'   , :local_key_field => 'media_id' , :local_table => 'rets_media'        , :date_modified_field => 'DATE_MODIFIED'    })
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
             | 
| 52 65 | 
             
              #=============================================================================
         | 
| 53 66 | 
             
              # Import method
         | 
| 54 67 | 
             
              #=============================================================================
         | 
| 55 | 
            -
             | 
| 56 | 
            -
              def self.import( | 
| 57 | 
            -
                self. | 
| 68 | 
            +
             | 
| 69 | 
            +
              def self.import(class_type, query)
         | 
| 70 | 
            +
                m = self.meta(class_type)
         | 
| 71 | 
            +
                self.log("Importing #{m.search_type}:#{class_type} with query #{query}...")
         | 
| 58 72 | 
             
                self.get_config if @@config.nil? || @@config['url'].nil?
         | 
| 59 73 | 
             
                params = {
         | 
| 60 | 
            -
                  :search_type => search_type,
         | 
| 74 | 
            +
                  :search_type => m.search_type,
         | 
| 61 75 | 
             
                  :class => class_type,
         | 
| 62 76 | 
             
                  :query => query,
         | 
| 63 | 
            -
                  :limit => -1, | 
| 77 | 
            +
                  :limit => -1,
         | 
| 64 78 | 
             
                  :timeout => -1
         | 
| 65 79 | 
             
                }
         | 
| 66 80 | 
             
                obj = nil
         | 
| 67 81 | 
             
                self.client.search(params) do |data|
         | 
| 68 82 | 
             
                  obj = self.get_instance_with_id(class_type, data)
         | 
| 69 83 | 
             
                  if obj.nil?
         | 
| 70 | 
            -
                    self.log("Error: object is nil") | 
| 84 | 
            +
                    self.log("Error: object is nil")
         | 
| 71 85 | 
             
                    self.log(data.inspect)
         | 
| 72 86 | 
             
                    next
         | 
| 73 87 | 
             
                  end
         | 
| 74 | 
            -
                  obj.parse(data) | 
| 75 | 
            -
                  obj.save | 
| 76 | 
            -
                end | 
| 88 | 
            +
                  obj.parse(data)
         | 
| 89 | 
            +
                  obj.save
         | 
| 90 | 
            +
                end
         | 
| 77 91 | 
             
              end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
              def self.get_instance_with_id(class_type, data) | 
| 92 | 
            +
             | 
| 93 | 
            +
              def self.get_instance_with_id(class_type, data)
         | 
| 80 94 | 
             
                obj = nil
         | 
| 81 95 | 
             
                m = case class_type
         | 
| 82 96 | 
             
                  when 'OPH' then CabooseRets::OpenHouse
         | 
| @@ -87,183 +101,182 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base | |
| 87 101 | 
             
                  when 'RES' then CabooseRets::ResidentialProperty
         | 
| 88 102 | 
             
                  when 'AGT' then CabooseRets::Agent
         | 
| 89 103 | 
             
                  when 'OFF' then CabooseRets::Office
         | 
| 90 | 
            -
                end | 
| 104 | 
            +
                end
         | 
| 91 105 | 
             
                obj = case class_type
         | 
| 92 106 | 
             
                  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       )
         | 
| 93 107 | 
             
                  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']      )
         | 
| 94 108 | 
             
                  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 )
         | 
| 95 | 
            -
                  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 ) | 
| 96 | 
            -
                  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 ) | 
| 97 | 
            -
                  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 ) | 
| 109 | 
            +
                  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 )
         | 
| 110 | 
            +
                  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 )
         | 
| 111 | 
            +
                  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 )
         | 
| 98 112 | 
             
                  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']    )
         | 
| 99 113 | 
             
                  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']    )
         | 
| 100 114 | 
             
                end
         | 
| 101 | 
            -
                return obj | 
| 102 | 
            -
              end
         | 
| 103 | 
            -
             | 
| 104 | 
            -
              #def self.delete_old_properties    
         | 
| 105 | 
            -
              #  self.log("Deleting old residential properties...")    
         | 
| 106 | 
            -
              #  self.get_config if @@config.nil? || @@config['url'].nil?
         | 
| 107 | 
            -
              #  
         | 
| 108 | 
            -
              #  d = DateTime.new(2000, 1, 1)
         | 
| 109 | 
            -
              #  now = DateTime.now
         | 
| 110 | 
            -
              #  while d < now
         | 
| 111 | 
            -
              #    d2 = d + 3.months
         | 
| 112 | 
            -
              #    puts "- Getting ids for #{d.strftime("%Y-%m-%d")} - #{d2.strftime("%Y-%m-%d")}..."                  
         | 
| 113 | 
            -
              #    q = "((DATE_CREATED=#{d.strftime("%Y-%m-%d")}+),(DATE_CREATED=#{d2.strftime("%Y-%m-%d")}-))",
         | 
| 114 | 
            -
              #    params = { :search_type => 'Property', :class => 'RES', :query => q, :limit => -1, :timeout => -1, :select => 'MLS_ACCT' } 
         | 
| 115 | 
            -
              #    ids = []
         | 
| 116 | 
            -
              #    self.client.search(params) do |data|        
         | 
| 117 | 
            -
              #      ids << data['MLS_ACCT'].to_i
         | 
| 118 | 
            -
              #    end
         | 
| 119 | 
            -
              #    d = d + 3.months
         | 
| 120 | 
            -
              #  end
         | 
| 121 | 
            -
              #  
         | 
| 122 | 
            -
              #  puts "Deleting properties..."
         | 
| 123 | 
            -
              #  #CabooseRets::ResidentialProperty.where("id not in (?)", ids).destroy_all            
         | 
| 124 | 
            -
              #end
         | 
| 125 | 
            -
              
         | 
| 115 | 
            +
                return obj
         | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
             | 
| 126 118 | 
             
              #=============================================================================
         | 
| 127 119 | 
             
              # Main updater
         | 
| 128 120 | 
             
              #=============================================================================
         | 
| 129 121 |  | 
| 130 122 | 
             
              def self.update_after(date_modified, save_images = true)
         | 
| 131 | 
            -
                self. | 
| 132 | 
            -
                self. | 
| 133 | 
            -
                self. | 
| 134 | 
            -
                self. | 
| 135 | 
            -
                self. | 
| 136 | 
            -
                self. | 
| 137 | 
            -
                self. | 
| 138 | 
            -
              end | 
| 139 | 
            -
             | 
| 140 | 
            -
              def self. | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 123 | 
            +
                self.update_helper('RES', date_modified, save_images)
         | 
| 124 | 
            +
                self.update_helper('COM', date_modified, save_images)
         | 
| 125 | 
            +
                self.update_helper('LND', date_modified, save_images)
         | 
| 126 | 
            +
                self.update_helper('MUL', date_modified, save_images)
         | 
| 127 | 
            +
                self.update_helper('OFF', date_modified, save_images)
         | 
| 128 | 
            +
                self.update_helper('AGT', date_modified, save_images)
         | 
| 129 | 
            +
                self.update_helper('OPH', date_modified, save_images)
         | 
| 130 | 
            +
              end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
              def self.update_helper(class_type, date_modified, save_images = true)
         | 
| 133 | 
            +
                m = self.meta(class_type)
         | 
| 134 | 
            +
                k = m.remote_key_field
         | 
| 135 | 
            +
                params = {
         | 
| 136 | 
            +
                  :search_type => m.search_type,
         | 
| 137 | 
            +
                  :class => class_type,
         | 
| 138 | 
            +
                  :select => [m.remote_key_field],
         | 
| 139 | 
            +
                  :query => "(#{m.date_modified_field}=#{date_modified.strftime("%FT%T")}+)",
         | 
| 140 | 
            +
                  :standard_names_only => true,
         | 
| 141 | 
            +
                  :timeout => -1
         | 
| 142 | 
            +
                }
         | 
| 143 | 
            +
                self.client.search(params) do |data|
         | 
| 144 | 
            +
                  case class_type
         | 
| 145 | 
            +
                    when 'RES' then self.delay(:priority => 10).import_residential_property(  data[k], save_images)
         | 
| 146 | 
            +
                    when 'COM' then self.delay(:priority => 10).import_commercial_property(   data[k], save_images)
         | 
| 147 | 
            +
                    when 'LND' then self.delay(:priority => 10).import_land_property(         data[k], save_images)
         | 
| 148 | 
            +
                    when 'MUL' then self.delay(:priority => 10).import_multi_family_property( data[k], save_images)
         | 
| 149 | 
            +
                    when 'OFF' then self.delay(:priority => 10).import_office(                data[k], save_images)
         | 
| 150 | 
            +
                    when 'AGT' then self.delay(:priority => 10).import_agent(                 data[k], save_images)
         | 
| 151 | 
            +
                    when 'OPH' then self.delay(:priority => 10).import_open_house(            data[k], save_images)
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
              end
         | 
| 155 | 
            +
             | 
| 147 156 | 
             
              #=============================================================================
         | 
| 148 157 | 
             
              # Single model import methods (called from a worker dyno)
         | 
| 149 158 | 
             
              #=============================================================================
         | 
| 150 | 
            -
             | 
| 151 | 
            -
              def self.import_property(mls_acct)
         | 
| 152 | 
            -
                self.import("(MLS_ACCT=*#{mls_acct}*)" | 
| 159 | 
            +
             | 
| 160 | 
            +
              def self.import_property(mls_acct, save_images = true)
         | 
| 161 | 
            +
                self.import('RES', "(MLS_ACCT=*#{mls_acct}*)")
         | 
| 153 162 | 
             
                p = CabooseRets::ResidentialProperty.where(:id => mls_acct.to_i).first
         | 
| 154 163 | 
             
                if p.nil?
         | 
| 155 | 
            -
                  self.import("(MLS_ACCT=*#{mls_acct}*)" | 
| 156 | 
            -
                  p = CabooseRets::CommercialProperty.where(:id => mls_acct.to_i).first | 
| 164 | 
            +
                  self.import('COM', "(MLS_ACCT=*#{mls_acct}*)")
         | 
| 165 | 
            +
                  p = CabooseRets::CommercialProperty.where(:id => mls_acct.to_i).first
         | 
| 157 166 | 
             
                  if p.nil?
         | 
| 158 | 
            -
                    self.import("(MLS_ACCT=*#{mls_acct}*)" | 
| 167 | 
            +
                    self.import('LND', "(MLS_ACCT=*#{mls_acct}*)")
         | 
| 159 168 | 
             
                    p = CabooseRets::LandProperty.where(:id => mls_acct.to_i).first
         | 
| 160 169 | 
             
                    if p.nil?
         | 
| 161 | 
            -
                      self.import("(MLS_ACCT=*#{mls_acct}*)" | 
| 170 | 
            +
                      self.import('MUL', "(MLS_ACCT=*#{mls_acct}*)")
         | 
| 162 171 | 
             
                      p = CabooseRets::MultiFamilyProperty.where(:id => mls_acct.to_i).first
         | 
| 163 172 | 
             
                      return if p.nil?
         | 
| 164 173 | 
             
                    end
         | 
| 165 174 | 
             
                  end
         | 
| 166 175 | 
             
                end
         | 
| 167 | 
            -
                self.download_property_images(p)
         | 
| 168 | 
            -
              end
         | 
| 169 | 
            -
             | 
| 170 | 
            -
              def self.import_residential_property(mls_acct, save_images = true) | 
| 171 | 
            -
                self.import("(MLS_ACCT=*#{mls_acct}*)" | 
| 172 | 
            -
                p = CabooseRets::ResidentialProperty.where(:id => mls_acct.to_i).first | 
| 173 | 
            -
                self.download_property_images(p, save_images) | 
| 174 | 
            -
                self.update_coords(p) | 
| 175 | 
            -
              end
         | 
| 176 | 
            -
             | 
| 177 | 
            -
              def self.import_commercial_property(mls_acct, save_images = true) | 
| 178 | 
            -
                self.import("(MLS_ACCT=*#{mls_acct}*)" | 
| 176 | 
            +
                self.download_property_images(p, save_images)
         | 
| 177 | 
            +
              end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
              def self.import_residential_property(mls_acct, save_images = true)
         | 
| 180 | 
            +
                self.import('RES', "(MLS_ACCT=*#{mls_acct}*)")
         | 
| 181 | 
            +
                p = CabooseRets::ResidentialProperty.where(:id => mls_acct.to_i).first
         | 
| 182 | 
            +
                self.download_property_images(p, save_images)
         | 
| 183 | 
            +
                self.update_coords(p)
         | 
| 184 | 
            +
              end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
              def self.import_commercial_property(mls_acct, save_images = true)
         | 
| 187 | 
            +
                self.import('COM', "(MLS_ACCT=*#{mls_acct}*)")
         | 
| 179 188 | 
             
                p = CabooseRets::CommercialProperty.where(:id => mls_acct.to_i).first
         | 
| 180 189 | 
             
                self.download_property_images(p, save_images)
         | 
| 181 190 | 
             
                self.update_coords(p)
         | 
| 182 191 | 
             
              end
         | 
| 183 | 
            -
             | 
| 184 | 
            -
              def self.import_land_property(mls_acct, save_images = true) | 
| 185 | 
            -
                self.import("(MLS_ACCT=*#{mls_acct}*)" | 
| 186 | 
            -
                p = CabooseRets::LandProperty.where(:id => mls_acct.to_i).first | 
| 192 | 
            +
             | 
| 193 | 
            +
              def self.import_land_property(mls_acct, save_images = true)
         | 
| 194 | 
            +
                self.import('LND', "(MLS_ACCT=*#{mls_acct}*)")
         | 
| 195 | 
            +
                p = CabooseRets::LandProperty.where(:id => mls_acct.to_i).first
         | 
| 187 196 | 
             
                self.download_property_images(p, save_images)
         | 
| 188 197 | 
             
                self.update_coords(p)
         | 
| 189 198 | 
             
              end
         | 
| 190 | 
            -
             | 
| 191 | 
            -
              def self.import_multi_family_property(mls_acct, save_images = true) | 
| 192 | 
            -
                self.import("(MLS_ACCT=*#{mls_acct}*)" | 
| 199 | 
            +
             | 
| 200 | 
            +
              def self.import_multi_family_property(mls_acct, save_images = true)
         | 
| 201 | 
            +
                self.import('MUL', "(MLS_ACCT=*#{mls_acct}*)")
         | 
| 193 202 | 
             
                p = CabooseRets::MultiFamilyProperty.where(:id => mls_acct.to_i).first
         | 
| 194 203 | 
             
                self.download_property_images(p, save_images)
         | 
| 195 204 | 
             
                self.update_coords(p)
         | 
| 196 205 | 
             
              end
         | 
| 197 | 
            -
             | 
| 206 | 
            +
             | 
| 198 207 | 
             
              def self.import_office(lo_code, save_images = true)
         | 
| 199 | 
            -
                self.import("(LO_LO_CODE=*#{lo_code}*)" | 
| 208 | 
            +
                self.import('OFF', "(LO_LO_CODE=*#{lo_code}*)")
         | 
| 200 209 | 
             
                office = CabooseRets::Office.where(:lo_code => lo_code.to_s).first
         | 
| 201 210 | 
             
                self.download_office_image(office) if save_images == true
         | 
| 202 211 | 
             
              end
         | 
| 203 | 
            -
             | 
| 212 | 
            +
             | 
| 204 213 | 
             
              def self.import_agent(la_code, save_images = true)
         | 
| 205 | 
            -
                self.import("(LA_LA_CODE=*#{la_code}*)" | 
| 214 | 
            +
                self.import('AGT', "(LA_LA_CODE=*#{la_code}*)")
         | 
| 206 215 | 
             
                a = CabooseRets::Agent.where(:la_code => la_code.to_s).first
         | 
| 207 216 | 
             
                self.download_agent_image(a) if save_images == true
         | 
| 208 217 | 
             
              end
         | 
| 209 | 
            -
             | 
| 218 | 
            +
             | 
| 210 219 | 
             
              def self.import_open_house(id, save_images = true)
         | 
| 211 | 
            -
                self.import("(ID=*#{id}*)" | 
| 220 | 
            +
                self.import('OPH', "(ID=*#{id}*)")
         | 
| 221 | 
            +
              end
         | 
| 222 | 
            +
             | 
| 223 | 
            +
              def self.import_media(id, save_images = true)
         | 
| 224 | 
            +
                self.import('GFX', "(MEDIA_ID=*#{id}*)")
         | 
| 212 225 | 
             
              end
         | 
| 213 226 |  | 
| 214 227 | 
             
              #=============================================================================
         | 
| 215 228 | 
             
              # Images
         | 
| 216 229 | 
             
              #=============================================================================
         | 
| 217 | 
            -
             | 
| 218 | 
            -
              def self.download_property_images(p, save_images = true) | 
| 230 | 
            +
             | 
| 231 | 
            +
              def self.download_property_images(p, save_images = true)
         | 
| 219 232 | 
             
                self.refresh_property_media(p)
         | 
| 220 233 | 
             
                return if save_images == false
         | 
| 221 | 
            -
             | 
| 234 | 
            +
             | 
| 222 235 | 
             
                self.log("-- Downloading images and resizing for #{p.mls_acct}")
         | 
| 223 236 | 
             
                media = []
         | 
| 224 237 | 
             
                self.client.get_object(:resource => :Property, :type => :Photo, :location => true, :id => p.id) do |headers, content|
         | 
| 225 | 
            -
             | 
| 238 | 
            +
             | 
| 226 239 | 
             
                  # Find the associated media record for the image
         | 
| 227 240 | 
             
                  filename = File.basename(headers['location'])
         | 
| 228 241 | 
             
                  m = CabooseRets::Media.where(:mls_acct => p.mls_acct, :file_name => filename).first
         | 
| 229 | 
            -
             | 
| 242 | 
            +
             | 
| 230 243 | 
             
                  if m.nil?
         | 
| 231 244 | 
             
                    self.log("Can't find media record for #{p.mls_acct} #{filename}.")
         | 
| 232 | 
            -
                  else | 
| 245 | 
            +
                  else
         | 
| 233 246 | 
             
                    m.image = URI.parse(headers['location'])
         | 
| 234 247 | 
             
                    media << m
         | 
| 235 248 | 
             
                    #m.save
         | 
| 236 | 
            -
                  end | 
| 249 | 
            +
                  end
         | 
| 237 250 | 
             
                end
         | 
| 238 | 
            -
             | 
| 251 | 
            +
             | 
| 239 252 | 
             
                self.log("-- Uploading images to S3 for #{p.mls_acct}")
         | 
| 240 | 
            -
                media.each do |m| | 
| 253 | 
            +
                media.each do |m|
         | 
| 241 254 | 
             
                  m.save
         | 
| 242 | 
            -
                end | 
| 255 | 
            +
                end
         | 
| 243 256 | 
             
              end
         | 
| 244 | 
            -
             | 
| 257 | 
            +
             | 
| 245 258 | 
             
              def self.refresh_property_media(p)
         | 
| 246 | 
            -
                self.log("-- Deleting images and metadata for #{p.mls_acct}...") | 
| 259 | 
            +
                self.log("-- Deleting images and metadata for #{p.mls_acct}...")
         | 
| 247 260 | 
             
                #CabooseRets::Media.where(:mls_acct => p.mls_acct, :media_type => 'Photo').destroy_all
         | 
| 248 261 | 
             
                CabooseRets::Media.where(:mls_acct => p.mls_acct).destroy_all
         | 
| 249 | 
            -
             | 
| 250 | 
            -
                self.log("-- Downloading image metadata for #{p.mls_acct}...") | 
| 262 | 
            +
             | 
| 263 | 
            +
                self.log("-- Downloading image metadata for #{p.mls_acct}...")
         | 
| 251 264 | 
             
                params = {
         | 
| 252 265 | 
             
                  :search_type => 'Media',
         | 
| 253 266 | 
             
                  :class => 'GFX',
         | 
| 254 267 | 
             
                  #:query => "(MLS_ACCT=*#{p.id}*),(MEDIA_TYPE=|I)",
         | 
| 255 268 | 
             
                  :query => "(MLS_ACCT=*#{p.id}*)",
         | 
| 256 269 | 
             
                  :timeout => -1
         | 
| 257 | 
            -
                } | 
| 258 | 
            -
                self.client.search(params) do |data| | 
| 270 | 
            +
                }
         | 
| 271 | 
            +
                self.client.search(params) do |data|
         | 
| 259 272 | 
             
                  m = CabooseRets::Media.new
         | 
| 260 273 | 
             
                  m.parse(data)
         | 
| 261 274 | 
             
                  #m.id = m.media_id
         | 
| 262 275 | 
             
                  m.save
         | 
| 263 276 | 
             
                end
         | 
| 264 277 | 
             
              end
         | 
| 265 | 
            -
             | 
| 266 | 
            -
              def self.download_agent_image(agent) | 
| 278 | 
            +
             | 
| 279 | 
            +
              def self.download_agent_image(agent)
         | 
| 267 280 | 
             
                self.log "Saving image for #{agent.first_name} #{agent.last_name}..."
         | 
| 268 281 | 
             
                begin
         | 
| 269 282 | 
             
                  self.client.get_object(:resource => :Agent, :type => :Photo, :location => true, :id => agent.la_code) do |headers, content|
         | 
| @@ -272,9 +285,9 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base | |
| 272 285 | 
             
                  end
         | 
| 273 286 | 
             
                rescue RETS::APIError => err
         | 
| 274 287 | 
             
                  self.log "No image for #{agent.first_name} #{agent.last_name}."
         | 
| 275 | 
            -
                end | 
| 288 | 
            +
                end
         | 
| 276 289 | 
             
              end
         | 
| 277 | 
            -
             | 
| 290 | 
            +
             | 
| 278 291 | 
             
              def self.download_office_image(office)
         | 
| 279 292 | 
             
                self.log "Saving image for #{office.lo_name}..."
         | 
| 280 293 | 
             
                begin
         | 
| @@ -282,58 +295,58 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base | |
| 282 295 | 
             
                    office.image = URI.parse(headers['location'])
         | 
| 283 296 | 
             
                    office.save
         | 
| 284 297 | 
             
                  end
         | 
| 285 | 
            -
                rescue RETS::APIError => err | 
| 298 | 
            +
                rescue RETS::APIError => err
         | 
| 286 299 | 
             
                  self.log "No image for #{office.lo_name}."
         | 
| 287 | 
            -
                end | 
| 300 | 
            +
                end
         | 
| 288 301 | 
             
              end
         | 
| 289 302 |  | 
| 290 303 | 
             
              #=============================================================================
         | 
| 291 304 | 
             
              # GPS
         | 
| 292 305 | 
             
              #=============================================================================
         | 
| 293 | 
            -
             | 
| 294 | 
            -
              def self.update_coords(p = nil) | 
| 306 | 
            +
             | 
| 307 | 
            +
              def self.update_coords(p = nil)
         | 
| 295 308 | 
             
                if p.nil?
         | 
| 296 309 | 
             
                  models = [CabooseRets::CommercialProperty, CabooseRets::LandProperty, CabooseRets::MultiFamilyProperty, CabooseRets::ResidentialProperty]
         | 
| 297 310 | 
             
                  names = ["commercial", "land", "multi-family", "residential"]
         | 
| 298 311 | 
             
                  i = 0
         | 
| 299 | 
            -
                  models.each do |model| | 
| 312 | 
            +
                  models.each do |model|
         | 
| 300 313 | 
             
                    self.log "Updating coords #{names[i]} properties..."
         | 
| 301 314 | 
             
                    model.where(:latitude => nil).reorder(:mls_acct).each do |p|
         | 
| 302 | 
            -
                      self.update_coords(p) | 
| 315 | 
            +
                      self.update_coords(p)
         | 
| 303 316 | 
             
                    end
         | 
| 304 317 | 
             
                    i = i + 1
         | 
| 305 318 | 
             
                  end
         | 
| 306 319 | 
             
                  return
         | 
| 307 320 | 
             
                end
         | 
| 308 | 
            -
             | 
| 321 | 
            +
             | 
| 309 322 | 
             
                self.log "Getting coords for mls_acct #{p.mls_acct}..."
         | 
| 310 323 | 
             
                coords = self.coords_from_address(CGI::escape "#{p.street_num} #{p.street_name}, #{p.city}, #{p.state} #{p.zip}")
         | 
| 311 324 | 
             
                return if coords.nil? || coords == false
         | 
| 312 | 
            -
             | 
| 325 | 
            +
             | 
| 313 326 | 
             
                p.latitude = coords['lat']
         | 
| 314 327 | 
             
                p.longitude = coords['lng']
         | 
| 315 | 
            -
                p.save | 
| 328 | 
            +
                p.save
         | 
| 316 329 | 
             
              end
         | 
| 317 | 
            -
             | 
| 318 | 
            -
              def self.coords_from_address(address) | 
| 330 | 
            +
             | 
| 331 | 
            +
              def self.coords_from_address(address)
         | 
| 319 332 | 
             
                begin
         | 
| 320 333 | 
             
                  uri = "https://maps.googleapis.com/maps/api/geocode/json?address=#{address}&sensor=false"
         | 
| 321 | 
            -
                  uri.gsub!(" ", "+") | 
| 334 | 
            +
                  uri.gsub!(" ", "+")
         | 
| 322 335 | 
             
                  resp = HTTParty.get(uri)
         | 
| 323 336 | 
             
                  json = JSON.parse(resp.body)
         | 
| 324 | 
            -
                  return json['results'][0]['geometry']['location'] | 
| 337 | 
            +
                  return json['results'][0]['geometry']['location']
         | 
| 325 338 | 
             
                rescue
         | 
| 326 339 | 
             
                  self.log "Error: #{uri}"
         | 
| 327 340 | 
             
                  sleep(2)
         | 
| 328 | 
            -
                  return false | 
| 341 | 
            +
                  return false
         | 
| 329 342 | 
             
                end
         | 
| 330 343 | 
             
              end
         | 
| 331 | 
            -
             | 
| 344 | 
            +
             | 
| 332 345 | 
             
              #=============================================================================
         | 
| 333 346 | 
             
              # Purging
         | 
| 334 347 | 
             
              #=============================================================================
         | 
| 335 | 
            -
             | 
| 336 | 
            -
              def self.purge | 
| 348 | 
            +
             | 
| 349 | 
            +
              def self.purge
         | 
| 337 350 | 
             
                self.purge_residential
         | 
| 338 351 | 
             
                self.purge_commercial
         | 
| 339 352 | 
             
                self.purge_land
         | 
| @@ -343,56 +356,89 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base | |
| 343 356 | 
             
                self.purge_open_houses
         | 
| 344 357 | 
             
                self.purge_media
         | 
| 345 358 | 
             
              end
         | 
| 346 | 
            -
             | 
| 347 | 
            -
              def self.purge_residential()  self.purge_helper(' | 
| 348 | 
            -
              def self.purge_commercial()   self.purge_helper(' | 
| 349 | 
            -
              def self.purge_land()         self.purge_helper(' | 
| 350 | 
            -
              def self.purge_multi_family() self.purge_helper(' | 
| 351 | 
            -
              def self.purge_offices()      self.purge_helper(' | 
| 352 | 
            -
              def self.purge_agents()       self.purge_helper(' | 
| 353 | 
            -
              def self.purge_open_houses()  self.purge_helper(' | 
| 354 | 
            -
              def self.purge_media()        self.purge_helper(' | 
| 355 | 
            -
             | 
| 356 | 
            -
              def self.purge_helper( | 
| 357 | 
            -
                
         | 
| 359 | 
            +
             | 
| 360 | 
            +
              def self.purge_residential()  self.purge_helper('RES', '2012-01-01') end
         | 
| 361 | 
            +
              def self.purge_commercial()   self.purge_helper('COM', '2012-01-01') end
         | 
| 362 | 
            +
              def self.purge_land()         self.purge_helper('LND', '2012-01-01') end
         | 
| 363 | 
            +
              def self.purge_multi_family() self.purge_helper('MUL', '2012-01-01') end
         | 
| 364 | 
            +
              def self.purge_offices()      self.purge_helper('OFF', '2012-01-01') end
         | 
| 365 | 
            +
              def self.purge_agents()       self.purge_helper('AGT', '2012-01-01') end
         | 
| 366 | 
            +
              def self.purge_open_houses()  self.purge_helper('OPH', '2012-01-01') end
         | 
| 367 | 
            +
              def self.purge_media()        self.purge_helper('GFX', '2012-01-01') end
         | 
| 368 | 
            +
             | 
| 369 | 
            +
              def self.purge_helper(class_type, date_modified)
         | 
| 370 | 
            +
                m = self.meta(class_type)
         | 
| 371 | 
            +
             | 
| 358 372 | 
             
                # Get the total number of records
         | 
| 359 | 
            -
                params = { | 
| 373 | 
            +
                params = {
         | 
| 374 | 
            +
                  :search_type => m.search_type,
         | 
| 375 | 
            +
                  :class => class_type,
         | 
| 376 | 
            +
                  :query => "(#{m.date_modified_field}=#{date_modified}T00:00:01+)",
         | 
| 377 | 
            +
                  :standard_names_only => true,
         | 
| 378 | 
            +
                  :timeout => -1
         | 
| 379 | 
            +
                }
         | 
| 360 380 | 
             
                self.client.search(params.merge({ :count_mode => :only }))
         | 
| 361 | 
            -
                count = self.client.rets_data[:code] == "20201" ? 0 : self.client.rets_data[:count] | 
| 381 | 
            +
                count = self.client.rets_data[:code] == "20201" ? 0 : self.client.rets_data[:count]
         | 
| 362 382 | 
             
                batch_count = (count.to_f/5000.0).ceil
         | 
| 363 383 |  | 
| 364 384 | 
             
                ids = []
         | 
| 365 | 
            -
                 | 
| 366 | 
            -
             | 
| 367 | 
            -
             | 
| 368 | 
            -
                 | 
| 385 | 
            +
                k = m.remote_key_field
         | 
| 386 | 
            +
                (0...batch_count).each do |i|
         | 
| 387 | 
            +
                  self.client.search(params.merge({ :select => [k], :limit => 5000, :offset => 5000*i })){ |data| ids << data[k] }
         | 
| 388 | 
            +
                end
         | 
| 389 | 
            +
             | 
| 390 | 
            +
                # Delete any records in the local database that shouldn't be there
         | 
| 391 | 
            +
                t = m.local_table
         | 
| 392 | 
            +
                k = m.local_key_field
         | 
| 393 | 
            +
                query = ["delete from #{t} where #{k} not in (?)", ids]
         | 
| 394 | 
            +
                ActiveRecord::Base.connection.execute(ActiveRecord::Base.send(:sanitize_sql_array, query))
         | 
| 395 | 
            +
             | 
| 396 | 
            +
                # Find any ids in the remote database that should be in the local database
         | 
| 397 | 
            +
                query = "select distinct #{k} from #{t}"
         | 
| 398 | 
            +
                rows = ActiveRecord::Base.connection.select_all(ActiveRecord::Base.send(:sanitize_sql_array, query))
         | 
| 399 | 
            +
                local_ids = rows.collect{ |row| row[k] }
         | 
| 400 | 
            +
                ids_to_add = ids - local_ids
         | 
| 401 | 
            +
                ids_to_add.each do |id|
         | 
| 402 | 
            +
                  puts "Importing #{id}..."
         | 
| 403 | 
            +
                  case class_type
         | 
| 404 | 
            +
                    when 'RES' then self.delay.import_residential_property(id)
         | 
| 405 | 
            +
                    when 'COM' then self.delay.import_commercial_property(id)
         | 
| 406 | 
            +
                    when 'LND' then self.delay.import_land_property(id)
         | 
| 407 | 
            +
                    when 'MUL' then self.delay.import_multi_family_property(id)
         | 
| 408 | 
            +
                    when 'OFF' then self.delay.import_office(id)
         | 
| 409 | 
            +
                    when 'AGT' then self.delay.import_agent(id)
         | 
| 410 | 
            +
                    when 'OPH' then self.delay.import_open_house(id)
         | 
| 411 | 
            +
                    when 'GFX' then self.delay.import_media(id)
         | 
| 412 | 
            +
                  end
         | 
| 413 | 
            +
                end
         | 
| 414 | 
            +
             | 
| 369 415 | 
             
              end
         | 
| 370 416 |  | 
| 371 417 | 
             
              #=============================================================================
         | 
| 372 418 | 
             
              # Logging
         | 
| 373 419 | 
             
              #=============================================================================
         | 
| 374 | 
            -
             | 
| 420 | 
            +
             | 
| 375 421 | 
             
              def self.log(msg)
         | 
| 376 422 | 
             
                #puts "[rets_importer] #{msg}"
         | 
| 377 423 | 
             
                Rails.logger.info("[rets_importer] #{msg}")
         | 
| 378 | 
            -
              end | 
| 379 | 
            -
             | 
| 424 | 
            +
              end
         | 
| 425 | 
            +
             | 
| 380 426 | 
             
              #=============================================================================
         | 
| 381 427 | 
             
              # Locking update task
         | 
| 382 428 | 
             
              #=============================================================================
         | 
| 383 | 
            -
             | 
| 384 | 
            -
              def self.update_rets | 
| 429 | 
            +
             | 
| 430 | 
            +
              def self.update_rets
         | 
| 385 431 | 
             
                return if self.task_is_locked
         | 
| 386 432 | 
             
                task_started = self.lock_task
         | 
| 387 | 
            -
             | 
| 433 | 
            +
             | 
| 388 434 | 
             
                begin
         | 
| 389 | 
            -
                  overlap = 30.seconds | 
| 390 | 
            -
                  if (DateTime.now - self.last_purged).to_i > 1 | 
| 435 | 
            +
                  overlap = 30.seconds
         | 
| 436 | 
            +
                  if (DateTime.now - self.last_purged).to_i > 1
         | 
| 391 437 | 
             
                    self.purge
         | 
| 392 438 | 
             
                    self.save_last_purged(task_started)
         | 
| 393 439 | 
             
                    overlap = 1.month
         | 
| 394 | 
            -
                  end | 
| 395 | 
            -
                  self.update_after(self.last_updated - overlap) | 
| 440 | 
            +
                  end
         | 
| 441 | 
            +
                  self.update_after(self.last_updated - overlap)
         | 
| 396 442 | 
             
            		  self.save_last_updated(task_started)
         | 
| 397 443 | 
             
            		  self.unlock_task
         | 
| 398 444 | 
             
            		rescue
         | 
| @@ -400,11 +446,11 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base | |
| 400 446 | 
             
            		ensure
         | 
| 401 447 | 
             
            		  self.unlock_task_if_last_updated(task_started)
         | 
| 402 448 | 
             
            		end
         | 
| 403 | 
            -
             | 
| 449 | 
            +
             | 
| 404 450 | 
             
            		# Start the same update process in five minutes
         | 
| 405 | 
            -
            		self.delay(:run_at => 1.minutes.from_now).update_rets | 
| 451 | 
            +
            		self.delay(:run_at => 1.minutes.from_now).update_rets
         | 
| 406 452 | 
             
            	end
         | 
| 407 | 
            -
             | 
| 453 | 
            +
             | 
| 408 454 | 
             
              def self.last_updated
         | 
| 409 455 | 
             
                if !Caboose::Setting.exists?(:name => 'rets_last_updated')
         | 
| 410 456 | 
             
                  Caboose::Setting.create(:name => 'rets_last_updated', :value => '2013-08-06T00:00:01')
         | 
| @@ -412,7 +458,7 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base | |
| 412 458 | 
             
                s = Caboose::Setting.where(:name => 'rets_last_updated').first
         | 
| 413 459 | 
             
                return DateTime.parse(s.value)
         | 
| 414 460 | 
             
              end
         | 
| 415 | 
            -
             | 
| 461 | 
            +
             | 
| 416 462 | 
             
              def self.last_purged
         | 
| 417 463 | 
             
                if !Caboose::Setting.exists?(:name => 'rets_last_purged')
         | 
| 418 464 | 
             
                  Caboose::Setting.create(:name => 'rets_last_purged', :value => '2013-08-06T00:00:01')
         | 
| @@ -420,36 +466,36 @@ class CabooseRets::RetsImporter # < ActiveRecord::Base | |
| 420 466 | 
             
                s = Caboose::Setting.where(:name => 'rets_last_purged').first
         | 
| 421 467 | 
             
                return DateTime.parse(s.value)
         | 
| 422 468 | 
             
              end
         | 
| 423 | 
            -
             | 
| 469 | 
            +
             | 
| 424 470 | 
             
              def self.save_last_updated(d)
         | 
| 425 471 | 
             
                s = Caboose::Setting.where(:name => 'rets_last_updated').first
         | 
| 426 472 | 
             
                s.value = d.strftime('%FT%T')
         | 
| 427 473 | 
             
                s.save
         | 
| 428 474 | 
             
              end
         | 
| 429 | 
            -
             | 
| 475 | 
            +
             | 
| 430 476 | 
             
              def self.save_last_purged(d)
         | 
| 431 477 | 
             
                s = Caboose::Setting.where(:name => 'rets_last_purged').first
         | 
| 432 478 | 
             
                s.value = d.strftime('%FT%T')
         | 
| 433 479 | 
             
                s.save
         | 
| 434 480 | 
             
              end
         | 
| 435 | 
            -
             | 
| 481 | 
            +
             | 
| 436 482 | 
             
              def self.task_is_locked
         | 
| 437 483 | 
             
                return Caboose::Setting.exists?(:name => 'rets_update_running')
         | 
| 438 484 | 
             
              end
         | 
| 439 | 
            -
             | 
| 485 | 
            +
             | 
| 440 486 | 
             
              def self.lock_task
         | 
| 441 487 | 
             
                d = DateTime.now.utc - 5.hours
         | 
| 442 488 | 
             
                Caboose::Setting.create(:name => 'rets_update_running', :value => d.strftime('%F %T'))
         | 
| 443 489 | 
             
                return d
         | 
| 444 490 | 
             
              end
         | 
| 445 | 
            -
             | 
| 491 | 
            +
             | 
| 446 492 | 
             
              def self.unlock_task
         | 
| 447 493 | 
             
                Caboose::Setting.where(:name => 'rets_update_running').first.destroy
         | 
| 448 494 | 
             
              end
         | 
| 449 | 
            -
             | 
| 495 | 
            +
             | 
| 450 496 | 
             
              def self.unlock_task_if_last_updated(d)
         | 
| 451 497 | 
             
                setting = Caboose::Setting.where(:name => 'rets_update_running').first
         | 
| 452 498 | 
             
                self.unlock_task if setting && d.strftime('%F %T') == setting.value
         | 
| 453 499 | 
             
              end
         | 
| 454 | 
            -
             | 
| 500 | 
            +
             | 
| 455 501 | 
             
            end
         | 
    
        data/lib/caboose_rets/version.rb
    CHANGED