datashift 0.9.0 → 0.10.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.
- data/README.markdown +63 -64
- data/Rakefile +4 -7
- data/VERSION +1 -1
- data/datashift.gemspec +92 -62
- data/lib/applications/apache_poi_extensions.rb +62 -0
- data/lib/applications/excel.rb +78 -0
- data/lib/applications/excel_base.rb +65 -0
- data/lib/applications/jexcel_file.rb +222 -0
- data/lib/applications/jexcel_file_extensions.rb +244 -0
- data/lib/applications/jruby/{jexcel_file.rb → old_pre_proxy_jexcel_file.rb} +0 -0
- data/lib/applications/ruby_poi_translations.rb +64 -0
- data/lib/applications/spreadsheet_extensions.rb +31 -0
- data/lib/datashift/method_details_manager.rb +4 -0
- data/lib/exporters/csv_exporter.rb +3 -1
- data/lib/exporters/excel_exporter.rb +59 -74
- data/lib/generators/excel_generator.rb +70 -74
- data/lib/guards.rb +57 -0
- data/lib/loaders/excel_loader.rb +105 -105
- data/lib/loaders/loader_base.rb +43 -21
- data/lib/loaders/paperclip/attachment_loader.rb +104 -0
- data/lib/loaders/paperclip/datashift_paperclip.rb +78 -0
- data/lib/loaders/paperclip/{image_loader.rb → image_loading.rb} +2 -18
- data/lib/thor/{generate_excel.thor → generate.thor} +48 -0
- data/lib/thor/paperclip.thor +85 -0
- data/lib/thor/tools.thor +23 -2
- data/spec/Gemfile +1 -7
- data/spec/csv_exporter_spec.rb +4 -4
- data/spec/csv_loader_spec.rb +1 -1
- data/spec/excel_exporter_spec.rb +43 -45
- data/spec/excel_generator_spec.rb +132 -60
- data/spec/excel_loader_spec.rb +134 -140
- data/spec/excel_spec.rb +179 -0
- data/spec/fixtures/ProjectsMultiCategoriesHeaderLookup.xls +0 -0
- data/spec/fixtures/config/database.yml +2 -2
- data/spec/fixtures/db/datashift_test_models_db.sqlite +0 -0
- data/spec/{db → fixtures/db}/migrate/20110803201325_create_test_bed.rb +0 -0
- data/spec/fixtures/load_datashift.thor +3 -0
- data/spec/fixtures/models/category.rb +7 -0
- data/spec/fixtures/models/empty.rb +2 -0
- data/spec/fixtures/models/loader_release.rb +10 -0
- data/spec/fixtures/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/fixtures/models/milestone.rb +8 -0
- data/spec/fixtures/models/owner.rb +5 -0
- data/spec/fixtures/models/project.rb +26 -0
- data/spec/fixtures/models/test_model_defs.rb +67 -0
- data/spec/fixtures/models/version.rb +7 -0
- data/spec/loader_spec.rb +4 -3
- data/spec/method_dictionary_spec.rb +7 -6
- data/spec/method_mapper_spec.rb +3 -2
- data/spec/rails_sandbox/.gitignore +15 -0
- data/spec/rails_sandbox/Gemfile +40 -0
- data/spec/rails_sandbox/README.rdoc +261 -0
- data/spec/rails_sandbox/Rakefile +7 -0
- data/spec/rails_sandbox/app/assets/images/rails.png +0 -0
- data/spec/rails_sandbox/app/assets/javascripts/application.js +15 -0
- data/spec/rails_sandbox/app/assets/stylesheets/application.css +13 -0
- data/spec/rails_sandbox/app/controllers/application_controller.rb +3 -0
- data/spec/rails_sandbox/app/helpers/application_helper.rb +2 -0
- data/spec/rails_sandbox/app/mailers/.gitkeep +0 -0
- data/spec/rails_sandbox/app/models/.gitkeep +0 -0
- data/spec/rails_sandbox/app/models/category.rb +7 -0
- data/spec/rails_sandbox/app/models/empty.rb +2 -0
- data/spec/rails_sandbox/app/models/loader_release.rb +10 -0
- data/spec/rails_sandbox/app/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/rails_sandbox/app/models/milestone.rb +8 -0
- data/spec/rails_sandbox/app/models/owner.rb +5 -0
- data/spec/rails_sandbox/app/models/project.rb +26 -0
- data/spec/rails_sandbox/app/models/test_model_defs.rb +67 -0
- data/spec/rails_sandbox/app/models/version.rb +7 -0
- data/spec/rails_sandbox/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_sandbox/config.ru +4 -0
- data/spec/rails_sandbox/config/application.rb +62 -0
- data/spec/rails_sandbox/config/boot.rb +6 -0
- data/spec/rails_sandbox/config/database.yml +20 -0
- data/spec/rails_sandbox/config/environment.rb +5 -0
- data/spec/rails_sandbox/config/environments/development.rb +37 -0
- data/spec/rails_sandbox/config/environments/production.rb +67 -0
- data/spec/rails_sandbox/config/environments/test.rb +37 -0
- data/spec/rails_sandbox/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_sandbox/config/initializers/inflections.rb +15 -0
- data/spec/rails_sandbox/config/initializers/mime_types.rb +5 -0
- data/spec/rails_sandbox/config/initializers/secret_token.rb +7 -0
- data/spec/rails_sandbox/config/initializers/session_store.rb +8 -0
- data/spec/rails_sandbox/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_sandbox/config/locales/en.yml +5 -0
- data/spec/rails_sandbox/config/routes.rb +58 -0
- data/spec/rails_sandbox/db/migrate/20110803201325_create_test_bed.rb +96 -0
- data/spec/rails_sandbox/db/schema.rb +81 -0
- data/spec/rails_sandbox/db/seeds.rb +7 -0
- data/spec/rails_sandbox/lib/assets/.gitkeep +0 -0
- data/spec/rails_sandbox/lib/tasks/.gitkeep +0 -0
- data/spec/rails_sandbox/log/.gitkeep +0 -0
- data/spec/rails_sandbox/public/404.html +26 -0
- data/spec/rails_sandbox/public/422.html +26 -0
- data/spec/rails_sandbox/public/500.html +25 -0
- data/spec/rails_sandbox/public/favicon.ico +0 -0
- data/spec/rails_sandbox/public/index.html +241 -0
- data/spec/rails_sandbox/public/robots.txt +5 -0
- data/spec/rails_sandbox/script/rails +6 -0
- data/spec/rails_sandbox/test/fixtures/.gitkeep +0 -0
- data/spec/rails_sandbox/test/functional/.gitkeep +0 -0
- data/spec/rails_sandbox/test/integration/.gitkeep +0 -0
- data/spec/rails_sandbox/test/performance/browsing_test.rb +12 -0
- data/spec/rails_sandbox/test/test_helper.rb +13 -0
- data/spec/rails_sandbox/test/unit/.gitkeep +0 -0
- data/spec/rails_sandbox/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/rails_sandbox/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/rails_sandbox/vendor/plugins/.gitkeep +0 -0
- data/spec/spec_helper.rb +144 -121
- data/spec/thor_spec.rb +34 -14
- metadata +207 -194
- data/lib/helpers/spree_helper.rb +0 -213
- data/lib/loaders/spreadsheet_loader.rb +0 -144
- data/lib/loaders/spree/image_loader.rb +0 -90
- data/lib/loaders/spree/product_loader.rb +0 -354
- data/lib/thor/spree/bootstrap_cleanup.thor +0 -61
- data/lib/thor/spree/products_images.thor +0 -252
- data/lib/thor/spree/reports.thor +0 -56
- data/public/spree/products/large/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/large/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/large/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/mini/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/mini/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/mini/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/original/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/original/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/original/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/product/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/product/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/product/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/small/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/small/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/small/DEMO_003_ror_mug.jpeg +0 -0
- data/spec/fixtures/datashift_Spree_db.sqlite +0 -0
- data/spec/fixtures/datashift_test_models_db.sqlite +0 -0
- data/spec/fixtures/negative/SpreeProdMiss1Mandatory.csv +0 -4
- data/spec/fixtures/negative/SpreeProdMiss1Mandatory.xls +0 -0
- data/spec/fixtures/negative/SpreeProdMissManyMandatory.csv +0 -4
- data/spec/fixtures/negative/SpreeProdMissManyMandatory.xls +0 -0
- data/spec/fixtures/spree/SpreeImages.xls +0 -0
- data/spec/fixtures/spree/SpreeMultiVariant.csv +0 -4
- data/spec/fixtures/spree/SpreeProducts.csv +0 -4
- data/spec/fixtures/spree/SpreeProducts.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsDefaults.yml +0 -15
- data/spec/fixtures/spree/SpreeProductsMandatoryOnly.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsMultiColumn.csv +0 -4
- data/spec/fixtures/spree/SpreeProductsMultiColumn.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsSimple.csv +0 -4
- data/spec/fixtures/spree/SpreeProductsSimple.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsWithImages.csv +0 -4
- data/spec/fixtures/spree/SpreeProductsWithImages.xls +0 -0
- data/spec/fixtures/spree/SpreeZoneExample.csv +0 -5
- data/spec/fixtures/spree/SpreeZoneExample.xls +0 -0
- data/spec/spree_exporter_spec.rb +0 -72
- data/spec/spree_generator_spec.rb +0 -96
- data/spec/spree_images_loader_spec.rb +0 -107
- data/spec/spree_loader_spec.rb +0 -375
- data/spec/spree_method_mapping_spec.rb +0 -226
- data/spec/spree_variants_loader_spec.rb +0 -189
- data/tasks/export/excel_generator.rake +0 -102
- data/tasks/import/excel.rake +0 -75
- data/test/helper.rb +0 -18
- data/test/test_interact.rb +0 -7
data/lib/helpers/spree_helper.rb
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
# Copyright:: (c) Autotelik Media Ltd 2011
|
|
2
|
-
# Author :: Tom Statter
|
|
3
|
-
# Date :: Aug 2011
|
|
4
|
-
# License:: MIT
|
|
5
|
-
#
|
|
6
|
-
# Details:: Spree Helper for Product Loading.
|
|
7
|
-
#
|
|
8
|
-
# Utils to try to manage different Spree versions seamlessly.
|
|
9
|
-
#
|
|
10
|
-
# Spree Helper for RSpec testing, enables mixing in Support for
|
|
11
|
-
# testing or loading Rails Spree e-commerce.
|
|
12
|
-
#
|
|
13
|
-
# The Spree version you want to test should be picked up from spec/Gemfile
|
|
14
|
-
#
|
|
15
|
-
# Since datashift gem is not a Rails app or a Spree App, provides utilities to internally
|
|
16
|
-
# create a Spree Database, and to load Spree components, enabling standalone testing.
|
|
17
|
-
#
|
|
18
|
-
# => Has been tested with 0.11.2, 0.7, 1.0.0
|
|
19
|
-
#
|
|
20
|
-
# => TODO - See if we can improve DB creation/migration ....
|
|
21
|
-
# N.B Some or all of Spree Tests may fail very first time run,
|
|
22
|
-
# as the database is auto generated
|
|
23
|
-
# =>
|
|
24
|
-
|
|
25
|
-
module DataShift
|
|
26
|
-
|
|
27
|
-
module SpreeHelper
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def self.root
|
|
31
|
-
Gem.loaded_specs['spree_core'] ? Gem.loaded_specs['spree_core'].full_gem_path : ""
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Helpers so we can cope with both pre 1.0 and post 1.0 versions of Spree in same datashift version
|
|
35
|
-
|
|
36
|
-
def self.get_spree_class(x)
|
|
37
|
-
if(is_namespace_version())
|
|
38
|
-
ModelMapper::class_from_string("Spree::#{x}")
|
|
39
|
-
else
|
|
40
|
-
ModelMapper::class_from_string(x.to_s)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def self.get_product_class
|
|
45
|
-
if(is_namespace_version())
|
|
46
|
-
Spree::Product
|
|
47
|
-
else
|
|
48
|
-
Product
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def self.version
|
|
53
|
-
Gem.loaded_specs['spree'] ? Gem.loaded_specs['spree'].version.version : "0.0.0"
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def self.is_namespace_version
|
|
57
|
-
SpreeHelper::version.to_f >= 1
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def self.lib_root
|
|
61
|
-
File.join(root, 'lib')
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def self.app_root
|
|
65
|
-
File.join(root, 'app')
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def self.load()
|
|
69
|
-
require 'spree'
|
|
70
|
-
require 'spree_core'
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# Datashift is usually included and tasks pulled in by a parent/host application.
|
|
75
|
-
# So here we are hacking our way around the fact that datashift is not a Rails/Spree app/engine
|
|
76
|
-
# so that we can ** run our specs ** directly in datashift library
|
|
77
|
-
# i.e without ever having to install datashift in a host application
|
|
78
|
-
#
|
|
79
|
-
# NOTES:
|
|
80
|
-
# => Will chdir into the sandbox to load environment as need to mimic being at root of a rails project
|
|
81
|
-
# chdir back after environment loaded
|
|
82
|
-
|
|
83
|
-
def self.boot( database_env)
|
|
84
|
-
|
|
85
|
-
if( ! is_namespace_version )
|
|
86
|
-
db_connect( database_env )
|
|
87
|
-
@dslog.info "Booting Spree using pre 1.0.0 version"
|
|
88
|
-
boot_pre_1
|
|
89
|
-
@dslog.info "Booted Spree using pre 1.0.0 version"
|
|
90
|
-
else
|
|
91
|
-
|
|
92
|
-
db_connect( database_env )
|
|
93
|
-
|
|
94
|
-
@dslog.info "Booting Spree using version #{SpreeHelper::version}"
|
|
95
|
-
|
|
96
|
-
require 'rails/all'
|
|
97
|
-
|
|
98
|
-
store_path = Dir.pwd
|
|
99
|
-
|
|
100
|
-
spree_sanbox_app = File.expand_path('../../../spec/sandbox', __FILE__)
|
|
101
|
-
|
|
102
|
-
unless(File.exists?(spree_sanbox_app))
|
|
103
|
-
puts "Creating new Rails sandbox for Spree : #{spree_sanbox_app}"
|
|
104
|
-
Dir.chdir( File.expand_path( "#{spree_sanbox_app}/..") )
|
|
105
|
-
system('rails new sandbox')
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
rails_root = spree_sanbox_app
|
|
109
|
-
|
|
110
|
-
$:.unshift rails_root
|
|
111
|
-
|
|
112
|
-
begin
|
|
113
|
-
require 'config/environment.rb'
|
|
114
|
-
rescue => e
|
|
115
|
-
#somethign in deface seems to blow up suddenly on 1.1
|
|
116
|
-
# puts e.backtrace
|
|
117
|
-
puts "Warning - Potential issue initializing Spree sanbox #{e.inspect}"
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
Dir.chdir( store_path )
|
|
121
|
-
|
|
122
|
-
@dslog.info "Booted Spree using version #{SpreeHelper::version}"
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def self.boot_pre_1
|
|
127
|
-
|
|
128
|
-
require 'rake'
|
|
129
|
-
require 'rubygems/package_task'
|
|
130
|
-
require 'thor/group'
|
|
131
|
-
|
|
132
|
-
require 'spree_core/preferences/model_hooks'
|
|
133
|
-
#
|
|
134
|
-
# Initialize preference system
|
|
135
|
-
ActiveRecord::Base.class_eval do
|
|
136
|
-
include Spree::Preferences
|
|
137
|
-
include Spree::Preferences::ModelHooks
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
gem 'paperclip'
|
|
141
|
-
gem 'nested_set'
|
|
142
|
-
|
|
143
|
-
require 'nested_set'
|
|
144
|
-
require 'paperclip'
|
|
145
|
-
require 'acts_as_list'
|
|
146
|
-
|
|
147
|
-
CollectiveIdea::Acts::NestedSet::Railtie.extend_active_record
|
|
148
|
-
ActiveRecord::Base.send(:include, Paperclip::Glue)
|
|
149
|
-
|
|
150
|
-
gem 'activemerchant'
|
|
151
|
-
require 'active_merchant'
|
|
152
|
-
require 'active_merchant/billing/gateway'
|
|
153
|
-
|
|
154
|
-
ActiveRecord::Base.send(:include, ActiveMerchant::Billing)
|
|
155
|
-
|
|
156
|
-
require 'scopes'
|
|
157
|
-
|
|
158
|
-
# Not sure how Rails manages this seems lots of circular dependencies so
|
|
159
|
-
# keep trying stuff till no more errors
|
|
160
|
-
|
|
161
|
-
Dir[lib_root + '/*.rb'].each do |r|
|
|
162
|
-
begin
|
|
163
|
-
require r if File.file?(r)
|
|
164
|
-
rescue => e
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
Dir[lib_root + '/**/*.rb'].each do |r|
|
|
169
|
-
begin
|
|
170
|
-
require r if File.file?(r) && ! r.include?('testing') && ! r.include?('generators')
|
|
171
|
-
rescue => e
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
load_models( true )
|
|
176
|
-
|
|
177
|
-
Dir[lib_root + '/*.rb'].each do |r|
|
|
178
|
-
begin
|
|
179
|
-
require r if File.file?(r)
|
|
180
|
-
rescue => e
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
Dir[lib_root + '/**/*.rb'].each do |r|
|
|
185
|
-
begin
|
|
186
|
-
require r if File.file?(r) && ! r.include?('testing') && ! r.include?('generators')
|
|
187
|
-
rescue => e
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
# require 'lib/product_filters'
|
|
192
|
-
|
|
193
|
-
load_models( true )
|
|
194
|
-
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
def self.load_models( report_errors = nil )
|
|
198
|
-
puts 'Loading Spree models from', root
|
|
199
|
-
Dir[root + '/app/models/**/*.rb'].each {|r|
|
|
200
|
-
begin
|
|
201
|
-
require r if File.file?(r)
|
|
202
|
-
rescue => e
|
|
203
|
-
puts("WARNING failed to load #{r}", e.inspect) if(report_errors == true)
|
|
204
|
-
end
|
|
205
|
-
}
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def self.migrate_up
|
|
209
|
-
ActiveRecord::Migrator.up( File.join(root, 'db/migrate') )
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
end
|
|
213
|
-
end
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
# Copyright:: (c) Autotelik Media Ltd 2011
|
|
2
|
-
# Author :: Tom Statter
|
|
3
|
-
# Date :: Jan 2012
|
|
4
|
-
# License:: MIT
|
|
5
|
-
#
|
|
6
|
-
# Details:: Specific loader to support Excel files via http://rubygems.org/gems/spreadsheet
|
|
7
|
-
#
|
|
8
|
-
# Offers an alternative for non JRuby usage(see excel_loader)
|
|
9
|
-
#
|
|
10
|
-
# Maps column headings to operations on the model.
|
|
11
|
-
# Iterates over all the rows using mapped operations to assign row data to a database object,
|
|
12
|
-
# i.e pulls data from each column and sends to object.
|
|
13
|
-
#
|
|
14
|
-
require 'datashift/exceptions'
|
|
15
|
-
|
|
16
|
-
module DataShift
|
|
17
|
-
|
|
18
|
-
unless(Guards::jruby?)
|
|
19
|
-
|
|
20
|
-
require 'loaders/loader_base'
|
|
21
|
-
|
|
22
|
-
module SpreadsheetLoading
|
|
23
|
-
|
|
24
|
-
gem 'spreadsheet'
|
|
25
|
-
require 'spreadsheet'
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# Spreadsheet.client_encoding = 'UTF-8'F
|
|
29
|
-
|
|
30
|
-
# Options:
|
|
31
|
-
# [:header_row] : Default is 0. Use alternative row as header definition.
|
|
32
|
-
# [:mandatory] : Array of mandatory column names
|
|
33
|
-
# [:strict] : Raise exception when no mapping found for a column heading (non mandatory)
|
|
34
|
-
# [:sheet_number]
|
|
35
|
-
|
|
36
|
-
def perform_spreadsheet_load( file_name, options = {} )
|
|
37
|
-
|
|
38
|
-
@mandatory = options[:mandatory] || []
|
|
39
|
-
|
|
40
|
-
@excel = Spreadsheet.open file_name
|
|
41
|
-
|
|
42
|
-
puts "\nLoading from Excel file: #{file_name}"
|
|
43
|
-
|
|
44
|
-
sheet_number = options[:sheet_number] || 0
|
|
45
|
-
|
|
46
|
-
@sheet = @excel.sheet( sheet_number )
|
|
47
|
-
|
|
48
|
-
header_row_index = options[:header_row] || 0
|
|
49
|
-
@header_row = @sheet.getRow(header_row_index)
|
|
50
|
-
|
|
51
|
-
raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" unless(@header_row)
|
|
52
|
-
|
|
53
|
-
@headers = []
|
|
54
|
-
|
|
55
|
-
(0..JExcelFile::MAX_COLUMNS).each do |i|
|
|
56
|
-
cell = @header_row.getCell(i)
|
|
57
|
-
break unless cell
|
|
58
|
-
header = "#{@excel.cell_value(cell).to_s}".strip
|
|
59
|
-
break if header.empty?
|
|
60
|
-
@headers << header
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" if(@headers.empty?)
|
|
64
|
-
|
|
65
|
-
# Create a method_mapper which maps list of headers into suitable calls on the Active Record class
|
|
66
|
-
map_headers_to_operators( @headers, options)
|
|
67
|
-
|
|
68
|
-
load_object_class.transaction do
|
|
69
|
-
@loaded_objects = []
|
|
70
|
-
|
|
71
|
-
(1..@excel.num_rows).collect do |row|
|
|
72
|
-
|
|
73
|
-
# Excel num_rows seems to return all 'visible' rows, which appears to be greater than the actual data rows
|
|
74
|
-
# (TODO - write spec to process .xls with a huge number of rows)
|
|
75
|
-
#
|
|
76
|
-
# This is rubbish but currently manually detect when actual data ends, this isn't very smart but
|
|
77
|
-
# got no better idea than ending once we hit the first completely empty row
|
|
78
|
-
break if @excel.sheet.getRow(row).nil?
|
|
79
|
-
|
|
80
|
-
contains_data = false
|
|
81
|
-
|
|
82
|
-
# TODO - Smart sorting of column processing order ....
|
|
83
|
-
# Does not currently ensure mandatory columns (for valid?) processed first but model needs saving
|
|
84
|
-
# before associations can be processed so user should ensure mandatory columns are prior to associations
|
|
85
|
-
|
|
86
|
-
# as part of this we also attempt to save early, for example before assigning to
|
|
87
|
-
# has_and_belongs_to associations which require the load_object has an id for the join table
|
|
88
|
-
|
|
89
|
-
# Iterate over the columns method_mapper found in Excel,
|
|
90
|
-
# pulling data out of associated column
|
|
91
|
-
@method_mapper.method_details.each_with_index do |method_detail, col|
|
|
92
|
-
|
|
93
|
-
value = value_at(row, col)
|
|
94
|
-
|
|
95
|
-
contains_data = true unless(value.nil? || value.to_s.empty?)
|
|
96
|
-
|
|
97
|
-
#puts "DEBUG: Excel process METHOD :#{method_detail.inspect}", value.inspect
|
|
98
|
-
prepare_data(method_detail, value)
|
|
99
|
-
|
|
100
|
-
process()
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
break unless(contains_data == true)
|
|
104
|
-
|
|
105
|
-
# TODO - requirements to handle not valid ?
|
|
106
|
-
# all or nothing or carry on and dump out the exception list at end
|
|
107
|
-
#puts "DEBUG: FINAL SAVE #{load_object.inspect}"
|
|
108
|
-
save
|
|
109
|
-
#puts "DEBUG: SAVED #{load_object.inspect}"
|
|
110
|
-
|
|
111
|
-
# don't forget to reset the object or we'll update rather than create
|
|
112
|
-
new_load_object
|
|
113
|
-
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
puts "Spreadsheet loading stage complete - #{loaded_objects.size} rows added."
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def value_at(row, column)
|
|
120
|
-
@excel.get_cell_value( @excel.sheet.getRow(row), column)
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
class SpreadsheetLoader < LoaderBase
|
|
126
|
-
|
|
127
|
-
include SpreadsheetLoading
|
|
128
|
-
|
|
129
|
-
def initialize(klass, object = nil, options = {})
|
|
130
|
-
super( klass, object, options )
|
|
131
|
-
raise "Cannot load - failed to create a #{klass}" unless @load_object
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def perform_load( file_name, options = {} )
|
|
135
|
-
perform_spreadsheet_load( file_name, options )
|
|
136
|
-
|
|
137
|
-
puts "Spreadsheet loading stage complete - #{loaded_objects.size} rows added."
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
end
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# Copyright:: (c) Autotelik Media Ltd 2011
|
|
2
|
-
# Author :: Tom Statter
|
|
3
|
-
# Date :: Jan 2011
|
|
4
|
-
# License:: MIT. Free, Open Source.
|
|
5
|
-
#
|
|
6
|
-
require 'loader_base'
|
|
7
|
-
require 'paperclip/image_loader'
|
|
8
|
-
|
|
9
|
-
module DataShift
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
module DataShift::SpreeImageLoading
|
|
13
|
-
|
|
14
|
-
include DataShift::Logging
|
|
15
|
-
include DataShift::ImageLoading
|
|
16
|
-
|
|
17
|
-
# Note the Spree Image model sets default storage path to
|
|
18
|
-
# => :path => ":rails_root/public/assets/products/:id/:style/:basename.:extension"
|
|
19
|
-
|
|
20
|
-
def create_image(klass, attachment_path, viewable_record = nil, options = {})
|
|
21
|
-
|
|
22
|
-
viewable = (SpreeHelper::version.to_f > 1 && viewable_record.is_a?(Spree::Product) ) ? viewable_record.master : viewable_record
|
|
23
|
-
|
|
24
|
-
super(klass, attachment_path, viewable, options)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
module SpreeHelper
|
|
29
|
-
|
|
30
|
-
# TODO - extract this out of SpreeHelper to create a general paperclip loader
|
|
31
|
-
class ImageLoader < LoaderBase
|
|
32
|
-
|
|
33
|
-
include DataShift::SpreeImageLoading
|
|
34
|
-
include DataShift::CsvLoading
|
|
35
|
-
include DataShift::ExcelLoading
|
|
36
|
-
|
|
37
|
-
def initialize(image = nil, options = {})
|
|
38
|
-
|
|
39
|
-
opts = options.merge(:load => false) # Don't need operators and no table Spree::Image
|
|
40
|
-
|
|
41
|
-
super( SpreeHelper::get_spree_class('Image'), image, opts )
|
|
42
|
-
|
|
43
|
-
if(SpreeHelper::version.to_f > 1.0 )
|
|
44
|
-
@attachment_klazz = DataShift::SpreeHelper::get_spree_class('Variant' )
|
|
45
|
-
else
|
|
46
|
-
@attachment_klazz = DataShift::SpreeHelper::get_spree_class('Product' )
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
puts "Attachment Class is #{@attachment_klazz}" if(@verbose)
|
|
50
|
-
|
|
51
|
-
raise "Failed to create Image for loading" unless @load_object
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def process()
|
|
55
|
-
|
|
56
|
-
if(current_value && @current_method_detail.operator?('attachment') )
|
|
57
|
-
|
|
58
|
-
# assign the image file data as an attachment
|
|
59
|
-
@load_object.attachment = get_file(current_value)
|
|
60
|
-
|
|
61
|
-
puts "Image attachment created : #{@load_object.inspect}"
|
|
62
|
-
|
|
63
|
-
elsif(current_value && @current_method_detail.operator )
|
|
64
|
-
|
|
65
|
-
# find the db record to assign our Image to
|
|
66
|
-
add_record( get_record_by(@attachment_klazz, @current_method_detail.operator, current_value) )
|
|
67
|
-
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def add_record(record)
|
|
73
|
-
if(record)
|
|
74
|
-
if(SpreeHelper::version.to_f > 1 )
|
|
75
|
-
@load_object.viewable = record
|
|
76
|
-
else
|
|
77
|
-
@load_object.viewable = record.product # SKU stored on Variant but we want it's master Product
|
|
78
|
-
end
|
|
79
|
-
@load_object.save
|
|
80
|
-
puts "Image viewable set : #{record.inspect}"
|
|
81
|
-
|
|
82
|
-
else
|
|
83
|
-
puts "WARNING - Cannot set viewable - No matching record supplied"
|
|
84
|
-
logger.error"Failed to find a matching record"
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
end
|
|
90
|
-
end
|
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
# Copyright:: (c) Autotelik Media Ltd 2010
|
|
2
|
-
# Author :: Tom Statter
|
|
3
|
-
# Date :: Aug 2010
|
|
4
|
-
# License:: MIT ?
|
|
5
|
-
#
|
|
6
|
-
# Details:: Specific over-rides/additions to support Spree Products
|
|
7
|
-
#
|
|
8
|
-
require 'loader_base'
|
|
9
|
-
require 'csv_loader'
|
|
10
|
-
require 'excel_loader'
|
|
11
|
-
require 'image_loader'
|
|
12
|
-
|
|
13
|
-
module DataShift
|
|
14
|
-
|
|
15
|
-
module SpreeHelper
|
|
16
|
-
|
|
17
|
-
class ProductLoader < LoaderBase
|
|
18
|
-
|
|
19
|
-
include DataShift::CsvLoading
|
|
20
|
-
include DataShift::ExcelLoading
|
|
21
|
-
include DataShift::ImageLoading
|
|
22
|
-
|
|
23
|
-
# depending on version get_product_class should return us right class, namespaced or not
|
|
24
|
-
|
|
25
|
-
def initialize(product = nil)
|
|
26
|
-
super( SpreeHelper::get_product_class(), product, :instance_methods => true )
|
|
27
|
-
|
|
28
|
-
@@image_klass ||= SpreeHelper::get_spree_class('Image')
|
|
29
|
-
@@option_type_klass ||= SpreeHelper::get_spree_class('OptionType')
|
|
30
|
-
@@option_value_klass ||= SpreeHelper::get_spree_class('OptionValue')
|
|
31
|
-
@@property_klass ||= SpreeHelper::get_spree_class('Property')
|
|
32
|
-
@@product_property_klass ||= SpreeHelper::get_spree_class('ProductProperty')
|
|
33
|
-
@@taxonomy_klass ||= SpreeHelper::get_spree_class('Taxonomy')
|
|
34
|
-
@@taxon_klass ||= SpreeHelper::get_spree_class('Taxon')
|
|
35
|
-
@@variant_klass ||= SpreeHelper::get_spree_class('Variant')
|
|
36
|
-
|
|
37
|
-
raise "Failed to create Product for loading" unless @load_object
|
|
38
|
-
|
|
39
|
-
logger.debug "PRODUCT #{@load_object.inspect} MASTER: #{@load_object.master.inspect}"
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def perform_load( file_name, options = {} )
|
|
43
|
-
# In >= 1.1.0 Image moved to master Variant from Product so no association called Images on Product anymore
|
|
44
|
-
options[:force_inclusion] = options[:force_inclusion] ? ['images'] : [*options[:force_inclusion]] << 'images'
|
|
45
|
-
|
|
46
|
-
super(file_name, options)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Over ride base class process with some Spree::Product specifics
|
|
50
|
-
#
|
|
51
|
-
# What process a value string from a column, assigning value(s) to correct association on Product.
|
|
52
|
-
# Method map represents a column from a file and it's correlated Product association.
|
|
53
|
-
# Value string which may contain multiple values for a collection (has_many) association.
|
|
54
|
-
#
|
|
55
|
-
def process()
|
|
56
|
-
|
|
57
|
-
# Special cases for Products, generally where a simple one stage lookup won't suffice
|
|
58
|
-
# otherwise simply use default processing from base class
|
|
59
|
-
if(current_value && (@current_method_detail.operator?('variants') || @current_method_detail.operator?('option_types')) )
|
|
60
|
-
|
|
61
|
-
add_options
|
|
62
|
-
|
|
63
|
-
elsif(@current_method_detail.operator?('taxons') && current_value)
|
|
64
|
-
|
|
65
|
-
add_taxons
|
|
66
|
-
|
|
67
|
-
elsif(@current_method_detail.operator?('product_properties') && current_value)
|
|
68
|
-
|
|
69
|
-
add_properties
|
|
70
|
-
|
|
71
|
-
elsif(@current_method_detail.operator?('images') && current_value)
|
|
72
|
-
|
|
73
|
-
add_images
|
|
74
|
-
|
|
75
|
-
elsif(current_value && (@current_method_detail.operator?('count_on_hand') || @current_method_detail.operator?('on_hand')) )
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# Unless we can save here, in danger of count_on_hand getting wiped out.
|
|
79
|
-
# If we set (on_hand or count_on_hand) on an unsaved object, during next subsequent save
|
|
80
|
-
# looks like some validation code or something calls Variant.on_hand= with 0
|
|
81
|
-
# If we save first, then our values seem to stick
|
|
82
|
-
|
|
83
|
-
# TODO smart column ordering to ensure always valid - if we always make it very last column might not get wiped ?
|
|
84
|
-
#
|
|
85
|
-
save_if_new
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
# Spree has some stock management stuff going on, so dont usually assign to column vut use
|
|
89
|
-
# on_hand and on_hand=
|
|
90
|
-
if(@load_object.variants.size > 0)
|
|
91
|
-
|
|
92
|
-
if(current_value.to_s.include?(LoaderBase::multi_assoc_delim))
|
|
93
|
-
|
|
94
|
-
#puts "DEBUG: COUNT_ON_HAND PER VARIANT",current_value.is_a?(String),
|
|
95
|
-
|
|
96
|
-
# Check if we processed Option Types and assign count per option
|
|
97
|
-
values = current_value.to_s.split(LoaderBase::multi_assoc_delim)
|
|
98
|
-
|
|
99
|
-
if(@load_object.variants.size == values.size)
|
|
100
|
-
@load_object.variants.each_with_index {|v, i| v.on_hand = values[i].to_i }
|
|
101
|
-
@load_object.save
|
|
102
|
-
else
|
|
103
|
-
puts "WARNING: Count on hand entries did not match number of Variants - None Set"
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# Can only set count on hand on Product if no Variants exist, else model throws
|
|
108
|
-
|
|
109
|
-
elsif(@load_object.variants.size == 0)
|
|
110
|
-
if(current_value.to_s.include?(LoaderBase::multi_assoc_delim))
|
|
111
|
-
puts "WARNING: Multiple count_on_hand values specified but no Variants/OptionTypes created"
|
|
112
|
-
load_object.on_hand = current_value.to_s.split(LoaderBase::multi_assoc_delim).first.to_i
|
|
113
|
-
else
|
|
114
|
-
load_object.on_hand = current_value.to_i
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
else
|
|
119
|
-
super
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
private
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
# Special case for OptionTypes as it's two stage process
|
|
128
|
-
# First add the possible option_types to Product, then we are able
|
|
129
|
-
# to define Variants on those options values.
|
|
130
|
-
# To defiene a Variant :
|
|
131
|
-
# 1) define at least one OptionType on Product, for example Size
|
|
132
|
-
# 2) Provide a value for at least one of these OptionType
|
|
133
|
-
# 3) A composite Variant can be created by supplyiung a vlaue for more than one OptionType
|
|
134
|
-
# fro example Colour : Red and Size Medium
|
|
135
|
-
# Supported Syntax :
|
|
136
|
-
# '|' seperates Variants
|
|
137
|
-
# ',' list of option values
|
|
138
|
-
# Examples :
|
|
139
|
-
# mime_type:jpeg;print_type:black_white|mime_type:jpeg|mime_type:png, PDF;print_type:colour
|
|
140
|
-
#
|
|
141
|
-
def add_options
|
|
142
|
-
|
|
143
|
-
# TODO smart column ordering to ensure always valid by time we get to associations
|
|
144
|
-
save_if_new
|
|
145
|
-
|
|
146
|
-
# example : mime_type:jpeg;print_type:black_white|mime_type:jpeg|mime_type:png, PDF;print_type:colour
|
|
147
|
-
|
|
148
|
-
variants = get_each_assoc#current_value.split( LoaderBase::multi_assoc_delim )
|
|
149
|
-
|
|
150
|
-
# 1) mime_type:jpeg;print_type:black_white 2) mime_type:jpeg 3) mime_type:png, PDF;print_type:colour
|
|
151
|
-
|
|
152
|
-
variants.each do |per_variant|
|
|
153
|
-
|
|
154
|
-
option_types = per_variant.split(';') # [mime_type:jpeg, print_type:black_white]
|
|
155
|
-
|
|
156
|
-
optiontype_vlist_map = {}
|
|
157
|
-
|
|
158
|
-
option_types.each do |ostr|
|
|
159
|
-
|
|
160
|
-
oname, value_str = ostr.split(LoaderBase::name_value_delim)
|
|
161
|
-
|
|
162
|
-
option_type = @@option_type_klass.find_by_name(oname)
|
|
163
|
-
|
|
164
|
-
unless option_type
|
|
165
|
-
option_type = @@option_type_klass.create( :name => oname, :presentation => oname.humanize)
|
|
166
|
-
# TODO - dynamic creation should be an option
|
|
167
|
-
|
|
168
|
-
unless option_type
|
|
169
|
-
puts "WARNING: OptionType #{oname} NOT found and could not create - Not set Product"
|
|
170
|
-
next
|
|
171
|
-
end
|
|
172
|
-
puts "Created missing OptionType #{option_type.inspect}"
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
# OptionTypes must be specified first on Product to enable Variants to be created
|
|
176
|
-
# TODO - is include? very inefficient ??
|
|
177
|
-
@load_object.option_types << option_type unless @load_object.option_types.include?(option_type)
|
|
178
|
-
|
|
179
|
-
# Can be simply list of OptionTypes, some or all without values
|
|
180
|
-
next unless(value_str)
|
|
181
|
-
|
|
182
|
-
optiontype_vlist_map[option_type] = []
|
|
183
|
-
|
|
184
|
-
# Now get the value(s) for the option e.g red,blue,green for OptType 'colour'
|
|
185
|
-
optiontype_vlist_map[option_type] = value_str.split(',')
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
next if(optiontype_vlist_map.empty?) # only option types specified - no values
|
|
189
|
-
|
|
190
|
-
# Now create set of Variants, some of which maybe composites
|
|
191
|
-
# Find the longest set of OVs to use as base for combining with the rest
|
|
192
|
-
sorted_map = optiontype_vlist_map.sort_by { |k,v| v.size }.reverse
|
|
193
|
-
|
|
194
|
-
# ovalues = 'pdf','jpeg','png'
|
|
195
|
-
option_type, ovalues = sorted_map.shift
|
|
196
|
-
# TODO .. benchmarking to find most efficient way to create these but ensure Product.variants list
|
|
197
|
-
# populated .. currently need to call reload to ensure this (seems reqd for Spree 1/Rails 3, wasn't required b4
|
|
198
|
-
ovalues.each do |ovname|
|
|
199
|
-
|
|
200
|
-
ov_list = []
|
|
201
|
-
|
|
202
|
-
ov = @@option_value_klass.find_or_create_by_name_and_option_type_id(ovname.strip, option_type.id)
|
|
203
|
-
|
|
204
|
-
ov_list << ov if ov
|
|
205
|
-
|
|
206
|
-
sorted_map.each do |ot, ovlist| ovlist.each do |for_composite|
|
|
207
|
-
ov = @@option_value_klass.find_or_create_by_name_and_option_type_id(for_composite.strip, ot.id)
|
|
208
|
-
|
|
209
|
-
ov_list << ov if(ov)
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
unless(ov_list.empty?)
|
|
214
|
-
i = @load_object.variants.size + 1
|
|
215
|
-
|
|
216
|
-
# This one line seems to works for 1.1.0 - 3.2 but not 1.0.0 - 3.1 ??
|
|
217
|
-
if(SpreeHelper::version.to_f >= 1.1)
|
|
218
|
-
variant = @load_object.variants.create( :sku => "#{@load_object.sku}_#{i}", :price => @load_object.price)
|
|
219
|
-
else
|
|
220
|
-
variant = @@variant_klass.create( :product => @load_object, :sku => "#{@load_object.sku}_#{i}", :price => @load_object.price, :available_on => @load_object.available_on)
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
variant.option_values << ov_list if(variant)
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
#puts "DEBUG Load Object now has Variants : #{@load_object.variants.inspect}"
|
|
228
|
-
@load_object.reload unless @load_object.new_record?
|
|
229
|
-
#puts "DEBUG Load Object now has Variants : #{@load_object.variants.inspect}"
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
end # each Variant
|
|
233
|
-
|
|
234
|
-
# Special case for Images
|
|
235
|
-
# A list of paths to Images with a optional 'alt' value - supplied in form :
|
|
236
|
-
# path:alt|path2:alt2|path_3:alt3 etc
|
|
237
|
-
#
|
|
238
|
-
def add_images
|
|
239
|
-
# TODO smart column ordering to ensure always valid by time we get to associations
|
|
240
|
-
save_if_new
|
|
241
|
-
|
|
242
|
-
images = get_each_assoc#current_value.split(LoaderBase::multi_assoc_delim)
|
|
243
|
-
|
|
244
|
-
images.each do |image|
|
|
245
|
-
puts "Add Image #{image}"
|
|
246
|
-
img_path, alt_text = image.split(LoaderBase::name_value_delim)
|
|
247
|
-
|
|
248
|
-
# moved from Prod to Variant in spree 1.x.x
|
|
249
|
-
attachment = (SpreeHelper::version.to_f > 1) ? @load_object.master : @load_object
|
|
250
|
-
|
|
251
|
-
image = create_image(@@image_klass, img_path, attachment, :alt => alt_text)
|
|
252
|
-
logger.debug("Product assigned an Image : #{image.inspect}")
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
# Special case for ProductProperties since it can have additional value applied.
|
|
259
|
-
# A list of Properties with a optional Value - supplied in form :
|
|
260
|
-
# property_name:value|property_name|property_name:value
|
|
261
|
-
# Example :
|
|
262
|
-
# test_pp_002|test_pp_003:Example free value|yet_another_property
|
|
263
|
-
|
|
264
|
-
def add_properties
|
|
265
|
-
# TODO smart column ordering to ensure always valid by time we get to associations
|
|
266
|
-
save_if_new
|
|
267
|
-
|
|
268
|
-
property_list = get_each_assoc#current_value.split(LoaderBase::multi_assoc_delim)
|
|
269
|
-
|
|
270
|
-
property_list.each do |pstr|
|
|
271
|
-
|
|
272
|
-
# Special case, we know we lookup on name so operator is effectively the name to lookup
|
|
273
|
-
find_by_name, find_by_value = get_find_operator_and_rest( pstr )
|
|
274
|
-
|
|
275
|
-
raise "Cannot find Property via #{find_by_name} (with value #{find_by_value})" unless(find_by_name)
|
|
276
|
-
|
|
277
|
-
property = @@property_klass.find_by_name(find_by_name)
|
|
278
|
-
|
|
279
|
-
unless property
|
|
280
|
-
property = @@property_klass.create( :name => find_by_name, :presentation => find_by_name.humanize)
|
|
281
|
-
logger.info "Created New Property #{property.inspect}"
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
if(property)
|
|
285
|
-
if(SpreeHelper::version.to_f >= 1.1)
|
|
286
|
-
# Property now protected from mass assignment
|
|
287
|
-
x = @@product_property_klass.new( :value => find_by_value )
|
|
288
|
-
x.property = property
|
|
289
|
-
x.save
|
|
290
|
-
@load_object.product_properties << x
|
|
291
|
-
logger.info "Created New ProductProperty #{x.inspect}"
|
|
292
|
-
else
|
|
293
|
-
@load_object.product_properties << @@product_property_klass.create( :property => property, :value => find_by_values)
|
|
294
|
-
end
|
|
295
|
-
else
|
|
296
|
-
puts "WARNING: Property #{find_by_name} NOT found - Not set Product"
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
# Nested tree structure support ..
|
|
304
|
-
# TAXON FORMAT
|
|
305
|
-
# name|name>child>child|name
|
|
306
|
-
|
|
307
|
-
def add_taxons
|
|
308
|
-
# TODO smart column ordering to ensure always valid by time we get to associations
|
|
309
|
-
save_if_new
|
|
310
|
-
|
|
311
|
-
chain_list = get_each_assoc#current_value().split(LoaderBase::multi_assoc_delim)
|
|
312
|
-
|
|
313
|
-
chain_list.each do |chain|
|
|
314
|
-
|
|
315
|
-
name_list = chain.split(/\s*>\s*/)
|
|
316
|
-
|
|
317
|
-
# manage per chain
|
|
318
|
-
parent_taxonomy, parent, taxon = nil, nil, nil
|
|
319
|
-
|
|
320
|
-
# Each chain can contain either a single Taxon, or the tree like structure parent>child>child
|
|
321
|
-
taxons = name_list.collect do |name|
|
|
322
|
-
|
|
323
|
-
#puts "DEBUG: NAME #{name.inspect}"
|
|
324
|
-
begin
|
|
325
|
-
taxon = @@taxon_klass.find_by_name( name )
|
|
326
|
-
|
|
327
|
-
if(taxon)
|
|
328
|
-
parent_taxonomy ||= taxon.taxonomy
|
|
329
|
-
else
|
|
330
|
-
parent_taxonomy ||= @@taxonomy_klass.find_or_create_by_name(name)
|
|
331
|
-
|
|
332
|
-
taxon = @@taxon_klass.find_or_create_by_name_and_parent_id_and_taxonomy_id(name, parent && parent.id, parent_taxonomy.id)
|
|
333
|
-
end
|
|
334
|
-
rescue => e
|
|
335
|
-
puts e.inspect
|
|
336
|
-
puts "ERROR : Cannot assign Taxon ['#{taxon}'] to Product ['#{load_object.name}']"
|
|
337
|
-
next
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
parent = taxon
|
|
341
|
-
taxon
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
unique_list = taxons.compact.uniq - (@load_object.taxons || [])
|
|
345
|
-
|
|
346
|
-
logger.debug("Product assigned to Taxons : #{unique_list.collect(&:name).inspect}")
|
|
347
|
-
@load_object.taxons << unique_list unless(unique_list.empty?)
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
end
|
|
353
|
-
end
|
|
354
|
-
end
|