datashift 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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