Class: ODDB::VaccinePlugin

Inherits:
Plugin show all
Defined in:
src/plugin/vaccines.rb,
test/test_plugin/vaccines.rb

Defined Under Namespace

Classes: ParsedActiveAgent, ParsedPackage, ParsedRegistration, ParsedSequence

Constant Summary

SWISSMEDIC_SERVER =
'www.swissmedic.ch'
INDEX_PATH =
'/daten/00080/00254/index.html?lang=de'
MEDDATA_SERVER =
MeddataDelegator.new
DOSE_PATTERN =
/(\d+(?:[,.]\d+)?)\s*((?:\/\d+)|[^\s\d]*)?/u
ENDMULTI_PATTERN =
/\d+\s*Stk$/u
MULTI_PATTERN =
/(\d+\s+)\b(Fl|Fertigspr)\b/u
XLS_PATH =
'/files/pdf/B3.1.35-d.xls'
SIZE_PATTERN =
/(?:(?:(\d+(?:[.,]\d+)?)\s*x\s*)?(\d+(?:[.,]\d+)?))?\s*([^\d\s]*)$/u

Constants inherited from Plugin

ARCHIVE_PATH, RECIPIENTS

Instance Method Summary (collapse)

Methods inherited from Plugin

#l10n_sessions, #log_info, #recipients, #resolve_link, #update_rss_feeds

Methods included from HttpFile

#http_body, #http_file

Constructor Details

- (VaccinePlugin) initialize(app)

A new instance of VaccinePlugin



129
130
131
132
133
134
135
136
# File 'src/plugin/vaccines.rb', line 129

def initialize(app)
  super
  @active = []
  @created = []
  @updated = []
  @deactivated = []
  @latest_path = File.join(ARCHIVE_PATH, 'xls', 'vaccines-latest.xls')
end

Instance Method Details

- (Object) extract_latest_filepath(html)



144
145
146
147
148
149
150
# File 'src/plugin/vaccines.rb', line 144

def extract_latest_filepath(html)
  writer = VaccineIndexWriter.new
  formatter = HtmlFormatter.new(writer)
  parser = HtmlParser.new(formatter)
  parser.feed(html)  
  writer.path
end

- (Object) get_latest_file



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'src/plugin/vaccines.rb', line 151

def get_latest_file
  if((index = http_body(SWISSMEDIC_SERVER, INDEX_PATH)) \
     && (path = extract_latest_filepath(index)) \
     && (download = http_body(SWISSMEDIC_SERVER, path)))
    latest = ''
    if(File.exist?(@latest_path))
      latest = File.read(@latest_path)
    end
    if(download[-1] != ?\n)
      download << "\n"
    end
    if(download != latest)
      target = File.join(ARCHIVE_PATH, 'xls',
                         @@today.strftime('vaccines-%Y.%m.%d.xls'))
      File.open(target, 'w') { |fh| fh.puts(download) }
      target
    end
  end
end

- (Object) get_packages(reg, active = nil)



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'src/plugin/vaccines.rb', line 170

def get_packages(reg, active=nil)
  criteria = { :ean => "7680" + reg.iksnr }
  template = { :info => [0,1] }
  seqs = reg.sequences
  MEDDATA_SERVER.session(:refdata) { |session|
    results = session.search(criteria)
    if(results.size == 1 && seqs.size == 1)
      result = results.first
      detail = session.detail(result, template)
      pack = parse_refdata_detail(detail[:info])
      seqs.first.packages.store(pack.ikscd, pack)
    else
      results.each { |result|
        detail = session.detail(result, template)
        pack = parse_refdata_detail(detail[:info])
        sequence = nil
        activeseq = nil
        if(active && (activepac = active.package(pack.ikscd)) \
          && (activeseq = activepac.sequence))
          sequence = seqs.find { |seq|
            seq.seqnr == activeseq.seqnr
          }
        end
        sequence ||= seqs.find { |seq|
          (sd = seq.dose) && (pd = pack.dose) \
            && (pd == sd || (sd.unit.to_s.empty? && sd.qty == pd.qty))
        }
        ## assign a new sequence since none could be identified
        sequence ||= seqs.find { |seq|
          seq.packages.empty? || seq.dose.nil?
        }
        if(sequence.nil?) 
          sequence = seqs.first.dup
          reg.sequences.push(sequence)
        end
        if(activeseq && sequence.seqnr.nil?)
          sequence.seqnr = activeseq.seqnr
        end
        if(sequence.dose.nil?)
          sequence.dose = pack.dose
        end
        sequence.packages.store(pack.ikscd, pack)
      }
    end
  }
end

- (Object) parse_refdata_detail(str)



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'src/plugin/vaccines.rb', line 216

def parse_refdata_detail(str)
  ean = str[0,13]
  name = str[13..-1]
  if(/^7680[0-9]{9}$/u.match(ean))
    pack = ParsedPackage.new
    pack.ikscd = ean[-4..-2,]
    mult, desc = nil
    if(mstring = name.slice!(ENDMULTI_PATTERN))
      mult, desc = mstring.split(/\s+/u, 2)
      name.strip!
    end
    if(sstring = name.slice!(SIZE_PATTERN))
      qty = $2.to_i
      if($1)
        qty *= $1.to_i
      end
      unit = $3
      if(qty == 0)
        qty = 1
      end
      if(mstring = name.slice!(MULTI_PATTERN))
        mult ||= mstring.split(/\s+/u, 2).first
      end
      if(mult)
        sstring = mult + ' x ' + sstring
        qty = qty.to_i * mult.to_i
      end
      pack.sizestring = sstring
      pack.size = Dose.new(qty, unit)
    else
      pack.size = Dose.new(1)
    end
    if(dstring = name.slice!(DOSE_PATTERN))
      pack.dose = Dose.new(*dstring.split(/\s+/u, 2))
    end
    pack
  end
end

- (Object) parse_worksheet(worksheet)



254
255
256
257
258
259
260
261
262
263
# File 'src/plugin/vaccines.rb', line 254

def parse_worksheet(worksheet)
  registrations = {}
  worksheet.each { |row|
    if(row && (pair = parse_worksheet_row(row)))
      reg, seqs = pair
      (registrations[reg.iksnr] ||= reg).sequences.concat(seqs)
    end
  }
  registrations
end

- (Object) parse_worksheet_row(row)



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'src/plugin/vaccines.rb', line 264

def parse_worksheet_row(row)
  if((iksval = row_at(row, 1)) \
     && /^[0-9]{3,5}(\.[0-9]+)?$/u.match(iksval.to_s))
    reg = ParsedRegistration.new
    reg.iksnr = sprintf('%05i', iksval.to_i)
    ## missing as of 11/2009
    #reg.indication = row_at(row, 2)
    reg.ikscat = row_at(row, 2)
    ## missing as of 02/2008
    #reg.out_of_trade = row_at(row, 9) == 'x'
    reg.company = row_at(row, 8)
    if((date = row_at(row, 9)) && date.is_a?(Date))
      reg.expiration_date = date
    end
    seq = ParsedSequence.new
    if(atc = row_at(row, 10))
      seq.atc_class = atc.gsub(/[^A-Z0-9]/u, '')
    end
    seqs = [seq]
    name = row_at(row, 0)
    if(match = /^(.*?)(\d+)\/(\d+)$/u.match(name))
      seq2 = seq.dup
      seq.name = match[1] + match[2]
      seq2.name = match[1] + match[3]
      seqs = [seq, seq2]
    else
      seq.name = name
    end
    [reg, seqs]
  end
end

- (Object) registrations_from_xls(path)



295
296
297
298
299
300
301
# File 'src/plugin/vaccines.rb', line 295

def registrations_from_xls(path)
  workbook = Spreadsheet.open(path)
  registrations = parse_worksheet(workbook.worksheet(0))
  registrations.each_value { |reg|
    get_packages(reg, @app.registration(reg.iksnr))
  }
end

- (Object) report



302
303
304
305
306
307
# File 'src/plugin/vaccines.rb', line 302

def report
  fmt = "%-14s %3i"
  ['@created', '@updated', '@deactivated'].collect { |var|
    sprintf(fmt, var[1..-1].capitalize << ':', instance_variable_get(var).size)
  }.join("\n")
end

- (Object) row_at(row, index)



308
309
310
# File 'src/plugin/vaccines.rb', line 308

def row_at(row, index)
  row[index]
end

- (Object) update(manual_download = nil)



137
138
139
140
141
142
143
# File 'src/plugin/vaccines.rb', line 137

def update(manual_download=nil)
  if(path = (manual_download || get_latest_file))
    update_registrations(registrations_from_xls(path))
    FileUtils.cp(path, @latest_path) 
    @app.rebuild_atc_chooser
  end
end

- (Object) update_atc_class(seq)



311
312
313
314
315
316
317
318
# File 'src/plugin/vaccines.rb', line 311

def update_atc_class(seq)
  if((code = seq.atc_class) \
     && !(atc = @app.atc_class(code)))
    begin
      atc = @app.create(Persistence::Pointer.new([:atc_class, code]))
    end while((code = atc.parent_code) && !@app.atc_class(code))
  end
end

- (Object) update_company(data)



319
320
321
322
323
324
325
326
327
328
# File 'src/plugin/vaccines.rb', line 319

def update_company(data)
  if((name = data.delete(:company)) && !name.empty?)
    company = @app.company_by_name(name)
    if(company.nil?)
      pointer = Persistence::Pointer.new(:company)
      company = @app.update(pointer.creator, {:name => name}, :swissmedic)
    end
    data.store(:company, company.pointer)
  end
end

- (Object) update_indication(data)



329
330
331
332
333
334
335
336
337
338
# File 'src/plugin/vaccines.rb', line 329

def update_indication(data)
  if((text = data.delete(:indication)) && !text.empty?)
    indication = @app.indication_by_text(text)
    if(indication.nil?)
      pointer = Persistence::Pointer.new(:indication)
      indication = @app.update(pointer.creator, { 'de' => text}, :swissmedic)
    end
    data.store(:indication, indication.pointer)
  end
end

- (Object) update_package(pack, seq_pointer)



339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'src/plugin/vaccines.rb', line 339

def update_package(pack, seq_pointer)
  pointer = seq_pointer + [:package, pack.ikscd]
  registration = seq_pointer.parent.resolve(@app)
  ## prevent the creation of duplicate ean-codes: if the package exists in 
  #  another sequence, it's probably been edited manually - use it.
  if(existing = registration.package(pack.ikscd))
    pointer = existing.pointer
  else
    pointer = pointer.creator
  end
  package = @app.update(pointer, {}, :swissmedic)
  ptr = if(part = package.parts.first)
          part.pointer
        else
          (package.pointer + :part).creator
        end
  @app.update(ptr, pack.data, :swissmedic)
  package
end

- (Object) update_registration(reg)



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'src/plugin/vaccines.rb', line 358

def update_registration(reg)
  data = reg.data
  data.store(:inactive_date, nil)
  update_company(data)
  update_indication(data)
  pointer = nil
  iksnr = reg.iksnr
  registration = @app.registration(iksnr)
  @active.push(iksnr)
  reg.assign_seqnrs(registration)
  if(registration)
    @updated.push(iksnr)
    pointer = registration.pointer
    @app.update(pointer, data, :swissmedic) unless(data.empty?)
  else
    @created.push(iksnr)
    pointer = Persistence::Pointer.new([:registration, reg.iksnr])
    registration = @app.update(pointer.creator, data)
  end
  reg.sequences.each { |seq| update_sequence(seq, pointer) }
  unless(reg.sequences.empty?)
    registration.each_sequence { |sequence|
      unless(reg.sequences.any? { |seq| 
        seq.seqnr == sequence.seqnr })
        @app.delete(sequence.pointer)
      end
    }
  end
  if(ikscat = reg.ikscat)
    registration.each_package { |pack|
      @app.update(pack.pointer, {:ikscat => ikscat}, :swissmedic)
    }
  end
end

- (Object) update_registrations(registrations)



392
393
394
395
396
397
398
399
400
401
402
# File 'src/plugin/vaccines.rb', line 392

def update_registrations(registrations)
  registrations.each_value { |reg|
    update_registration(reg)
  }
  @app.registrations.each_value { |reg|
    if(reg.vaccine && !@active.include?(reg.iksnr))
      @deactivated.push(reg.iksnr)
      @app.update(reg.pointer, {:inactive_date => @@today}, :swissmedic)
    end
  } unless @active.empty?
end

- (Object) update_sequence(seq, reg_pointer)



403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'src/plugin/vaccines.rb', line 403

def update_sequence(seq, reg_pointer)
  pointer = reg_pointer + [:sequence, seq.seqnr]
  update_atc_class(seq)
  sequence = @app.update(pointer.creator, seq.data, :swissmedic)
  seq.packages.each_value { |pack| update_package(pack, pointer) }
  seq.active_agents.each { |act| 
    update_active_agent(act, pointer) }
  ## remove old packages
  unless(seq.packages.empty?)
    sequence.each_package { |package|
      unless(seq.packages.include?(package.ikscd))
        @app.delete(package.pointer)
      end
    }
  end
end

- (Object) update_substance(substance_name)



419
420
421
422
423
424
# File 'src/plugin/vaccines.rb', line 419

def update_substance(substance_name)
  @app.substance(substance_name) or begin
    pointer = Persistence::Pointer.new(:substance)
    @app.update(pointer.creator, {'de' => substance_name}, :swissmedic)
  end
end