allhomes_xml 0.1.0

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.
@@ -0,0 +1,4 @@
1
+ # Require all other files
2
+ Dir[File.dirname(__FILE__) + '/allhomes_xml/*.rb'].each {|file| require file }
3
+ # Require price files
4
+ Dir[File.dirname(__FILE__) + '/allhomes_xml/price/*.rb'].each {|file| require file }
@@ -0,0 +1,17 @@
1
+ module AllhomesXml
2
+
3
+ # Storage container for agents - primary and secondary(optional)
4
+ class Agents
5
+
6
+ attr_accessor :primary_agent, :secondary_agent
7
+
8
+ def primary hash
9
+ self.primary_agent = hash
10
+ end
11
+ def secondary hash
12
+ self.secondary_agent = hash
13
+ end
14
+
15
+ end
16
+
17
+ end
File without changes
@@ -0,0 +1,7 @@
1
+ module AllhomesXml
2
+
3
+ # Storage container for attributes
4
+ class Attributes < Hash
5
+ end
6
+
7
+ end
@@ -0,0 +1,31 @@
1
+ module AllhomesXml
2
+
3
+ # Creates a template listing for use by higher level classes
4
+ class BasicListing
5
+
6
+ # All generic attributes common to all listings
7
+ attr_accessor :id, :property_type, :agency_id, :agents, :unit_number, :street_number, :street_name, :street_type, :complex, :suburb, :postcode, :state, :country, :hide_address, :title, :description, :eer, :photos, :price, :exhibitions, :bedrooms, :bathrooms, :ensuites, :carspaces, :garagespaces, :attributes
8
+
9
+ def required
10
+ [:id, :agents, :suburb, :property_type, :postcode]
11
+ end
12
+
13
+ # Creates a new basic listing - takes a hash full of attributes as an argument
14
+ def initialize(args)
15
+
16
+ args.each_pair do |attribute, value|
17
+
18
+ # Remove junk off the beginning/end of strings
19
+ value.strip! if value.instance_of? String and not attribute == :description
20
+
21
+ send "#{attribute}=", value
22
+
23
+ end
24
+
25
+ required.each { |field| raise "#{field} field cannot be blank - property #{id}!" if self.send(field).blank? }
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,15 @@
1
+ module AllhomesXml
2
+
3
+ module Price
4
+
5
+ class BasicPrice
6
+ def initialize(args)
7
+ args.each_pair do |attribute, value|
8
+ send "#{attribute}=", value
9
+ end
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,7 @@
1
+ module AllhomesXml
2
+
3
+ # Storage container for exhibitions
4
+ class AllhomesXml::Exhibitions < Array
5
+ end
6
+
7
+ end
@@ -0,0 +1,416 @@
1
+ module AllhomesXml
2
+
3
+ class Generator
4
+
5
+ COMMERCIAL_PROPERTY_TYPES = %w(office hotel industrial motel retail warehouse)
6
+
7
+ # Creates a new XML class to house all data
8
+ # Takes an Allhomes username and password hash as it's argument
9
+ def initialize(args)
10
+
11
+ @username = args[:username]
12
+ @password = args[:password]
13
+ @properties = []
14
+
15
+ end
16
+
17
+ def << property
18
+ @properties << property
19
+ end
20
+
21
+ # Generates the XML
22
+ def generate
23
+
24
+ require 'builder'
25
+
26
+ xml = Builder::XmlMarkup.new :indent => 4
27
+
28
+ xml.instruct! :xml, :version => "1.0"
29
+
30
+ time = Time.now
31
+ xml.listings({:feedId => time.to_i,
32
+ :generated => time.xmlschema,
33
+ :username => @username,
34
+ :password => @password,
35
+ :xmlns => "http://www.allhomes.com.au/2008/v1/listingFeed",
36
+ :'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
37
+ :'xsi:schemaLocation' => "http://www.allhomes.com.au/2008/v1/listingFeed listingFeed.xsd "}) do
38
+
39
+
40
+ @properties.each do |property|
41
+
42
+ # Set up a quick variable for checking if this property is a sale listing
43
+ property.class.name == "AllhomesXml::SaleListing" ? sale_listing = true : sale_listing = false
44
+
45
+ if sale_listing
46
+
47
+ # Attributes for the initial tag
48
+ listingAttributes = { :saleStatus => get_sale_status(property),
49
+ :uniqueId => "S#{property.id}"}
50
+
51
+ # If this property is sold, add the attributes to the initial tag
52
+ if property.exchange_date and property.sale_price
53
+ listingAttributes.update({:saleDate => property.exchange_date.strftime("%Y-%m-%d"), :salePrice => property.sale_price})
54
+ end
55
+
56
+ else
57
+
58
+ # Attributes for the initial tag
59
+ listingAttributes = { :rentalStatus => get_rent_status(property),
60
+ :uniqueId => "R#{property.id}"}
61
+
62
+ # If the property is rented, add the rented date and price
63
+ if property.rented and property.rented_date and property.rented_price
64
+ listingAttributes.update({:rentedDate => property.rented_date.strftime("%Y-%m-%d"), :rentedPrice => property.rented_price})
65
+ end
66
+
67
+ end
68
+
69
+ # Generate initial tag
70
+ if COMMERCIAL_PROPERTY_TYPES.include? property.property_type
71
+ sale_listing ? opening_tag = "commercialSaleListing" : opening_tag = "commercialRentalListing"
72
+ else
73
+ sale_listing ? opening_tag = "residentialSaleListing" : opening_tag = "residentialRentalListing"
74
+ end
75
+
76
+ # Opening Tag
77
+ ######################################################
78
+ xml.tag!(opening_tag, listingAttributes) do
79
+
80
+ # Agent Details
81
+ ######################################################
82
+ xml.agentDetails do
83
+ xml.agencyId property.agency_id
84
+ xml.primaryContact do
85
+ xml.firstName property.agents.primary_agent[:firstname]
86
+ xml.lastName property.agents.primary_agent[:surname]
87
+ end
88
+
89
+ if sale_listing
90
+ if property.agents.secondary_agent
91
+ xml.alternativeContact do
92
+ xml.firstName property.agents.secondary_agent[:firstname]
93
+ xml.lastName property.agents.secondary_agent[:surname]
94
+ end
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ # Street Address
101
+ ######################################################
102
+ xml.streetAddress do
103
+
104
+ xml.unitNumber property.unit_number unless property.unit_number.blank?
105
+ xml.streetNumber property.street_number unless (property.street_number =~ /^[&\w\- ]+$/).nil?
106
+ xml.streetName property.street_name
107
+ xml.streetType property.street_type.upcase
108
+ xml.propertyName property.complex unless property.complex.blank?
109
+ xml.suburb property.suburb
110
+ xml.postCode property.postcode
111
+ xml.state property.state
112
+ xml.country "Australia"
113
+
114
+ if property.hide_address
115
+ xml.addressVisibility "HIDE_STREET_NUMBER_AND_NAME"
116
+ else
117
+ xml.addressVisibility "VISIBLE"
118
+ end
119
+
120
+ end
121
+
122
+ # Formal Address - Sale Only
123
+ ######################################################
124
+ if sale_listing and property.state == 'ACT'
125
+
126
+ xml.formalAddress do
127
+
128
+ xml.blockSection do
129
+
130
+ if (property.block =~ /[^0-9]/).nil?
131
+ xml.block property.block
132
+ else
133
+ xml.block
134
+ end
135
+ xml.section property.section
136
+
137
+ end
138
+
139
+ # end
140
+
141
+ end
142
+
143
+ end
144
+
145
+ # Title and Description
146
+ ######################################################
147
+ xml.title property.title
148
+ if property.description.blank?
149
+ xml.description 'No description available.'
150
+ else
151
+ xml.description property.description
152
+ end
153
+
154
+ # EER
155
+ ######################################################
156
+ xml.eer property.eer if not property.eer.blank? and not property.eer == 'N/A'
157
+
158
+ # Street Directory Reference
159
+ ######################################################
160
+ xml.streetDirectoryReference do
161
+
162
+ xml.type ""
163
+ xml.reference ""
164
+
165
+ end
166
+
167
+ # Listing Status
168
+ ######################################################
169
+ xml.listingStatus "active"
170
+
171
+ # Photos
172
+ ######################################################
173
+ unless property.photos.blank?
174
+
175
+ xml.images do
176
+
177
+ property.photos.each do |photo|
178
+
179
+ xml.image do
180
+
181
+ xml.imageReference photo[:url]
182
+ xml.caption photo[:caption] unless photo[:caption].blank?
183
+ xml.orderIndex photo[:order]
184
+
185
+ end
186
+
187
+ end
188
+
189
+ end
190
+
191
+ end
192
+
193
+ # Rental Availability - Rentals Only
194
+ ######################################################
195
+ if not sale_listing and (property.available_from or property.available_to)
196
+
197
+ xml.availability do
198
+
199
+ xml.from property.available_from.strftime("%Y-%m-%d") if property.available_from
200
+ xml.to property.available_to.strftime("%Y-%m-%d") if property.available_to
201
+
202
+ end
203
+
204
+ end
205
+
206
+ # Sale Authority - Sale Only
207
+ ######################################################
208
+ xml.saleAuthority "exclusive" if sale_listing
209
+
210
+ # Price
211
+ ######################################################
212
+ if sale_listing
213
+
214
+ case property.price.class.name
215
+
216
+ # If the property is an auction
217
+ when "AllhomesXml::Price::Auction"
218
+
219
+ xml.auction do
220
+
221
+ xml.date property.price.date.strftime("%Y-%m-%d")
222
+ xml.startTime property.price.start.strftime("%H:%M:%S")
223
+ xml.unpublishedPriceEstimate property.price.estimate unless property.price.estimate.blank?
224
+
225
+ end
226
+
227
+ # If the property is by tender
228
+ when "AllhomesXml::Price::Tender"
229
+
230
+ xml.tender do
231
+
232
+ xml.closingDate property.price.date.xmlschema
233
+
234
+ end
235
+
236
+ # If the property is by Expressions of Interest
237
+ when "AllhomesXml::Price::EOI"
238
+
239
+ xml.expressionOfInterest do
240
+
241
+ xml.closingDate property.price.date.xmlschema
242
+
243
+ end
244
+
245
+ # If the property is sold by plain old price
246
+ when "AllhomesXml::Price::Range"
247
+
248
+ xml.price do
249
+
250
+ xml.lower property.price.low
251
+ xml.upper property.price.high
252
+
253
+ end
254
+
255
+ when "AllhomesXml::Price::Fixed"
256
+
257
+ xml.price do
258
+
259
+ xml.lower property.price.price
260
+ property.offers_over ? xml.offersAbove("true") : xml.offersAbove("false")
261
+
262
+ end
263
+
264
+ # If the property is by negotiation
265
+ else
266
+
267
+ xml.price ""
268
+
269
+ end
270
+
271
+ # If rental listing
272
+ else
273
+
274
+ xml.price do
275
+
276
+ xml.lower property.price unless property.price.blank?
277
+ xml.paymentPeriod "weekly" unless property.price.blank?
278
+
279
+ end
280
+
281
+ end
282
+
283
+ # Exhibitions
284
+ ##################
285
+ unless property.exhibitions.blank?
286
+
287
+ xml.exhibitions do
288
+
289
+ property.exhibitions.each do |opentime|
290
+
291
+ xml.exhibition do
292
+
293
+ xml.date opentime[:date].strftime("%Y-%m-%d")
294
+ xml.startTime opentime[:start].strftime("%H:%M:%S")
295
+ xml.endTime opentime[:finish].strftime("%H:%M:%S")
296
+
297
+ end
298
+
299
+ end
300
+
301
+ end
302
+
303
+ end
304
+
305
+ # Rental Purpose
306
+ ##################
307
+ xml.rentalPurpose 'residential' if not sale_listing and not COMMERCIAL_PROPERTY_TYPES.include?(property.property_type)
308
+
309
+ # Property Details
310
+ ##################
311
+ xml.propertyDetails do
312
+
313
+ # House & Block Size
314
+ ##################
315
+ xml.buildingDetails do
316
+
317
+ if sale_listing and property.floor_area and not property.floor_area.to_f == 0
318
+
319
+ xml.buildingSize property.floor_area.to_f
320
+
321
+ end
322
+
323
+ end
324
+
325
+ xml.landDetails do
326
+
327
+ xml.blockSize property.block_size if sale_listing and property.block_size and (property.block_size =~ /[^0-9.]/).nil?
328
+
329
+ end
330
+
331
+ # UV
332
+ ##################
333
+ xml.unimprovedLandValue(property.uv) if sale_listing and not property.uv.blank?
334
+
335
+ # Property Type
336
+ ##################
337
+ xml.propertyType property.property_type
338
+
339
+ # Features
340
+ ##################
341
+ # If we're not dealing with a commercial property, output the features
342
+ unless COMMERCIAL_PROPERTY_TYPES.include? property.property_type
343
+
344
+ # Features unique to sales / rentals
345
+ features = {}
346
+ if sale_listing
347
+ features['coreArea'] = true if property.core_area
348
+ features['bodyCorporate'] = true if property.body_corporate
349
+ features['plansApproved'] = true if property.plans_approved
350
+ else
351
+ features['petsAllowed'] = true if property.pets_allowed
352
+ features['shortTermLease'] = true if property.short_term_lease
353
+ end
354
+
355
+ # Features common to both sales / rentals
356
+ features[:bedrooms] = property.bedrooms unless property.bedrooms.blank?
357
+ features[:bathrooms] = property.bathrooms unless property.bathrooms.blank?
358
+ features[:ensuites] = property.ensuites unless property.ensuites.blank?
359
+ features[:carportSpaces] = property.carspaces unless property.carspaces.blank?
360
+ features[:garageSpaces] = property.garagespaces unless property.garagespaces.blank?
361
+
362
+ # Merge extra attributes
363
+ features.update property.attributes
364
+
365
+ # Features tag
366
+ xml.features features
367
+
368
+ end
369
+
370
+ end
371
+
372
+ end
373
+
374
+ end
375
+
376
+ end
377
+
378
+ end
379
+
380
+ protected
381
+
382
+ def get_sale_status property
383
+
384
+ if property.sold
385
+ 'sold'
386
+ else
387
+ if property.withdrawn
388
+ 'withdrawn'
389
+ elsif property.under_offer
390
+ 'underOffer'
391
+ else
392
+ 'forSale'
393
+ end
394
+ end
395
+
396
+ end
397
+
398
+ def get_rent_status property
399
+
400
+ if property.rented
401
+ 'rented'
402
+ else
403
+ if property.withdrawn
404
+ 'withdrawn'
405
+ elsif property.under_application
406
+ 'underApplication'
407
+ else
408
+ 'forRent'
409
+ end
410
+ end
411
+
412
+ end
413
+
414
+ end
415
+
416
+ end