aemo 0.1.27 → 0.1.28

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.
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