aemo 0.1.27 → 0.1.28

Sign up to get free protection for your applications and to get access to all the features.
data/lib/aemo/nem13.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  module AEMO
2
2
  class NEM13
3
-
4
3
  end
5
- end
4
+ end
data/lib/aemo/nmi.rb CHANGED
@@ -15,9 +15,10 @@ module AEMO
15
15
  'VIC' => 'Victoria',
16
16
  'WA' => 'Western Australia',
17
17
  'NT' => 'Northern Territory'
18
- }
19
- # NMI_ALLOCATIONS as per AEMO Documentation at http://aemo.com.au/Electricity/Policies-and-Procedures/Retail-and-Metering/~/media/Files/Other/Retail%20and%20Metering/NMI_Allocation_List_v7_June_2012.ashx
20
- # Last accessed 2015-02-04
18
+ }.freeze
19
+
20
+ # NMI_ALLOCATIONS as per AEMO Documentation at http://aemo.com.au/Electricity/Policies-and-Procedures/Retail-and-Metering/~/media/Files/Other/Retail% 20and% 20Metering/NMI_Allocation_List_v7_June_2012.ashx
21
+ # Last accessed 2016-05-15
21
22
  NMI_ALLOCATIONS = {
22
23
  'ACTEWP' => {
23
24
  title: 'Actew Distribution Ltd and Jemena Networks (ACT) Pty Ltd',
@@ -192,7 +193,7 @@ module AEMO
192
193
  state: 'TAS',
193
194
  type: 'electricity',
194
195
  includes: [
195
- /^(T[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
196
+ /^(T[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/
196
197
  ],
197
198
  excludes: [
198
199
  ]
@@ -395,17 +396,17 @@ module AEMO
395
396
  excludes: [
396
397
  ]
397
398
  }
398
- }
399
+ }.freeze
399
400
  # Transmission Node Identifier Codes are loaded from a json file
400
401
  # Obtained from http://www.nemweb.com.au/
401
402
  #
402
403
  # See /lib/data for further data manipulation required
403
- TNI_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__),'..','data','aemo-tni.json')))
404
+ TNI_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__), '..', 'data', 'aemo-tni.json'))).freeze
404
405
  # Distribution Loss Factor Codes are loaded from a json file
405
- # Obtained from MSATS, matching to DNSP from file http://www.aemo.com.au/Electricity/Market-Operations/Loss-Factors-and-Regional-Boundaries/~/media/Files/Other/loss%20factors/DLF_FINAL_V2_2014_2015.ashx
406
+ # Obtained from MSATS, matching to DNSP from file http://www.aemo.com.au/Electricity/Market-Operations/Loss-Factors-and-Regional-Boundaries/~/media/Files/Other/loss% 20factors/DLF_FINAL_V2_2014_2015.ashx
406
407
  # Last accessed 2015-02-06
407
408
  # See /lib/data for further data manipulation required
408
- DLF_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__),'..','data','aemo-dlf.json')))
409
+ DLF_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__), '..', 'data', 'aemo-dlf.json'))).freeze
409
410
 
410
411
  # [String] National Meter Identifier
411
412
  @nmi = nil
@@ -424,20 +425,24 @@ module AEMO
424
425
 
425
426
  attr_accessor :nmi, :msats_detail, :tni, :dlf, :customer_classification_code, :customer_threshold_code, :jurisdiction_code, :classification_code, :status, :address, :meters, :roles, :data_streams
426
427
 
427
- # Initialize a NEM12 file
428
+ # Initialize a NMI file
428
429
  #
429
430
  # @param nmi [String] the National Meter Identifier (NMI)
430
431
  # @param options [Hash] a hash of options
432
+ # @option options [Hash] :msats_detail MSATS details as per #parse_msats_detail requirements
431
433
  # @return [AEMO::NMI] an instance of AEMO::NMI is returned
432
- def initialize(nmi,options={})
433
- raise ArgumentError.new("NMI is not a string") unless nmi.is_a?(String)
434
- raise ArgumentError.new("NMI is not 10 characters") unless nmi.length == 10
435
- raise ArgumentError.new("NMI is not constructed with valid characters") unless AEMO::NMI.valid_nmi?(nmi)
434
+ def initialize(nmi, options = {})
435
+ raise ArgumentError, 'NMI is not a string' unless nmi.is_a?(String)
436
+ raise ArgumentError, 'NMI is not 10 characters' unless nmi.length == 10
437
+ raise ArgumentError, 'NMI is not constructed with valid characters' unless AEMO::NMI.valid_nmi?(nmi)
438
+
439
+ @nmi = nmi
440
+ @meters = []
441
+ @roles = {}
442
+ @data_streams = []
443
+ @msats_detail = options[:msats_detail]
436
444
 
437
- @nmi = nmi
438
- @meters = []
439
- @roles = {}
440
- @data_streams = []
445
+ parse_msats_detail unless @msats_detail.nil?
441
446
  end
442
447
 
443
448
  # A function to validate the instance's nmi value
@@ -459,7 +464,7 @@ module AEMO
459
464
  # @param checksum_value [Integer] the checksum value to check against the current National Meter Identifier's checksum value
460
465
  # @return [Boolean] whether or not the checksum is valid
461
466
  def valid_checksum?(checksum_value)
462
- checksum_value == self.checksum
467
+ checksum_value == checksum
463
468
  end
464
469
 
465
470
  # Checksum is a function to calculate the checksum value for a given National Meter Identifier
@@ -469,10 +474,8 @@ module AEMO
469
474
  summation = 0
470
475
  @nmi.reverse.split(//).each_index do |i|
471
476
  value = nmi[nmi.length - i - 1].ord
472
- if(i % 2 == 0)
473
- value = value * 2
474
- end
475
- value = value.to_s.split(//).map{|i| i.to_i}.reduce(:+)
477
+ value *= 2 if i.even?
478
+ value = value.to_s.split(//).map(&:to_i).reduce(:+)
476
479
  summation += value
477
480
  end
478
481
  checksum = (10 - (summation % 10)) % 10
@@ -482,18 +485,26 @@ module AEMO
482
485
  # Provided MSATS is configured, gets the MSATS data for the NMI
483
486
  #
484
487
  # @return [Hash] MSATS NMI Detail data
485
- def raw_msats_nmi_detail(options={})
486
- raise ArgumentError, 'MSATS has no authentication credentials' unless AEMO::MSATS.can_authenticate?
487
-
488
- AEMO::MSATS.nmi_detail(@nmi,options)
488
+ def raw_msats_nmi_detail(options = {})
489
+ raise ArgumentError,
490
+ 'MSATS has no authentication credentials' unless AEMO::MSATS.can_authenticate?
491
+ AEMO::MSATS.nmi_detail(@nmi, options)
489
492
  end
490
493
 
491
494
  # Provided MSATS is configured, uses the raw MSATS data to augment NMI information
492
495
  #
493
496
  # @return [self] returns self
494
- def update_from_msats!(options={})
497
+ def update_from_msats!(options = {})
495
498
  # Update local cache
496
499
  @msats_detail = raw_msats_nmi_detail(options)
500
+ parse_msats_detail
501
+ self
502
+ end
503
+
504
+ # Turns raw MSATS junk into useful things
505
+ #
506
+ # @return [self] returns self
507
+ def parse_msats_detail
497
508
  # Set the details if there are any
498
509
  unless @msats_detail['MasterData'].nil?
499
510
  @tni = @msats_detail['MasterData']['TransmissionNodeIdentifier']
@@ -512,7 +523,7 @@ module AEMO
512
523
  unless @msats_detail['MeterRegister'].nil?
513
524
  meters = @msats_detail['MeterRegister']['Meter']
514
525
  meters = [meters] if meters.is_a?(Hash)
515
- meters.select{|x| !x['Status'].nil? }.each do |meter|
526
+ meters.select { |x| !x['Status'].nil? }.each do |meter|
516
527
  @meters << OpenStruct.new(
517
528
  status: meter['Status'],
518
529
  installation_type_code: meter['InstallationTypeCode'],
@@ -522,9 +533,9 @@ module AEMO
522
533
  serial_number: meter['SerialNumber']
523
534
  )
524
535
  end
525
- meters.select{|x| x['Status'].nil? }.each do |registers|
526
- m = @meters.find{|x| x.serial_number == registers['SerialNumber']}
527
- m.registers << register = OpenStruct.new(
536
+ meters.select { |x| x['Status'].nil? }.each do |registers|
537
+ m = @meters.find { |x| x.serial_number == registers['SerialNumber'] }
538
+ m.registers << OpenStruct.new(
528
539
  controlled_load: (registers['RegisterConfiguration']['Register']['ControlledLoad'] == 'Y'),
529
540
  dial_format: registers['RegisterConfiguration']['Register']['DialFormat'],
530
541
  multiplier: registers['RegisterConfiguration']['Register']['Multiplier'],
@@ -549,7 +560,13 @@ module AEMO
549
560
  data_streams = @msats_detail['DataStreams']['DataStream']
550
561
  data_streams = [data_streams] if data_streams.is_a?(Hash) # Deal with issue of only one existing
551
562
  data_streams.each do |stream|
552
- @data_streams << OpenStruct.new(suffix: stream['Suffix'], profile_name: stream['ProfileName'],averaged_daily_load: stream['AveragedDailyLoad'], data_stream_type: stream['DataStreamType'],status: stream['Status'])
563
+ @data_streams << OpenStruct.new(
564
+ suffix: stream['Suffix'],
565
+ profile_name: stream['ProfileName'],
566
+ averaged_daily_load: stream['AveragedDailyLoad'],
567
+ data_stream_type: stream['DataStreamType'],
568
+ status: stream['Status']
569
+ )
553
570
  end
554
571
  end
555
572
  self
@@ -561,7 +578,12 @@ module AEMO
561
578
  def friendly_address
562
579
  friendly_address = ''
563
580
  if @address.is_a?(Hash)
564
- friendly_address = @address.values.map{|x| x.is_a?(Hash) ? x.values.map{|y| y.is_a?(Hash) ? y.values.join(" ") : y }.join(" ") : x }.join(", ")
581
+ friendly_address = @address.values.map do |x|
582
+ if x.is_a?(Hash)
583
+ x = x.values.map { |y| y.is_a?(Hash) ? y.values.join(' ') : y }.join(' ')
584
+ end
585
+ x
586
+ end.join(', ')
565
587
  end
566
588
  friendly_address
567
589
  end
@@ -571,7 +593,7 @@ module AEMO
571
593
  # @param status [String] the stateus [C|R]
572
594
  # @return [Array<OpenStruct>] Returns an array of OpenStructs for Meters with the status provided
573
595
  def meters_by_status(status = 'C')
574
- @meters.select{|x| x.status == "#{status}"}
596
+ @meters.select { |x| x.status == status.to_s }
575
597
  end
576
598
 
577
599
  # Returns the data_stream OpenStructs for the requested status (A/I)
@@ -579,14 +601,14 @@ module AEMO
579
601
  # @param status [String] the stateus [A|I]
580
602
  # @return [Array<OpenStruct>] Returns an array of OpenStructs for the current Meters
581
603
  def data_streams_by_status(status = 'A')
582
- @data_streams.select{|x| x.status == "#{status}"}
604
+ @data_streams.select { |x| x.status == status.to_s }
583
605
  end
584
606
 
585
607
  # The current daily load
586
608
  #
587
609
  # @return [Integer] the current daily load for the meter
588
610
  def current_daily_load
589
- data_streams_by_status().inject(0) { |sum, stream| sum += stream.averaged_daily_load.to_i }
611
+ data_streams_by_status.map { |x| x.averaged_daily_load.to_i }.inject(0, :+)
590
612
  end
591
613
 
592
614
  # A function to validate the NMI provided
@@ -602,7 +624,7 @@ module AEMO
602
624
  # @param nmi [String] the NMI to check the checksum against
603
625
  # @param checksum_value [Integer] the checksum value to check against the current National Meter Identifier's checksum value
604
626
  # @return [Boolean] whether or not the checksum is valid
605
- def self.valid_checksum?(nmi,checksum_value)
627
+ def self.valid_checksum?(nmi, checksum_value)
606
628
  nmi = AEMO::NMI.new(nmi)
607
629
  nmi.valid_checksum?(checksum_value)
608
630
  end
@@ -626,14 +648,14 @@ module AEMO
626
648
 
627
649
  # A function to return the distribution loss factor value for a given date
628
650
  #
629
- # @param [DateTime,Time] datetime the date for the distribution loss factor value
630
- # @return [nil,float] the distribution loss factor value
651
+ # @param [DateTime, Time] datetime the date for the distribution loss factor value
652
+ # @return [nil, float] the distribution loss factor value
631
653
  def dlfc_value(datetime = DateTime.now)
632
654
  raise 'No DLF set, ensure that you have set the value either via the update_from_msats! function or manually' if @dlf.nil?
633
655
  raise 'DLF is invalid' unless DLF_CODES.keys.include?(@dlf)
634
- raise 'Invalid date' unless [DateTime,Time].include?(datetime.class)
635
- possible_values = DLF_CODES[@dlf].select{|x| DateTime.parse(x['FromDate']) <= datetime && datetime <= DateTime.parse(x['ToDate']) }
636
- if possible_values.length == 0
656
+ raise 'Invalid date' unless [DateTime, Time].include?(datetime.class)
657
+ possible_values = DLF_CODES[@dlf].select { |x| DateTime.parse(x['FromDate']) <= datetime && datetime <= DateTime.parse(x['ToDate']) }
658
+ if possible_values.empty?
637
659
  nil
638
660
  else
639
661
  possible_values.first['Value'].to_f
@@ -642,66 +664,50 @@ module AEMO
642
664
 
643
665
  # A function to return the distribution loss factor value for a given date
644
666
  #
645
- # @param [DateTime,Time] start the date for the distribution loss factor value
646
- # @param [DateTime,Time] finish the date for the distribution loss factor value
647
- # @return [Array(Hash)] array of hashes of start,finish and value
648
- def dlfc_values(start = DateTime.now, finish=DateTime.now)
667
+ # @param [DateTime, Time] start the date for the distribution loss factor value
668
+ # @param [DateTime, Time] finish the date for the distribution loss factor value
669
+ # @return [Array(Hash)] array of hashes of start, finish and value
670
+ def dlfc_values(start = DateTime.now, finish = DateTime.now)
649
671
  raise 'No DLF set, ensure that you have set the value either via the update_from_msats! function or manually' if @dlf.nil?
650
672
  raise 'DLF is invalid' unless DLF_CODES.keys.include?(@dlf)
651
- raise 'Invalid start' unless [DateTime,Time].include?(start.class)
652
- raise 'Invalid finish' unless [DateTime,Time].include?(finish.class)
673
+ raise 'Invalid start' unless [DateTime, Time].include?(start.class)
674
+ raise 'Invalid finish' unless [DateTime, Time].include?(finish.class)
653
675
  raise 'start cannot be after finish' if start > finish
654
- DLF_CODES[@dlf].reject{|x| start > DateTime.parse(x['ToDate']) || finish < DateTime.parse(x['FromDate']) }.map{|x| { 'start' => x['FromDate'], 'finish' => x['ToDate'], 'value' => x['Value'].to_f}}
676
+ DLF_CODES[@dlf].reject { |x| start > DateTime.parse(x['ToDate']) || finish < DateTime.parse(x['FromDate']) }
677
+ .map { |x| { 'start' => x['FromDate'], 'finish' => x['ToDate'], 'value' => x['Value'].to_f } }
655
678
  end
656
679
 
657
680
  # A function to return the transmission node identifier loss factor value for a given date
658
681
  #
659
- # @param [DateTime,Time] datetime the date for the distribution loss factor value
660
- # @return [nil,float] the transmission node identifier loss factor value
682
+ # @param [DateTime, Time] datetime the date for the distribution loss factor value
683
+ # @return [nil, float] the transmission node identifier loss factor value
661
684
  def tni_value(datetime = DateTime.now)
662
685
  raise 'No TNI set, ensure that you have set the value either via the update_from_msats! function or manually' if @tni.nil?
663
686
  raise 'TNI is invalid' unless TNI_CODES.keys.include?(@tni)
664
- raise 'Invalid date' unless [DateTime,Time].include?(datetime.class)
665
- possible_values = TNI_CODES[@tni].select{|x| DateTime.parse(x['FromDate']) <= datetime && datetime <= DateTime.parse(x['ToDate']) }
666
- if possible_values.length == 0
667
- nil
668
- else
669
- possible_values = possible_values.first['mlf_data']['loss_factors'].select{|x| DateTime.parse(x['start']) <= datetime && datetime <= DateTime.parse(x['finish']) }
670
- if possible_values.length == 0
671
- nil
672
- else
673
- possible_values.first['value'].to_f
674
- end
675
- end
687
+ raise 'Invalid date' unless [DateTime, Time].include?(datetime.class)
688
+ possible_values = TNI_CODES[@tni].select { |x| DateTime.parse(x['FromDate']) <= datetime && datetime <= DateTime.parse(x['ToDate']) }
689
+ return nil if possible_values.empty?
690
+ possible_values = possible_values.first['mlf_data']['loss_factors'].select { |x| DateTime.parse(x['start']) <= datetime && datetime <= DateTime.parse(x['finish']) }
691
+ return nil if possible_values.empty?
692
+ possible_values.first['value'].to_f
676
693
  end
677
694
 
678
695
  # A function to return the transmission node identifier loss factor value for a given date
679
696
  #
680
- # @param [DateTime,Time] start the date for the distribution loss factor value
681
- # @param [DateTime,Time] finish the date for the distribution loss factor value
682
- # @return [Array(Hash)] array of hashes of start,finish and value
683
- def tni_values(start=DateTime.now,finish=DateTime.now)
697
+ # @param [DateTime, Time] start the date for the distribution loss factor value
698
+ # @param [DateTime, Time] finish the date for the distribution loss factor value
699
+ # @return [Array(Hash)] array of hashes of start, finish and value
700
+ def tni_values(start = DateTime.now, finish = DateTime.now)
684
701
  raise 'No TNI set, ensure that you have set the value either via the update_from_msats! function or manually' if @tni.nil?
685
702
  raise 'TNI is invalid' unless TNI_CODES.keys.include?(@tni)
686
- raise 'Invalid start' unless [DateTime,Time].include?(start.class)
687
- raise 'Invalid finish' unless [DateTime,Time].include?(finish.class)
703
+ raise 'Invalid start' unless [DateTime, Time].include?(start.class)
704
+ raise 'Invalid finish' unless [DateTime, Time].include?(finish.class)
688
705
  raise 'start cannot be after finish' if start > finish
689
- possible_values = TNI_CODES[@tni].reject{|x| start > DateTime.parse(x['ToDate']) || finish < DateTime.parse(x['FromDate']) }
690
- tni_values = []
691
- if possible_values.length == 0
692
- nil
693
- else
694
- possible_values.each do |possible_value|
695
- tni_values += possible_value['mlf_data']['loss_factors'].reject{|x| start > DateTime.parse(x['finish']) || finish < DateTime.parse(x['start']) }
696
- end
697
- end
698
- tni_values
706
+ possible_values = TNI_CODES[@tni]
707
+ .reject { |x| start > DateTime.parse(x['ToDate']) || finish < DateTime.parse(x['FromDate']) }
708
+ .reject { |x| start > DateTime.parse(x['finish']) || finish < DateTime.parse(x['start']) }
709
+ return nil if possible_values.empty?
710
+ possible_values.map { |x| x['mlf_data']['loss_factors'] }
699
711
  end
700
-
701
- # ######### #
702
- protected
703
- # ######### #
704
-
705
712
  end
706
-
707
713
  end
data/lib/aemo/region.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  module AEMO
2
+ # AEMO::Region
3
+ #
4
+ # @author Joel Courtney
5
+ # @abstract
6
+ # @since 0.1.0
2
7
  class Region
3
-
4
8
  # Regions under juristiction
5
9
  REGIONS = {
6
10
  'ACT' => 'Australian Capital Territory',
@@ -11,12 +15,12 @@ module AEMO
11
15
  'VIC' => 'Victoria',
12
16
  'NT' => 'Northern Territory',
13
17
  'WA' => 'Western Australia'
14
- }
18
+ }.freeze
15
19
 
16
20
  attr_accessor :region
17
21
 
18
22
  def initialize(region)
19
- raise ArgumentError.new("Region '#{region}' is not valid.") unless is_valid_region?(region)
23
+ raise ArgumentError, "Region '#{region}' is not valid." unless valid_region?(region)
20
24
  @region = region
21
25
  @current_trading = []
22
26
  @current_dispatch = []
@@ -35,30 +39,27 @@ module AEMO
35
39
  end
36
40
 
37
41
  def current_dispatch
38
- if @current_dispatch.length == 0 || @current_dispatch.last.datetime != (Time.now - Time.now.to_i % 300)
42
+ if @current_dispatch.empty? || @current_dispatch.last.datetime != (Time.now - Time.now.to_i % 300)
39
43
  @current_dispatch = AEMO::Market.current_dispatch(@region)
40
44
  end
41
45
  @current_dispatch
42
46
  end
43
47
 
44
48
  def current_trading
45
- if @current_trading.length == 0 || @current_trading.reject{|i| i.period_type != 'TRADE'}.last.datetime != (Time.now - Time.now.to_i % 300)
49
+ if @current_trading.empty? || @current_trading.reject { |i| i.period_type != 'TRADE' }.last.datetime != (Time.now - Time.now.to_i % 300)
46
50
  @current_trading = AEMO::Market.current_trading(@region)
47
51
  end
48
52
  @current_trading
49
53
  end
50
54
 
51
55
  def self.all
52
- REGIONS.keys.map{|k| AEMO::Region.new(k)}
56
+ REGIONS.keys.map { |k| AEMO::Region.new(k) }
53
57
  end
54
58
 
55
- # ######### #
56
- protected
57
- # ######### #
59
+ protected
58
60
 
59
- def is_valid_region?(region)
61
+ def valid_region?(region)
60
62
  REGIONS.keys.include?(region)
61
63
  end
62
-
63
64
  end
64
65
  end
data/lib/aemo/version.rb CHANGED
@@ -2,14 +2,14 @@
2
2
  #
3
3
  # Copyright 2014 Joel Courtney
4
4
  #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # Licensed under the Apache License, Version 2.0 (the 'License');
6
6
  # you may not use this file except in compliance with the License.
7
7
  # You may obtain a copy of the License at
8
8
  #
9
9
  # http://www.apache.org/licenses/LICENSE-2.0
10
10
  #
11
11
  # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # distributed under the License is distributed on an 'AS IS' BASIS,
13
13
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
@@ -22,7 +22,7 @@
22
22
  # @author Joel Courtney <euphemize@gmail.com>
23
23
  module AEMO
24
24
  # aemo version
25
- VERSION = '0.1.27'
25
+ VERSION = '0.1.28'.freeze
26
26
 
27
27
  # aemo version split amongst different revisions
28
28
  MAJOR_VERSION, MINOR_VERSION, REVISION = VERSION.split('.').map(&:to_i)
@@ -0,0 +1,62 @@
1
+ require 'nokogiri'
2
+ require 'json'
3
+ require 'csv'
4
+ require 'active_support/all'
5
+
6
+ @path = Dir.pwd
7
+ @files = Dir.entries(@path).reject { |f| %w(. ..).include?(f) }
8
+
9
+ @mlf_data = {}
10
+ @dlf_data = {}
11
+
12
+ # Let's get the CSV Data first
13
+
14
+ # TNI to MLF
15
+ CSV.open(File.join(@path, 'tni-mlf-codes.csv'), headers: true, converters: :numeric).each do |row|
16
+ @mlf_data[row['TNI']] ||= { location: row['Location'], voltage: row['Voltage'], loss_factors: [] }
17
+ @mlf_data[row['TNI']][:loss_factors] << { start: DateTime.parse('2015-07-01T00:00:00+1000'), finish: DateTime.parse('2016-07-01T00:00:00+1000'), value: row['FY16'] }
18
+ @mlf_data[row['TNI']][:loss_factors] << { start: DateTime.parse('2014-07-01T00:00:00+1000'), finish: DateTime.parse('2015-07-01T00:00:00+1000'), value: row['FY15'] }
19
+ @mlf_data[row['TNI']][:loss_factors] << { start: DateTime.parse('2013-07-01T00:00:00+1000'), finish: DateTime.parse('2014-07-01T00:00:00+1000'), value: row['FY14'] }
20
+ end
21
+
22
+ # TNI to MLF
23
+ CSV.open(File.join(@path, 'aemo-dlf-dnsp.csv'), headers: true, converters: :numeric).each do |row|
24
+ @dlf_data[row['dlf_code']] ||= row['nsp_code']
25
+ end
26
+
27
+ # Now to create the DLF and TNI output JSON files for use
28
+ @files.select { |x| ['aemo-tni.xml', 'aemo-dlf.xml'].include?(x) }.each do |file|
29
+ output_file = file.gsub('.xml', '.json')
30
+ output_data = {}
31
+ open_file = File.open(File.join(@path, file))
32
+ xml = Nokogiri::XML(open_file) { |c| c.options = Nokogiri::XML::ParseOptions::NOBLANKS }
33
+ open_file.close
34
+
35
+ xml.xpath('//Row').each do |row|
36
+ row_children = row.children
37
+ code = row_children.find { |x| x.name == 'Code' }.children.first.text
38
+ output_data[code] ||= []
39
+ output_data_instance = {}
40
+ row_children.each do |row_child|
41
+ output_data_instance[row_child.name] = row_child.children.first.text
42
+ end
43
+ if file =~ /tni/
44
+ puts "output_data_instance: #{output_data_instance.inspect}"
45
+ output_data_instance[:mlf_data] = {}
46
+ unless @mlf_data[code].nil?
47
+ output_data_instance[:mlf_data] = @mlf_data[code].deep_dup
48
+ output_data_instance[:mlf_data][:loss_factors] = output_data_instance[:mlf_data][:loss_factors].reject do |x|
49
+ DateTime.parse(output_data_instance['ToDate']) < x[:start] || DateTime.parse(output_data_instance['FromDate']) >= x[:finish]
50
+ end
51
+ puts "output_data_instance[:mlf_data][:loss_factors]: #{output_data_instance[:mlf_data][:loss_factors].inspect}"
52
+ end
53
+ elsif file =~ /dlf/
54
+ output_data_instance[:nsp_code] = @dlf_data[code]
55
+ end
56
+ output_data[code] << output_data_instance
57
+ end
58
+
59
+ File.open(File.join(@path, output_file), 'w') do |write_file|
60
+ write_file.write(output_data.to_json)
61
+ end
62
+ end