circuitdata 0.3.5 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +11 -0
- data/Rakefile +8 -0
- data/lib/circuitdata.rb +76 -388
- data/lib/circuitdata/bk_comparer.rb +106 -0
- data/lib/circuitdata/compatibility_checker.rb +119 -0
- data/lib/circuitdata/file_comparer.rb +243 -0
- data/lib/circuitdata/schema_files/v1/ottp_circuitdata_schema.json +5587 -0
- data/lib/circuitdata/schema_files/v1/ottp_circuitdata_schema_definitions.json +1139 -0
- data/lib/circuitdata/schema_files/v1/ottp_circuitdata_skeleton_schema.json +55 -0
- data/lib/circuitdata/schema_files/v1/ottp_schema_definitions.json +102 -0
- data/lib/circuitdata/version.rb +1 -1
- metadata +10 -3
- data/lib/tasks/circuitdata_tasks.rake +0 -4
@@ -0,0 +1,106 @@
|
|
1
|
+
def self.compare_files(filehash, validate_origins=false)
|
2
|
+
# Prepare the return
|
3
|
+
ra = {
|
4
|
+
error: false,
|
5
|
+
errormessage: "",
|
6
|
+
summary: {},
|
7
|
+
conflicts: {},
|
8
|
+
product: nil,
|
9
|
+
columns: [],
|
10
|
+
mastercolumn: nil,
|
11
|
+
rows: []
|
12
|
+
}
|
13
|
+
|
14
|
+
#parsedfiles
|
15
|
+
unless filehash.is_a? Hash
|
16
|
+
ra[:error] = true
|
17
|
+
ra[:errormessage] = "You have to feed this function with a hash of names and hashes"
|
18
|
+
return ra
|
19
|
+
end
|
20
|
+
|
21
|
+
# extend the hash that is received
|
22
|
+
nh = {}
|
23
|
+
filehash.each do |fhk, fhv|
|
24
|
+
nh[fhk] = {
|
25
|
+
orig: fhv,
|
26
|
+
parsed: nil,
|
27
|
+
content: nil,
|
28
|
+
has: {}
|
29
|
+
}
|
30
|
+
# READ THE CONTENT
|
31
|
+
ra[:error], ra[:errormessage], nh[fhk][:content] = self.read_json(fhv)
|
32
|
+
ra[:summary] = {} if ra[:error]
|
33
|
+
ra[:conflicts] = {} if ra[:error]
|
34
|
+
return ra if ra[:error]
|
35
|
+
# VALIDATE THE FILES
|
36
|
+
if validate_origins
|
37
|
+
ra[:error], ra[:errormessage], validationserrors = self.validate(nh[fhk][:content])
|
38
|
+
ra[:summary] = {} if ra[:error]
|
39
|
+
ra[:conflicts] = {} if ra[:error]
|
40
|
+
return ra if ra[:error]
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# SET THE PRODUCT NAME
|
45
|
+
nh[fhk][:has][:products], nh[fhk][:has][:stackup], nh[fhk][:has][:profile_default], nh[fhk][:has][:profile_restricted], nh[fhk][:has][:profile_enforced], nh[fhk][:has][:capabilities], nh[fhk][:has][:product] = self.content(nh[fhk][:content])
|
46
|
+
unless nh[fhk][:has][:product].nil?
|
47
|
+
#self.iterate(nh[fhk][:content])
|
48
|
+
|
49
|
+
#root_node = Tree::TreeNode.new("ROOT", "Root Content")
|
50
|
+
#root_node.print_tree
|
51
|
+
|
52
|
+
ra[:product] = nh[fhk][:has][:product] if ra[:product].nil?
|
53
|
+
if nh[fhk][:has][:product] != ra[:product]
|
54
|
+
ra[:error] = true
|
55
|
+
ra[:errormessage] = "Your files contains several different product names"
|
56
|
+
ra[:summary] = {}
|
57
|
+
ra[:conflicts] = {}
|
58
|
+
return ra
|
59
|
+
end
|
60
|
+
ra[:mastercolumn] = fhk if ra[:mastercolumn].nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
# THIS IS WHERE I NEED THINGS TO HAPPEN
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# RETURN IF THERE IS NO PRODUCT
|
68
|
+
if ra[:mastercolumn].nil?
|
69
|
+
ra[:error] = true
|
70
|
+
ra[:errormessage] = "none of the files contains a product"
|
71
|
+
ra[:summary] = {}
|
72
|
+
ra[:conflicts] = {}
|
73
|
+
return ra
|
74
|
+
end
|
75
|
+
|
76
|
+
{
|
77
|
+
current_level: 0,
|
78
|
+
current_key: nil,
|
79
|
+
|
80
|
+
}
|
81
|
+
# Populate the master column
|
82
|
+
#self.iterate(filehash[ra[:mastercolumn].to_sym])
|
83
|
+
#ra[:summary] = productjson[:open_trade_transfer_package][:products][ra[:product]][:printed_circuits_fabrication_data]
|
84
|
+
|
85
|
+
#test = {}
|
86
|
+
#self.save_pair(productjson[:open_trade_transfer_package][:products][ra[:product]][:printed_circuits_fabrication_data], test)
|
87
|
+
#puts test
|
88
|
+
# Populate the product rows
|
89
|
+
#productjson[:open_trade_transfer_package]["products"][ra[:product]]["printed_circuits_fabrication_data"].each do |key, value|
|
90
|
+
# if value.is_a? Hash
|
91
|
+
# value.each do |subkey, subvalue|
|
92
|
+
# ra[:rows][]
|
93
|
+
#end
|
94
|
+
|
95
|
+
# Do comparisons
|
96
|
+
#number = 1
|
97
|
+
#filehash.each do |key, value|
|
98
|
+
# unless key.to_s == productfile
|
99
|
+
# #puts self.compatibility_checker( productjson, value, false )
|
100
|
+
# number += 1
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
#puts JSON.pretty_generate(ra)
|
104
|
+
#puts JSON.pretty_generate(nh)
|
105
|
+
return ra
|
106
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
class Circuitdata::CompatibilityChecker
|
2
|
+
def initialize(product_file, check_file, validate_origins)
|
3
|
+
require 'json'
|
4
|
+
require 'json-schema'
|
5
|
+
|
6
|
+
@product_file = product_file
|
7
|
+
@check_file = check_file
|
8
|
+
@validate_origins = validate_origins
|
9
|
+
# Final hash
|
10
|
+
@fh = {error: false, message: nil, errors: {validation: {}, restricted: {}, enforced: {}, capabilities: {}}}
|
11
|
+
end
|
12
|
+
|
13
|
+
def start_check
|
14
|
+
# Initialize & validate
|
15
|
+
@fh[:error], @fh[:message], product_data = Circuitdata.read_json(@product_file)
|
16
|
+
return @fh if @fh[:error]
|
17
|
+
@fh[:error], @fh[:message], @fh[:errors][:validation] = Circuitdata.validate(product_data)
|
18
|
+
return @fh if @fh[:error]
|
19
|
+
if @check_file.present?
|
20
|
+
@fh[:error], @fh[:message], check_data = Circuitdata.read_json(@check_file)
|
21
|
+
return @fh if @fh[:error]
|
22
|
+
@fh[:error], @fh[:message], @fh[:errors][:validation] = Circuitdata.validate(check_data)
|
23
|
+
return @fh if @fh[:error]
|
24
|
+
f2_types = Circuitdata.get_data_summary(check_data)[1]
|
25
|
+
# read the schema
|
26
|
+
schema_path = File.join(File.dirname(__FILE__), 'schema_files/v1/ottp_circuitdata_skeleton_schema.json')
|
27
|
+
restricted_schema = enforced_schema = capability_schema = Circuitdata.read_json(schema_path)[2]
|
28
|
+
# Compare the content
|
29
|
+
perform_comparison(product_data, check_data, restricted_schema, 'restricted') if f2_types.include? 'profile_restricted'
|
30
|
+
perform_comparison(product_data, check_data, enforced_schema, 'enforced') if f2_types.include? 'profile_enforced'
|
31
|
+
perform_comparison(product_data, check_data, capability_schema, 'capabilities') if f2_types.include? 'capabilities'
|
32
|
+
end
|
33
|
+
|
34
|
+
@fh
|
35
|
+
end
|
36
|
+
|
37
|
+
def perform_comparison(product_data, check_data, schema, type)
|
38
|
+
case type
|
39
|
+
when 'restricted'
|
40
|
+
check_hash = check_data.dig(:open_trade_transfer_package, :profiles, :restricted, :printed_circuits_fabrication_data)
|
41
|
+
when 'enforced'
|
42
|
+
check_hash = check_data.dig(:open_trade_transfer_package, :profiles, :enforced, :printed_circuits_fabrication_data)
|
43
|
+
when 'capabilities'
|
44
|
+
check_hash = check_data.dig(:open_trade_transfer_package, :capabilities, :printed_circuits_fabrication_data)
|
45
|
+
else
|
46
|
+
check_hash = {}
|
47
|
+
end
|
48
|
+
# binding.pry
|
49
|
+
|
50
|
+
check_hash.each do |k, v|
|
51
|
+
v.each do |kl1, vl1| # level 1
|
52
|
+
common_hash = schema.dig(:properties, :open_trade_transfer_package, :properties, :products, :patternProperties, :'^(?!generic$).*', :properties, :printed_circuits_fabrication_data, :properties)
|
53
|
+
# binding.pry
|
54
|
+
common_hash[k.to_sym]||= {:type => 'object', :properties => {}}
|
55
|
+
common_hash[:stackup][:properties][:specified][:properties][k.to_sym] ||= {:type => 'object', :properties => {}}
|
56
|
+
|
57
|
+
case vl1.class.name
|
58
|
+
when 'String'
|
59
|
+
if vl1.match("^(\\d*|\\d*.\\d*)\\.\\.\\.(\\d*|\\d*.\\d*)$") #This is a value range
|
60
|
+
from, too = vl1.match("^(\\d*|\\d*.\\d*)\\.\\.\\.(\\d*|\\d*.\\d*)$").captures
|
61
|
+
case type
|
62
|
+
when 'restricted'
|
63
|
+
new_hash = {:not => {:allOf => [{:minimum => from.to_f},{:maximum => too.to_f}]}}
|
64
|
+
else
|
65
|
+
new_hash = eval("{:minimum => #{from}, :maximum => #{too}}")
|
66
|
+
end
|
67
|
+
else # This is a normal string - check for commas
|
68
|
+
enum = []
|
69
|
+
vl1.split(',').each {|enumvalue| enum << enumvalue.strip}
|
70
|
+
case type
|
71
|
+
when 'restricted'
|
72
|
+
new_hash = {:not => {:anyOf => [{ :enum => ''}]}}
|
73
|
+
new_hash[:not][:anyOf][0][:enum] = enum
|
74
|
+
else
|
75
|
+
new_hash = eval("{:enum => #{enum}}")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
when 'Numeric' # This is a normal string
|
79
|
+
case type
|
80
|
+
when 'restricted'
|
81
|
+
new_hash = {:not => {:allOf => [{:minimum => vl1.to_f},{:maximum => vl1.to_f}]}}
|
82
|
+
else
|
83
|
+
new_hash = eval("{:enum => [#{vl1.to_s}]}")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
common_hash[k.to_sym][:properties][kl1.to_sym] = new_hash
|
87
|
+
common_hash[:stackup][:properties][:specified][:properties][k.to_sym][:properties][kl1.to_sym] = new_hash
|
88
|
+
end if v.is_a? Hash
|
89
|
+
end
|
90
|
+
|
91
|
+
# perform validations
|
92
|
+
begin
|
93
|
+
validation_errors = JSON::Validator.fully_validate(schema.to_json, product_data, :errors_as_objects => true)
|
94
|
+
|
95
|
+
if validation_errors.any?
|
96
|
+
@fh[:error] = true
|
97
|
+
@fh[:message] = 'The product to check did not meet the requirements'
|
98
|
+
|
99
|
+
# format the errors well here
|
100
|
+
|
101
|
+
validation_errors.each do |error|
|
102
|
+
error_array = []
|
103
|
+
begin
|
104
|
+
error_array << error[:message].match("^(The\\sproperty\\s\\'[\\s\\S]*\\'\\s)([\\s\\S]*)(\\sin\\sschema[\\s\\S]*)$").captures[1]
|
105
|
+
rescue
|
106
|
+
error_array << error[:message]
|
107
|
+
end
|
108
|
+
@fh[:errors][type.to_sym][error[:fragment]] = error_array
|
109
|
+
end
|
110
|
+
end
|
111
|
+
rescue JSON::Schema::ReadFailed
|
112
|
+
@fh[:error] = true
|
113
|
+
@fh[:message] = "Could not read the submitted `#{type}` schema" # enforced_schema
|
114
|
+
rescue JSON::Schema::SchemaError
|
115
|
+
@fh[:error] = true
|
116
|
+
@fh[:message] = "Something was wrong with the submitted `#{type}` schema" # enforced_schema
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
class Circuitdata::FileComparer
|
2
|
+
def initialize(file_hash, validate_origins)
|
3
|
+
@file_hash = file_hash
|
4
|
+
@validate_origins = validate_origins
|
5
|
+
@rows = {}
|
6
|
+
@nh = {} # a new_hash to combine all the data
|
7
|
+
@columns = []
|
8
|
+
@default_column = nil
|
9
|
+
@master_column = nil
|
10
|
+
# Final hash
|
11
|
+
@fh = {error: false, message: nil, conflict: false, product_name: nil, columns: nil, master_column: nil, rows: nil}
|
12
|
+
end
|
13
|
+
|
14
|
+
def compare
|
15
|
+
# Initial check
|
16
|
+
unless @file_hash.is_a? Hash
|
17
|
+
@fh[:error] = true
|
18
|
+
@fh[:message] = 'You have to feed this function with a hash of names and hashes'
|
19
|
+
return @fh
|
20
|
+
end
|
21
|
+
|
22
|
+
# Process the hashes
|
23
|
+
products_array = []
|
24
|
+
@file_hash.each do |k, v|
|
25
|
+
# read content
|
26
|
+
@fh[:error], @fh[:message], file_content = Circuitdata.read_json(v)
|
27
|
+
return @fh if @fh[:error]
|
28
|
+
products, types = Circuitdata.get_data_summary(file_content)
|
29
|
+
products_array.push(*products) # add products to tracking array
|
30
|
+
# populate the new_hash to be used later
|
31
|
+
@nh[k] = {types: types, products: products, data: file_content}
|
32
|
+
end
|
33
|
+
|
34
|
+
# check if the files content meet the requirements
|
35
|
+
if valid_product?(products_array)
|
36
|
+
@fh[:product_name] = products_array.first.to_s
|
37
|
+
@columns = @nh.keys
|
38
|
+
# get all data with products in it
|
39
|
+
product_hashes = @nh.select{|k, v| v[:products].any?}
|
40
|
+
product_columns = product_hashes.keys
|
41
|
+
|
42
|
+
# Add conflicts into the new_hash
|
43
|
+
product_hashes.each do |column_k, column_v|
|
44
|
+
master_json = column_v.dig(:data)
|
45
|
+
@nh.each do |file_k, file_v|
|
46
|
+
products, data = file_v[:products], file_v[:data]
|
47
|
+
check_results = Circuitdata.compatibility_checker(master_json, data, false)
|
48
|
+
# format the conflicts correctly here
|
49
|
+
file_v[:conflicts] ||= {}
|
50
|
+
file_v[:conflicts][column_k] = get_validation_summary(check_results, file_k)
|
51
|
+
# initialize the rows format - for all the product items
|
52
|
+
product_hash = data.dig(:open_trade_transfer_package, :products, @fh[:product_name].to_sym, :printed_circuits_fabrication_data)
|
53
|
+
if products.any?
|
54
|
+
init_row_format(product_hash)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
# Initialize the rows format - for all default profile items
|
58
|
+
@default_column, file_v = @nh.select{|k, v| v[:types].include?("profile_defaults")}.first # this should only be a single file
|
59
|
+
data = file_v[:data]
|
60
|
+
product_hash = data.dig(:open_trade_transfer_package, :profiles, :defaults, :printed_circuits_fabrication_data)
|
61
|
+
init_row_format(product_hash)
|
62
|
+
end
|
63
|
+
|
64
|
+
# populate the @rows
|
65
|
+
product_columns.each do |column|
|
66
|
+
@master_column = column
|
67
|
+
process_row_hash('populate')
|
68
|
+
end
|
69
|
+
# populate the @rows summary
|
70
|
+
product_columns.each do |column|
|
71
|
+
@master_column = column
|
72
|
+
process_row_hash('get_summary')
|
73
|
+
end
|
74
|
+
process_row_hash('populate_defaults')
|
75
|
+
end
|
76
|
+
|
77
|
+
@fh[:columns] = @columns.unshift(:summary)
|
78
|
+
@fh[:rows] = @rows
|
79
|
+
@fh
|
80
|
+
end
|
81
|
+
|
82
|
+
def init_row_format(product_hash)
|
83
|
+
product_hash.each do |k, v|
|
84
|
+
if v.is_a?(Hash)
|
85
|
+
@rows[k] ||= {}
|
86
|
+
v.each do |kl1, vl1|
|
87
|
+
@rows[k][kl1] ||= get_l1_hash(@columns)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
@rows[k] ||= []
|
91
|
+
# if array functionality eg Holes
|
92
|
+
end if ['Hash', 'Array'].include?(v.class.name)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def process_row_hash(action)
|
97
|
+
@rows.each do |k, v| # product elements level
|
98
|
+
if v.is_a?(Hash)
|
99
|
+
v.each do |kl1, vl1| # specification level
|
100
|
+
value, conflict, conflicts_with, conflict_message = [], false, [], []
|
101
|
+
vl1.each do |kl2, vl2| # the specification column level - call the function from here
|
102
|
+
conflicts = @nh.dig(kl2, :conflicts, @master_column)
|
103
|
+
case action
|
104
|
+
when 'populate'
|
105
|
+
check = conflicts.any? && conflicts.dig(:rows, k, kl1).present?
|
106
|
+
vl2[:value] = @nh.dig(kl2, :data, :open_trade_transfer_package, :products, @fh[:product_name].to_sym, :printed_circuits_fabrication_data, k, kl1)
|
107
|
+
vl2[:conflict] = check unless vl2[:conflict] # update only when the status is false
|
108
|
+
vl2[:conflicts_with] = check ? vl2[:conflicts_with] << @master_column : []
|
109
|
+
vl2[:conflict_message] = check ? vl2[:conflict_message] + conflicts&.dig(:rows, k, kl1) : []
|
110
|
+
|
111
|
+
# update master_column conflicts with
|
112
|
+
if check
|
113
|
+
master_row = @rows.dig(k, kl1, @master_column)
|
114
|
+
master_row[:conflicts_with] = master_row[:conflicts_with] + conflicts.dig(:master_conflicts)
|
115
|
+
master_row[:conflict] = true
|
116
|
+
master_row[:conflict_message] = (master_row[:conflict_message] + vl2[:conflict_message]).uniq
|
117
|
+
end
|
118
|
+
when 'get_summary'
|
119
|
+
# get the summary items
|
120
|
+
if kl2 != :summary
|
121
|
+
items_v = vl2[:value]
|
122
|
+
master_value = vl1.dig(@master_column, :value)
|
123
|
+
# dont test if the @master_column value is also nil
|
124
|
+
if value.empty? || !value.include?(items_v)
|
125
|
+
value << items_v
|
126
|
+
conflicts_with << kl2
|
127
|
+
# jump the default column
|
128
|
+
if kl2 != @master_column # Add errors to the specific rows items
|
129
|
+
# get the item type
|
130
|
+
col_type = get_column_type(@nh.dig(kl2, :types))
|
131
|
+
vl2[:conflict] = true
|
132
|
+
vl2[:conflicts_with] = (vl2[:conflicts_with] << @master_column).uniq
|
133
|
+
vl2[:conflict_message] = (vl2[:conflict_message] << customize_conflict_message(col_type, kl2, @master_column)).uniq
|
134
|
+
# update the master row
|
135
|
+
master_row = @rows.dig(k, kl1, @master_column)
|
136
|
+
master_row[:conflicts_with] = master_row[:conflicts_with] << kl2
|
137
|
+
master_row[:conflict] = true
|
138
|
+
# get a customized error message here
|
139
|
+
master_row[:conflict_message] = (master_row[:conflict_message] << customize_conflict_message(col_type, @master_column, kl2)).uniq
|
140
|
+
end
|
141
|
+
end unless items_v.nil? || master_value.nil?
|
142
|
+
conflict = true if vl2[:conflict]
|
143
|
+
conflicts_with = conflicts_with + vl2[:conflicts_with]
|
144
|
+
conflict_message = conflict_message + vl2[:conflict_message]
|
145
|
+
end
|
146
|
+
when 'populate_defaults'
|
147
|
+
if kl2 == @default_column
|
148
|
+
vl2[:value] = @nh.dig(kl2, :data, :open_trade_transfer_package, :profiles, :defaults, :printed_circuits_fabrication_data, k, kl1)
|
149
|
+
vl2[:conflict] = false
|
150
|
+
vl2[:conflicts_with] = []
|
151
|
+
vl2[:conflict_message] = []
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
case action
|
156
|
+
when 'get_summary'
|
157
|
+
if value.count > 1
|
158
|
+
conflict = true
|
159
|
+
else
|
160
|
+
value = value.first
|
161
|
+
end
|
162
|
+
vl1[:summary] = {value: value, conflict: conflict, conflicts_with: conflicts_with.uniq, conflict_message: conflict_message.uniq}
|
163
|
+
when 'populate_defaults'
|
164
|
+
# if all the values are blank, use the default value
|
165
|
+
vl1[:summary][:value] ||= vl1.dig(@default_column, :value)
|
166
|
+
end
|
167
|
+
if action == 'get_summary'
|
168
|
+
end
|
169
|
+
@fh[:conflict] = true if conflict
|
170
|
+
end
|
171
|
+
else
|
172
|
+
# if array functionality eg Holes
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def customize_conflict_message(type, col, conflicting_col)
|
178
|
+
case type
|
179
|
+
when :product
|
180
|
+
"#{col.to_s} value conflicts with value from #{conflicting_col.to_s}"
|
181
|
+
when :restricted
|
182
|
+
"#{col.to_s} value is restricted in #{conflicting_col.to_s}"
|
183
|
+
when :enforced
|
184
|
+
"#{col.to_s} value conflicts with the enforced value from #{conflicting_col.to_s}"
|
185
|
+
when :capability
|
186
|
+
"#{col.to_s} value is outside the capabilities of #{conflicting_col.to_s}"
|
187
|
+
else
|
188
|
+
"There were some value conflicts"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def get_column_type(types)
|
193
|
+
types ||= []
|
194
|
+
if types.include? "product"
|
195
|
+
:product
|
196
|
+
elsif types.include? "profile_restricted"
|
197
|
+
:restricted
|
198
|
+
elsif types.include? "profile_enforced"
|
199
|
+
:enforced
|
200
|
+
elsif types.include? "capabilities"
|
201
|
+
:capability
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def get_validation_summary(validation, column)
|
206
|
+
summary = {}
|
207
|
+
if validation[:error]
|
208
|
+
summary[:master_conflicts] ||= []
|
209
|
+
summary[:master_conflicts] << column
|
210
|
+
summary[:conflicts], summary[:rows] = true, {}
|
211
|
+
validation[:errors].each do |type, errors| # validation, restricted, enforced, capabilities
|
212
|
+
errors.each do |k, v|
|
213
|
+
folders_stack = k.split('/')
|
214
|
+
folder, spec = folders_stack[5], folders_stack[6]
|
215
|
+
summary[:rows][folder.to_sym] ||= {}
|
216
|
+
spec_message = summary[:rows][folder.to_sym][spec.to_sym] || []
|
217
|
+
summary[:rows][folder.to_sym][spec.to_sym] = spec_message+v
|
218
|
+
end if errors.any?
|
219
|
+
end
|
220
|
+
end
|
221
|
+
summary
|
222
|
+
end
|
223
|
+
|
224
|
+
def get_l1_hash(columns)
|
225
|
+
l1_hash = {}
|
226
|
+
columns.each{|c| l1_hash[c]={} }
|
227
|
+
l1_hash
|
228
|
+
end
|
229
|
+
|
230
|
+
def valid_product?(products_array)
|
231
|
+
if products_array.uniq.count > 1
|
232
|
+
@fh[:error] = true
|
233
|
+
@fh[:message] = 'Your files contains several different product names'
|
234
|
+
return false # validation fails because of different product names
|
235
|
+
end
|
236
|
+
if products_array.empty?
|
237
|
+
@fh[:error] = true
|
238
|
+
@fh[:message] = 'None of the files contains a product'
|
239
|
+
return false # c=validation fails because there are no products
|
240
|
+
end
|
241
|
+
true
|
242
|
+
end
|
243
|
+
end
|