1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
module Stif
module ReflexSynchronization
class << self
attr_accessor :imported_count, :updated_count, :deleted_count, :processed
def reset_counts
self.imported_count = 0
self.updated_count = 0
self.deleted_count = 0
self.processed = []
end
def processed_counts
{
imported: self.imported_count,
updated: self.updated_count,
deleted: self.deleted_count
}
end
def log_processing_time message, time
Rails.logger.info "Reflex:sync - #{message} done in #{time} seconds"
end
def increment_counts prop_name, value
self.send("#{prop_name}=", self.send(prop_name) + value)
end
def defaut_referential
StopAreaReferential.find_by(name: "Reflex")
end
def find_by_object_id objectid
Chouette::StopArea.find_by(objectid: objectid)
end
def save_if_valid object
if object.valid?
object.save
else
Rails.logger.error "Reflex:sync - #{object.class.model_name} with objectid #{object.objectid} can't be saved - errors : #{object.errors.messages}"
end
end
def synchronize
reset_counts
['getOR', 'getOP'].each do |method|
start = Time.now
results = Reflex::API.new().process(method)
log_processing_time("Process #{method}", Time.now - start)
stop_areas = results[:Quay] | results[:StopPlace]
time = Benchmark.measure do
stop_areas.each do |entry|
next unless is_valid_type_of_place_ref?(method, entry)
entry['TypeOfPlaceRef'] = self.stop_area_area_type entry, method
self.create_or_update_stop_area entry
self.processed << entry['id']
end
end
log_processing_time("Create or update StopArea", time.real)
time = Benchmark.measure do
stop_areas.map{|entry| self.stop_area_set_parent(entry)}
end
log_processing_time("StopArea set parent", time.real)
end
# Set deleted_at for item not returned by api since last sync
time = Benchmark.measure { self.set_deleted_stop_area }
log_processing_time("StopArea #{self.deleted_count} deleted", time.real)
self.processed_counts
end
def is_valid_type_of_place_ref? method, entry
return true if entry["TypeOfPlaceRef"].nil?
return true if method == 'getOR' && ['ZDL', 'LDA', 'ZDE'].include?(entry["TypeOfPlaceRef"])
return true if method == 'getOP' && ['ZDE', 'ZDL'].include?(entry["TypeOfPlaceRef"])
end
def stop_area_area_type entry, method
from = method.last
from = 'r' if entry['OBJECT_STATUS'] == 'REFERENCE_OBJECT'
from = 'p' if entry['OBJECT_STATUS'] == 'LOCAL_OBJECT'
type = entry['TypeOfPlaceRef']
if entry['type'] == 'Quay'
type = "zde#{from}"
else
type = "zdl#{from}" if type != 'LDA'
end
type.downcase
end
def set_deleted_stop_area
deleted = Chouette::StopArea.where(deleted_at: nil).pluck(:objectid).uniq - self.processed.uniq
deleted.each_slice(50) do |object_ids|
Chouette::StopArea.where(objectid: object_ids).update_all(deleted_at: Time.now)
end
increment_counts :deleted_count, deleted.size
end
def stop_area_set_parent entry
return false unless entry['parent'] || entry['quays']
stop = self.find_by_object_id entry['id']
return false unless stop
if entry['parent']
stop.parent = self.find_by_object_id entry['parent']
save_if_valid(stop) if stop.changed?
end
if entry['quays']
entry['quays'].each do |id|
children = self.find_by_object_id id
next unless children
children.parent = stop
save_if_valid(children) if children.changed?
end
end
end
def access_point_access_type entry
if entry['IsEntry'] == 'true' && entry['IsExit'] == 'true'
'in_out'
elsif entry['IsEntry'] == 'true'
'in'
elsif entry['IsExit'] == 'true'
'out'
end
end
def create_or_update_access_point entry, stop_area
access = Chouette::AccessPoint.find_or_create_by(objectid: entry['id'])
# Hack, on save object_version will be incremented by 1
entry['version'] = entry['version'].to_i + 1 if access.persisted?
access.access_type = self.access_point_access_type(entry)
access.stop_area = stop_area
{
:name => 'Name',
:object_version => 'version',
:zip_code => 'PostalRegion',
:city_name => 'Town'
}.each do |k, v| access[k] = entry[v] end
if entry['gml:pos']
access['longitude'] = entry['gml:pos'][:lng]
access['latitude'] = entry['gml:pos'][:lat]
end
save_if_valid(access) if access.changed?
end
def create_or_update_stop_area entry
stop = Chouette::StopArea.find_or_create_by(objectid: entry['id'])
stop.deleted_at = nil
stop.stop_area_referential = self.defaut_referential
{
:comment => 'Description',
:name => 'Name',
:area_type => 'TypeOfPlaceRef',
:object_version => 'version',
:zip_code => 'PostalRegion',
:city_name => 'Town',
:stif_type => 'OBJECT_STATUS'
}.each do |k, v| stop[k] = entry[v] end
# TODO: use stop.update_attributes instead of the above
if entry['gml:pos']
stop['longitude'] = entry['gml:pos'][:lng]
stop['latitude'] = entry['gml:pos'][:lat]
end
if stop.changed?
stop.created_at = entry[:created]
stop.import_xml = entry[:xml]
prop = stop.new_record? ? :imported_count : :updated_count
increment_counts prop, 1
save_if_valid(stop)
end
# Create AccessPoint from StopPlaceEntrance
if entry[:stop_place_entrances]
entry[:stop_place_entrances].each do |entrance|
self.create_or_update_access_point entrance, stop
end
end
stop
end
end
end
end
|