datashift 0.7.0 → 0.8.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.
@@ -0,0 +1,66 @@
1
+ # Copyright:: (c) Autotelik Media Ltd 2012
2
+ # Author :: Tom Statter
3
+ # Date :: March 2012
4
+ # License:: MIT. Free, Open Source.
5
+ #
6
+ # Usage::
7
+ # bundle exec thor help datashift:spreeboot
8
+ # bundle exec thor datashift:spreeboot:cleanup
9
+ #
10
+ # Note, not DataShift, case sensitive, create namespace for command line : datashift
11
+
12
+ require 'excel_exporter'
13
+
14
+ module Datashift
15
+
16
+ class Reports < Thor
17
+
18
+ include DataShift::Logging
19
+
20
+ desc "missing_images", "Spree Products without an image"
21
+
22
+ def missing_images(report = nil)
23
+
24
+ require 'spree_helper'
25
+ require 'image_loader'
26
+
27
+ require File.expand_path('config/environment.rb')
28
+
29
+ klass = DataShift::SpreeHelper::get_spree_class('Product')
30
+
31
+ missing = klass.all.find_all {|p| p.images.size == 0 }
32
+
33
+ puts "There are #{missing.size} Products without an associated Image"
34
+
35
+ if(DataShift::Guards::jruby?)
36
+ fname = report ? report : "missing_images.xls"
37
+ DataShift::ExcelExporter.new( fname ).export( missing )
38
+ else
39
+ puts missing.collect(&:name).inspect
40
+ end
41
+
42
+ @drop_box = "/home/stattert/Dropbox/DaveWebsiteInfo/"
43
+
44
+ @image_list = %w{
45
+ 010InafixTheArmourGodAllFolders
46
+ 01Figuresurbanlandscapepaintings
47
+ 01FinishedArtPrints
48
+ 02Seascapespainting
49
+ 03Landscapes
50
+ 04Spain
51
+
52
+ 07SignsJohnAllFolders
53
+ 07_Mar
54
+ 09Powerpointsermonaids
55
+ }
56
+
57
+ options = { :recursive => true }
58
+
59
+ images = @image_list.collect do |p|
60
+ DataShift::ImageLoading::get_files(File.join(@drop_box,p), options)
61
+ end
62
+
63
+ puts images.inspect
64
+ end
65
+ end
66
+ end
@@ -9,7 +9,14 @@ class CreateTestBed < ActiveRecord::Migration
9
9
 
10
10
  def self.up
11
11
 
12
+ create_table :users do |t|
13
+ t.string :title
14
+ t.string :first_name
15
+ end
16
+
17
+ # belongs_to :user
12
18
  # has many :milestones
19
+ #
13
20
  create_table :projects do |t|
14
21
  t.string :title
15
22
  t.string :value_as_string
@@ -18,10 +25,13 @@ class CreateTestBed < ActiveRecord::Migration
18
25
  t.datetime :value_as_datetime, :default => nil
19
26
  t.integer :value_as_integer, :default => 0
20
27
  t.decimal :value_as_double, :precision => 8, :scale => 2, :default => 0.0
28
+ t.references :user
21
29
  t.timestamps
22
30
  end
23
31
 
24
- # belongs_to :project, project => has_many
32
+ # belongs_to :project
33
+ # @project => has_many :milestones
34
+
25
35
  create_table :milestones do |t|
26
36
  t.string :name
27
37
  t.datetime :datetime, :default => nil
@@ -73,6 +83,7 @@ class CreateTestBed < ActiveRecord::Migration
73
83
  end
74
84
 
75
85
  def self.down
86
+ drop_table :users
76
87
  drop_table :projects
77
88
  drop_table :categories
78
89
  drop_table :loader_releases
@@ -56,7 +56,7 @@ if(Guards::jruby?)
56
56
  puts "Can manually check file @ #{expect}"
57
57
  end
58
58
 
59
- it "should genrate a complex template .xls file from model" do
59
+ it "should include all associations in template .xls file from model" do
60
60
 
61
61
  expect= result_file('project_plus_assoc_template_spec.xls')
62
62
 
@@ -67,7 +67,45 @@ if(Guards::jruby?)
67
67
  File.exists?(expect).should be_true
68
68
 
69
69
  end
70
+
71
+
72
+ it "should enable us to exclude cetain associations in template .xls file from model" do
73
+
74
+ expect= result_file('project_plus_some_assoc_template_spec.xls')
75
+
76
+ gen = ExcelGenerator.new(expect)
77
+
78
+ options = {:exclude => :milestones }
79
+
80
+ gen.generate_with_associations(Project, options)
81
+
82
+ File.exists?(expect).should be_true
83
+
84
+ excel = JExcelFile.new(expect)
85
+
86
+ excel.each_row {|r| puts r.inspect }
87
+
88
+ end
89
+
90
+
91
+ it "should enable us to autosize columns in the .xls file" do
92
+
93
+ expect= result_file('project_autosized_template_spec.xls')
94
+
95
+ gen = ExcelGenerator.new(expect)
96
+
97
+ options = {:autosize => true, :exclude => :milestones }
98
+
99
+ gen.generate_with_associations(Project, options)
70
100
 
101
+ File.exists?(expect).should be_true
102
+
103
+ excel = JExcelFile.new(expect)
104
+
105
+ excel.each_row {|r| puts r.inspect }
106
+
107
+ end
108
+
71
109
  end
72
110
  else
73
111
  puts "WARNING: skipped excel_generator_spec : Requires JRUBY - JExcelFile requires JAVA"
@@ -114,6 +114,7 @@ if(Guards::jruby?)
114
114
  loader.perform_load( $DataShiftFixturePath + '/ProjectsMultiCategoriesHeaderLookup.xls')
115
115
 
116
116
  loader.loaded_count.should == (Project.count - count)
117
+ loader.loaded_count.should > 3
117
118
 
118
119
  {'004' => 4, '005' => 1, '006' => 0, '007' => 1 }.each do|title, expected|
119
120
  project = Project.find_by_title(title)
@@ -0,0 +1,4 @@
1
+ "SKU","Name","Description","Available On"," Price","CostPrice","Option Types","Option Types","Variants","count_on_hand"
2
+ "MV_001","Demo Product for AR Loader","blah blah","2011-02-14",399.99,320.00,"mime_type:jpeg, PDF;print_type:colour",,"mime_type:PNG","12|6|7"
3
+ "MV_002","Demo Excel Load via Jruby","less blah","2011-05-14",100.00,30.00,"mime_type:jpeg;print_type:black_white",,"mime_type:PNG;print_type:black_white","5|4"
4
+ "MV_003","Demo third row in future","more blah blah","2012-07-01",50.34,23.34,"mime_type:jpeg;print_type:colour, sepia;size:large|mime_type:PNG","mime_type:PDF|print_type:black_white",,"12|4|7|12"
@@ -1,4 +1,4 @@
1
1
  "SKU","Name","Description","Available On"," Price","CostPrice","count_on_hand","Option Types"
2
2
  "SIMPLE_001","Simple Product for AR Loader","blah blah","2011-02-14",345.78,320.00,12,"mime_type"
3
3
  "SIMPLE_002","Simple Excel Load via Jruby","less blah","2011-05-14",100.00,30.00,5,"mime_type"
4
- "SIMPLE_003","Simple third row avail in future","more blah blah","2012-07-01",50.34,23.34,23,"mime_type|print_type"
4
+ "SIMPLE_003","Simple third row avail in future","more blah blah","2112-07-01",50.34,23.34,23,"mime_type|print_type"
@@ -1,3 +1,7 @@
1
+ # A set of models and associations we can use in our specs to test
2
+ # basic database columns and also relationships
3
+
4
+ # See Companion migration spec/db/migrate
1
5
 
2
6
  class Project < ActiveRecord::Base
3
7
 
@@ -35,7 +35,10 @@ describe 'SpreeImageLoading' do
35
35
  @Product_klass.count.should == 0
36
36
 
37
37
  MethodDictionary.clear
38
- MethodDictionary.find_operators( @klass )
38
+
39
+ # For Spree important to get instance methods too as Product delegates
40
+ # many important attributes to Variant (master)
41
+ MethodDictionary.find_operators( @Product_klass, :instance_methods => true )
39
42
 
40
43
  @product_loader = DataShift::SpreeHelper::ProductLoader.new
41
44
  rescue => e
@@ -45,17 +48,13 @@ describe 'SpreeImageLoading' do
45
48
  end
46
49
 
47
50
 
48
- it "should load Products with associated image from CSV" do
49
-
50
- # In >= 1.1.0 Image moved to master Variant from Product
51
-
51
+ it "should create Image from path in Product loading column from CSV", :fail => true do
52
+
52
53
  options = {:mandatory => ['sku', 'name', 'price']}
53
54
 
54
- options[:force_inclusion] = ['sku', 'images'] if(SpreeHelper::version.to_f > 1 )
55
-
56
55
  @product_loader.perform_load( SpecHelper::spree_fixture('SpreeProductsWithImages.csv'), options )
57
56
 
58
- @Image_klass.all.each_with_index {|i, x| puts "RESULT IMAGE #{x}", i.inspect }
57
+ @Image_klass.all.each_with_index {|i, x| puts "SPEC CHECK IMAGE #{x}", i.inspect }
59
58
 
60
59
  p = @Product_klass.find_by_name("Demo Product for AR Loader")
61
60
 
@@ -70,15 +69,11 @@ describe 'SpreeImageLoading' do
70
69
  end
71
70
 
72
71
 
73
- it "should load Products with associated image" do
72
+ it "should create Image from path in Product loading column from Excel", :fail => true do
74
73
 
75
74
  options = {:mandatory => ['sku', 'name', 'price']}
76
75
 
77
- options[:force_inclusion] = ['sku', 'images'] if(SpreeHelper::version.to_f > 1 )
78
-
79
76
  @product_loader.perform_load( SpecHelper::spree_fixture('SpreeProductsWithImages.xls'), options )
80
-
81
- @Image_klass.all.each_with_index {|i, x| puts "RESULT IMAGE #{x}", i.inspect }
82
77
 
83
78
  p = @klass.find_by_name("Demo Product for AR Loader")
84
79
 
@@ -91,7 +86,9 @@ describe 'SpreeImageLoading' do
91
86
 
92
87
  end
93
88
 
94
- it "should be able to assign Images to preloaded Products", :fail => true do
89
+ it "should be able to assign Images to preloaded Products" do
90
+
91
+ pending "Currently functionality supplied by a thor task images()"
95
92
 
96
93
  MethodDictionary.find_operators( @Image_klass )
97
94
 
@@ -101,24 +98,9 @@ describe 'SpreeImageLoading' do
101
98
 
102
99
  @Image_klass.all.size.should == 0
103
100
 
104
- # force inclusion means add to operator list even if not present
105
- options = { :verbose => true, :force_inclusion => ['sku', 'attachment'] } if(SpreeHelper::version.to_f > 1 )
106
-
107
101
  loader = DataShift::SpreeHelper::ImageLoader.new(nil, options)
108
102
 
109
103
  loader.perform_load( SpecHelper::spree_fixture('SpreeImages.xls'), options )
110
-
111
- @Image_klass.all.each_with_index {|i, x| puts "RESULT IMAGE #{x}", i.inspect }
112
-
113
- @Image_klass.count.should == 3
114
-
115
- p = @klass.find_by_name("Demo Product for AR Loader")
116
-
117
- p.name.should == "Demo Product for AR Loader"
118
-
119
- p.images.should have_exactly(1).items
120
-
121
- @Product_klass.all.each {|p| p.images.should have_exactly(1).items }
122
104
 
123
105
  end
124
106
 
@@ -30,8 +30,7 @@ describe 'SpreeLoader' do
30
30
  before(:each) do
31
31
 
32
32
  begin
33
-
34
-
33
+
35
34
  before_each_spree
36
35
 
37
36
  @Product_klass.count.should == 0
@@ -39,7 +38,10 @@ describe 'SpreeLoader' do
39
38
  @Variant_klass.count.should == 0
40
39
 
41
40
  MethodDictionary.clear
42
- MethodDictionary.find_operators( @Product_klass )
41
+
42
+ # For Spree important to get instance methods too as Product delegates
43
+ # many important attributes to Variant (master)
44
+ MethodDictionary.find_operators( @Product_klass, :instance_methods => true )
43
45
 
44
46
  # want to test both lookup and dynamic creation - this Taxonomy should be found, rest created
45
47
  root = @Taxonomy_klass.create( :name => 'Paintings' )
@@ -80,25 +82,24 @@ describe 'SpreeLoader' do
80
82
  loader.loaded_count.should == @Zone_klass.count
81
83
  end
82
84
 
85
+ it "should raise an error for missing file" do
86
+ lambda { test_basic_product('SpreeProductsSimple.txt') }.should raise_error BadFile
87
+ end
83
88
 
89
+ it "should raise an error for unsupported file types" do
90
+ lambda { test_basic_product('SpreeProductsDefaults.yml') }.should raise_error UnsupportedFileType
91
+ end
92
+
84
93
  # Loader should perform identically regardless of source, whether csv, .xls etc
85
94
 
86
- it "should load basic Products .xls via Spree loader", :fail => true do
95
+ it "should load basic Products .xls via Spree loader", :opts => true do
87
96
  test_basic_product('SpreeProductsSimple.xls')
88
97
  end
89
98
 
90
- it "should load basic Products from .csv via Spree loader", :csv => true, :fail => true do
99
+ it "should load basic Products from .csv via Spree loader", :csv => true do
91
100
  test_basic_product('SpreeProductsSimple.csv')
92
101
  end
93
102
 
94
- it "should raise an error for missing file" do
95
- lambda { test_basic_product('SpreeProductsSimple.txt') }.should raise_error BadFile
96
- end
97
-
98
- it "should raise an error for unsupported file types" do
99
- lambda { test_basic_product('SpreeProductsDefaults.yml') }.should raise_error UnsupportedFileType
100
- end
101
-
102
103
  def test_basic_product( source )
103
104
 
104
105
  @product_loader.perform_load( SpecHelper::spree_fixture(source), :mandatory => ['sku', 'name', 'price'] )
@@ -224,13 +225,13 @@ describe 'SpreeLoader' do
224
225
  p.option_types[0].name.should == "mime_type"
225
226
  p.option_types[0].presentation.should == "Mime type"
226
227
 
227
- @Variant_klass.all[1].sku.should == "DEMO_001_0"
228
+ @Variant_klass.all[1].sku.should == "DEMO_001_1"
228
229
  @Variant_klass.all[1].price.should == 399.99
229
230
 
230
231
  # V1
231
232
  v1 = p.variants[0]
232
233
 
233
- v1.sku.should == "DEMO_001_0"
234
+ v1.sku.should == "DEMO_001_1"
234
235
  v1.price.should == 399.99
235
236
  v1.count_on_hand.should == 12
236
237
 
@@ -258,7 +259,50 @@ describe 'SpreeLoader' do
258
259
 
259
260
  @product_loader.failed_objects.size.should == 0
260
261
  end
262
+
263
+ # Composite Variant Syntax is option_type_A_name:value;option_type_B_name:value
264
+ # which creates a SINGLE Variant with 2 option types
261
265
 
266
+ it "should create Variants with MULTIPLE option types from single column", :new => true do
267
+ @product_loader.perform_load( SpecHelper::spree_fixture('SpreeMultiVariant.csv'), :mandatory => ['sku', 'name', 'price'] )
268
+
269
+ # Product 1)
270
+ # 1 + 2) mime_type:jpeg,PDF;print_type:colour equivalent to (mime_type:jpeg;print_type:colour|mime_type:PDF;print_type:colour)
271
+ # 3) mime_type:PNG
272
+ #
273
+ # Product 2
274
+ # 4) mime_type:jpeg;print_type:black_white
275
+ # 5) mime_type:PNG;print_type:black_white
276
+ #
277
+ # Product 3
278
+ # 6 +7) mime_type:jpeg;print_type:colour,sepia;size:large
279
+ # 8) mime_type:jpeg;print_type:colour
280
+ # 9) mime_type:PNG
281
+ # 9 + 10) mime_type:PDF|print_type:black_white
282
+
283
+ prod_count = 3
284
+ var_count = 10
285
+
286
+ # plus 3 MASTER VARIANTS
287
+ @Product_klass.count.should == prod_count
288
+ @Variant_klass.count.should == prod_count + var_count
289
+
290
+ p = @Product_klass.first
291
+
292
+ p.variants_including_master.should have_exactly(4).items
293
+ p.variants.should have_exactly(3).items
294
+
295
+ p.variants.each { |v| v.option_values.each {|o| puts o.inspect } }
296
+
297
+ p.option_types.each { |ot| puts ot.inspect }
298
+ p.option_types.should have_exactly(2).items # mime_type, print_type
299
+
300
+ v1 = p.variants[0]
301
+ v1.option_values.should have_exactly(2).items
302
+ v1.option_values.collect(&:name).sort.should == ['colour','jpeg']
303
+
304
+ end
305
+
262
306
  ##################
263
307
  ### PROPERTIES ###
264
308
  ##################
@@ -429,5 +473,6 @@ describe 'SpreeLoader' do
429
473
  it "should raise exception when single mandatory column missing from .csv", :ex => true do
430
474
  expect {@product_loader.perform_load($SpreeNegativeFixturePath + '/SpreeProdMiss1Mandatory.csv', :mandatory => 'sku' )}.to raise_error(DataShift::MissingMandatoryError)
431
475
  end
476
+
432
477
 
433
478
  end
@@ -0,0 +1,45 @@
1
+ namespace :datashift do
2
+
3
+ namespace :db do
4
+
5
+ SYSTEM_TABLE_EXCLUSION_LIST = ['schema_migrations']
6
+
7
+ desc "Purge the current database"
8
+ task :purge, [:exclude_system_tables] => [:environment] do |t, args|
9
+ require 'highline/import'
10
+
11
+ if(Rails.env.production?)
12
+ agree("WARNING: In Production database, REALLY PURGE ? [y]:")
13
+ end
14
+
15
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
16
+ case config['adapter']
17
+ when "mysql", "mysql2", "jdbcmysql"
18
+ ActiveRecord::Base.establish_connection(config)
19
+ ActiveRecord::Base.connection.tables.each do |table|
20
+ next if(args[:exclude_system_tables] && SYSTEM_TABLE_EXCLUSION_LIST.include?(table) )
21
+ puts "purging table: #{table}"
22
+ ActiveRecord::Base.connection.execute("TRUNCATE #{table}")
23
+ end
24
+ when "sqlite","sqlite3"
25
+ dbfile = config["database"] || config["dbfile"]
26
+ File.delete(dbfile) if File.exist?(dbfile)
27
+ when "sqlserver"
28
+ dropfkscript = "#{config["host"]}.#{config["database"]}.DP1".gsub(/\\/,'-')
29
+ `osql -E -S #{config["host"]} -d #{config["database"]} -i db\\#{dropfkscript}`
30
+ `osql -E -S #{config["host"]} -d #{config["database"]} -i db\\#{Rails.env}_structure.sql`
31
+ when "oci", "oracle"
32
+ ActiveRecord::Base.establish_connection(config)
33
+ ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
34
+ ActiveRecord::Base.connection.execute(ddl)
35
+ end
36
+ when "firebird"
37
+ ActiveRecord::Base.establish_connection(config)
38
+ ActiveRecord::Base.connection.recreate_database!
39
+ else
40
+ raise "Task not supported by '#{config["adapter"]}'"
41
+ end
42
+ end
43
+
44
+ end
45
+ end