move-to-go 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/bin/move-to-go +210 -0
  3. data/lib/move-to-go/can_become_immutable.rb +29 -0
  4. data/lib/move-to-go/csv_helper.rb +47 -0
  5. data/lib/move-to-go/email_helper.rb +14 -0
  6. data/lib/move-to-go/errors.rb +31 -0
  7. data/lib/move-to-go/excel_helper.rb +10 -0
  8. data/lib/move-to-go/global_phone.json +6571 -0
  9. data/lib/move-to-go/model/address.rb +63 -0
  10. data/lib/move-to-go/model/class_settings.rb +50 -0
  11. data/lib/move-to-go/model/clientvisit.rb +10 -0
  12. data/lib/move-to-go/model/comment.rb +10 -0
  13. data/lib/move-to-go/model/coworker.rb +82 -0
  14. data/lib/move-to-go/model/coworker_reference.rb +33 -0
  15. data/lib/move-to-go/model/customfield.rb +87 -0
  16. data/lib/move-to-go/model/deal.rb +216 -0
  17. data/lib/move-to-go/model/deal_class_settings.rb +97 -0
  18. data/lib/move-to-go/model/deal_state.rb +15 -0
  19. data/lib/move-to-go/model/deal_status.rb +23 -0
  20. data/lib/move-to-go/model/deal_status_reference.rb +47 -0
  21. data/lib/move-to-go/model/deal_status_setting.rb +49 -0
  22. data/lib/move-to-go/model/documents.rb +76 -0
  23. data/lib/move-to-go/model/file.rb +193 -0
  24. data/lib/move-to-go/model/history.rb +148 -0
  25. data/lib/move-to-go/model/history_classification.rb +26 -0
  26. data/lib/move-to-go/model/link.rb +82 -0
  27. data/lib/move-to-go/model/organization.rb +250 -0
  28. data/lib/move-to-go/model/person.rb +164 -0
  29. data/lib/move-to-go/model/referencetosource.rb +58 -0
  30. data/lib/move-to-go/model/relation.rb +23 -0
  31. data/lib/move-to-go/model/rootmodel.rb +663 -0
  32. data/lib/move-to-go/model/salescall.rb +10 -0
  33. data/lib/move-to-go/model/settings.rb +61 -0
  34. data/lib/move-to-go/model/tag.rb +35 -0
  35. data/lib/move-to-go/model/talkedto.rb +10 -0
  36. data/lib/move-to-go/model/triedtoreach.rb +10 -0
  37. data/lib/move-to-go/model_helpers.rb +97 -0
  38. data/lib/move-to-go/phone_helper.rb +75 -0
  39. data/lib/move-to-go/roo_helper.rb +82 -0
  40. data/lib/move-to-go/serialize_helper.rb +199 -0
  41. data/lib/move-to-go/shard_helper.rb +96 -0
  42. data/lib/move-to-go/source.rb +108 -0
  43. data/lib/move-to-go/templating.rb +52 -0
  44. data/lib/move-to-go.rb +20 -0
  45. data/sources/VISMA/.gitignore +14 -0
  46. data/sources/VISMA/.move-to-go/readme.txt +1 -0
  47. data/sources/VISMA/.move-to-go/runner.rb +89 -0
  48. data/sources/VISMA/Database/KONTAKT.DBF +0 -0
  49. data/sources/VISMA/Database/KUND.DBF +0 -0
  50. data/sources/VISMA/Gemfile +5 -0
  51. data/sources/VISMA/converter.rb +120 -0
  52. data/sources/base-crm/.move-to-go/runner.rb +235 -0
  53. data/sources/base-crm/Gemfile +5 -0
  54. data/sources/base-crm/README.md +9 -0
  55. data/sources/base-crm/converter.rb +56 -0
  56. data/sources/base-crm/data/contacts.csv +13 -0
  57. data/sources/base-crm/data/coworkers.csv +3 -0
  58. data/sources/base-crm/data/deals.csv +5 -0
  59. data/sources/base-crm/data/histories.csv +6 -0
  60. data/sources/base-crm/data/leads.csv +4 -0
  61. data/sources/base-crm/data/tasks.csv +5 -0
  62. data/sources/csv/.gitignore +14 -0
  63. data/sources/csv/.move-to-go/readme.txt +1 -0
  64. data/sources/csv/.move-to-go/runner.rb +65 -0
  65. data/sources/csv/Gemfile +5 -0
  66. data/sources/csv/converter.rb +218 -0
  67. data/sources/csv/data/coworkers.csv +2 -0
  68. data/sources/csv/data/deals.csv +2 -0
  69. data/sources/csv/data/organizations.csv +2 -0
  70. data/sources/csv/data/persons.csv +2 -0
  71. data/sources/custom/.gitignore +14 -0
  72. data/sources/custom/.move-to-go/readme.txt +1 -0
  73. data/sources/custom/.move-to-go/runner.rb +30 -0
  74. data/sources/custom/Gemfile +4 -0
  75. data/sources/custom/converter.rb +45 -0
  76. data/sources/excel/.gitignore +14 -0
  77. data/sources/excel/.move-to-go/readme.txt +3 -0
  78. data/sources/excel/.move-to-go/runner.rb +140 -0
  79. data/sources/excel/Gemfile +7 -0
  80. data/sources/excel/converter.rb +188 -0
  81. data/sources/excel/files/avtal.docx +0 -0
  82. data/sources/excel/files/more/avtal.docx +0 -0
  83. data/sources/excel/files/more/offert-2.pdf +0 -0
  84. data/sources/excel/files/offert-2.docx +0 -0
  85. data/sources/excel/files/offert.docx +0 -0
  86. data/sources/excel/sample-data.xlsx +0 -0
  87. data/sources/excel-basic/.gitignore +14 -0
  88. data/sources/excel-basic/.move-to-go/readme.txt +3 -0
  89. data/sources/excel-basic/.move-to-go/runner.rb +139 -0
  90. data/sources/excel-basic/Exempelfil.xlsx +0 -0
  91. data/sources/excel-basic/Gemfile +6 -0
  92. data/sources/excel-basic/converter.rb +175 -0
  93. data/sources/excel-basic/files/avtal.docx +0 -0
  94. data/sources/excel-basic/files/more/avtal.docx +0 -0
  95. data/sources/excel-basic/files/more/offert-2.pdf +0 -0
  96. data/sources/excel-basic/files/offert-2.docx +0 -0
  97. data/sources/excel-basic/files/offert.docx +0 -0
  98. data/sources/lime-crm-basic/.gitignore +14 -0
  99. data/sources/lime-crm-basic/.move-to-go/readme.txt +1 -0
  100. data/sources/lime-crm-basic/.move-to-go/runner.rb +524 -0
  101. data/sources/lime-crm-basic/Gemfile +6 -0
  102. data/sources/lime-crm-basic/converter.rb +396 -0
  103. data/sources/lime-easy/.gitignore +14 -0
  104. data/sources/lime-easy/.move-to-go/readme.txt +1 -0
  105. data/sources/lime-easy/.move-to-go/runner.rb +348 -0
  106. data/sources/lime-easy/Export/readme.txt +6 -0
  107. data/sources/lime-easy/Gemfile +5 -0
  108. data/sources/lime-easy/converter.rb +362 -0
  109. data/sources/salesforce/.gitignore +14 -0
  110. data/sources/salesforce/.move-to-go/readme.txt +1 -0
  111. data/sources/salesforce/.move-to-go/runner.rb +404 -0
  112. data/sources/salesforce/Gemfile +6 -0
  113. data/sources/salesforce/Gemfile.lock +48 -0
  114. data/sources/salesforce/converter.rb +113 -0
  115. data/sources/salesforce/export/readme.txt +3 -0
  116. data/spec/address_spec.rb +49 -0
  117. data/spec/class_settings_spec.rb +37 -0
  118. data/spec/coworker_spec.rb +94 -0
  119. data/spec/custom_field_spec.rb +22 -0
  120. data/spec/deal_class_settings_spec.rb +116 -0
  121. data/spec/deal_spec.rb +232 -0
  122. data/spec/deal_status_reference_spec.rb +17 -0
  123. data/spec/documents_spec.rb +64 -0
  124. data/spec/file_spec.rb +178 -0
  125. data/spec/helpers/csv_helper_spec.rb +45 -0
  126. data/spec/helpers/email_helper_spec.rb +37 -0
  127. data/spec/helpers/phone_helper_spec.rb +119 -0
  128. data/spec/helpers/roo_helper_spec.rb +10 -0
  129. data/spec/helpers/serialize_helper_spec.rb +253 -0
  130. data/spec/helpers/shard_helper_spec.rb +141 -0
  131. data/spec/helpers/xsd_validate_spec.rb +57 -0
  132. data/spec/history_spec.rb +150 -0
  133. data/spec/link_spec.rb +107 -0
  134. data/spec/organization_spec.rb +221 -0
  135. data/spec/person_spec.rb +129 -0
  136. data/spec/rootmodel_spec.rb +993 -0
  137. data/spec/spec_helper.rb +30 -0
  138. metadata +362 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 30c626193cc7bca95c36653b34caaf2bf9e7b593
4
+ data.tar.gz: 0ffa9010615f179ed02e9c0a51b7f9723eee3cfd
5
+ SHA512:
6
+ metadata.gz: 6338cf52b8472ffd1d4ccc2a494d2191549b27aa290e8feed5971e9716f7d9eac84662dc87a472c40b7830cbda310b1390209763fdaa03817116c22e11c42119
7
+ data.tar.gz: d961df52d8fa809abd86d355420da3eaf626b60a04a8bcac207829d911943cae79fe9b5c8eaa2ad01bba18232a60308bb00e03bc46c95a9182e7f2c3bc25ee43
data/bin/move-to-go ADDED
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "thor"
4
+ require_relative '../lib/move-to-go'
5
+ require 'progress'
6
+
7
+
8
+ RUNNER_DIR = ".move-to-go"
9
+
10
+ class MoveToGoCommandLine < Thor
11
+
12
+ desc "about", "About move-to-go"
13
+ def about()
14
+ puts "move-to-go is an migration tool for LIME Go. It can take virtually any input source and create import data files that LIME Go likes."
15
+ puts "move-to-go has some predefined sources that will make it easy for you to migrate your data."
16
+ puts ""
17
+ end
18
+
19
+ desc "list-sources", "Lists the available sources"
20
+ def list_sources()
21
+ puts "The following sources are available:"
22
+ puts
23
+
24
+ sources = MoveToGo::Sources.new(source_path)
25
+ sources.list().each do |s|
26
+ puts "\t#{s}"
27
+ end
28
+
29
+ puts "\nCreate a new project with 'move-to-go new <PROJECT> <SOURCE>' with one of these sources."
30
+ puts "Use 'move-to-go about <SOURCE>' for more information about a specific source."
31
+ end
32
+
33
+ desc "about <SOURCE>", "Prints information about the specifed source"
34
+ def about(source)
35
+ sources = MoveToGo::Sources.new(source_path)
36
+
37
+ sources.about_source(source)
38
+ end
39
+
40
+ desc "new <PROJECT> <SOURCE>", "Creates a new migration project with a specifed name and source"
41
+ def new(project, source)
42
+ sources = MoveToGo::Sources.new(source_path)
43
+
44
+ if sources.create_project_from_source(project, source)
45
+ puts "\nProject '#{project}' created from source '#{source}'."
46
+ puts "Modify the #{project}/converter.rb script to suit your source."
47
+ puts "Use 'move-to-go run' from the project directory to create the zip file for LIME Go."
48
+ end
49
+ end
50
+
51
+ desc "run", "Executes the current project and create a go.zip file with data and files. Existing go.zip will be overwritten, use --output to specify a different filename."
52
+ option(:output,
53
+ :desc => "Name of the file where the converted source will be saved. This file should be sent to LIME Go. If the file already exist it will be replaced.",
54
+ :type => :string,
55
+ :required => false)
56
+ option(:ignore_invalid_files,
57
+ :desc => "Output will be created even if the import contains missing or invalid files",
58
+ :type => :boolean,
59
+ :required => false)
60
+ option(:log_to_file,
61
+ :desc => "Console output will be redirected to file",
62
+ :type => :string,
63
+ :required => false)
64
+ option(:max_file_size,
65
+ :desc => "Maximum size in bytes of documents included in zip",
66
+ :type => :numeric,
67
+ :required => false)
68
+ option(:output_documents,
69
+ :desc => "Name of the file to put imported documents in (default in same as --output)",
70
+ :type => :string,
71
+ :required => false)
72
+ option(:shard_size,
73
+ :desc => "Large imports are sharded into several zip-files. This property sets how many objects each zip-file should contain. Default is 25 000",
74
+ :type => :numeric,
75
+ :required => false)
76
+ def run_import()
77
+ if !options.log_to_file.nil?
78
+ $stdout = File.new(options.log_to_file == "log_to_file" ? "move-to-go.log" : options.log_to_file, 'w')
79
+ $stdout.sync = true
80
+ end
81
+ max_file_size = options.max_file_size.nil? ? MoveToGo::File::DEFAULT_MAX_FILE_SIZE : options.max_file_size
82
+
83
+ if !is_valid_project?
84
+ return
85
+ end
86
+
87
+ runner_file = ::File.expand_path("./#{RUNNER_DIR}/runner.rb", Dir.pwd)
88
+ require(runner_file)
89
+ model = convert_source()
90
+
91
+ if model.documents.files.length > 0 && (!defined?(FILES_FOLDER) || FILES_FOLDER.empty?())
92
+ puts "WARNING: It looks like you are importing files but FILES_FOLDER has not been set in your converter.rb."
93
+ puts "WARNING: FILES_FOLDER should be set unless you are only importing files with absolute paths."
94
+ end
95
+
96
+ if model.documents.files.length > 0 && (!defined?(FILES_FOLDER_AT_CUSTOMER) || FILES_FOLDER_AT_CUSTOMER.empty?())
97
+ puts "WARNING: It looks like you are importing files but FILES_FOLDER_AT_CUSTOMER has not been set in your converter.rb"
98
+ puts "WARNING: This means that files with an absolute path will be imported with their original path. Set this constant if you want to get files from the FILES_FOLDER directory."
99
+ end
100
+
101
+ is_ok, error_msg, warnings_msg = can_be_serialized?(model, options.ignore_invalid_files, max_file_size)
102
+ if is_ok
103
+
104
+ if options.ignore_invalid_files && model.documents.files.length > 0
105
+ log_and_remove_invalid_files model, max_file_size
106
+ end
107
+ model.report_rootmodel_status()
108
+
109
+ puts "Starting sharding of model..."
110
+ sharder = MoveToGo::ShardHelper.new(options.shard_size)
111
+ models_to_serialize = sharder.shard_model(model)
112
+
113
+ if models_to_serialize.length > 1
114
+ puts "Import is large and will be broken into #{models_to_serialize.length} files"
115
+ end
116
+
117
+ models_to_serialize.each_with_index do |model, i|
118
+ go_data_zip = options.output.nil? == true ? "go" : options.output
119
+ go_data_zip += "_#{i}.zip"
120
+ go_files = options.output_documents.nil? == true ? nil : ::File.basename(options.output_documents,File.extname(options.output_documents))
121
+ model.save_to_zip(go_data_zip, go_files)
122
+ puts "Source has been been converted into '#{go_data_zip}'."
123
+ puts " - and files into '#{go_files}.zip'." if !go_files.nil?
124
+ if !warnings_msg.empty?
125
+ puts "WARNINGS: "
126
+ puts warnings_msg
127
+ end
128
+ end
129
+ else
130
+ puts "ERROR: Source could not be converted due to:"
131
+ puts error_msg
132
+
133
+ if !options.ignore_invalid_files &&
134
+ model.documents.files.any? {|file| file.validate.empty?}
135
+ puts "move-to-go detected invalid files (see above), you can ignore these with the option --ignore-invalid-files."
136
+ end
137
+ end
138
+ end
139
+
140
+ private
141
+ def log_and_remove_invalid_files(model, max_file_size)
142
+ if model.documents.files.length > 0
143
+ file_log_header = "name;integration_id;path;organization.integrationid;organization.name;deal.integrationid;deal.name;file.size"
144
+ file_log = ""
145
+ files_to_remove = []
146
+ model.documents.files.with_progress(" - Trying to log files that can't be found...").each do |file|
147
+ if !::File.exists?(file.path_for_project)
148
+ file_log = "#{file_log}#{file.name};#{file.integration_id};#{file.path};#{file.organization.nil? ? '' : file.organization.integration_id};#{file.organization.nil? ? '' : file.organization.name};#{file.deal.nil? ? '' : file.deal.integration_id};#{file.deal.nil? ? '' : file.deal.name};0\n"
149
+ files_to_remove.push file
150
+ elsif ::File.size(file.path_for_project) > max_file_size
151
+ file_log = "#{file_log}#{file.name};#{file.integration_id};#{file.path};#{file.organization.nil? ? '' : file.organization.integration_id};#{file.organization.nil? ? '' : file.organization.name};#{file.deal.nil? ? '' : file.deal.integration_id};#{file.deal.nil? ? '' : file.deal.name};#{::File.size(file.path_for_project)}\n"
152
+ files_to_remove.push file
153
+ end
154
+ end
155
+
156
+ files_to_remove.each do |file|
157
+ model.documents.files.delete file
158
+ end
159
+
160
+ if file_log.length > 0
161
+ log_filename = 'move-to-go-invalid-files.csv'
162
+ ::File.open(log_filename, 'w') { |f|
163
+ f.puts file_log_header
164
+ f.puts file_log
165
+ }
166
+ puts "WARNING: move-to-go has invalid files (#{files_to_remove.length} of #{model.documents.files.length}). Filenames of all ignored files has been written to '#{log_filename}'."
167
+ else
168
+ puts "All files are OK."
169
+ end
170
+ end
171
+ end
172
+
173
+ private
174
+ def can_be_serialized?(rootmodel, ignore_invalid_files, max_file_size)
175
+ is_ok = false
176
+ error = rootmodel.sanity_check
177
+ if error.empty?
178
+ error, warnings = rootmodel.validate(ignore_invalid_files, max_file_size)
179
+
180
+ if error.empty?
181
+ is_ok = true
182
+ end
183
+ end
184
+
185
+ return [is_ok, error, warnings]
186
+ end
187
+
188
+ private
189
+ def is_valid_project?()
190
+ if Dir.exists?(RUNNER_DIR) == false
191
+ puts "This doesnt look like a move-to-go project. Are you in the right directory or did you mess with the '#{RUNNER_DIR}' folder?"
192
+ return false
193
+ end
194
+
195
+ runner_file = File.expand_path("./#{RUNNER_DIR}/runner.rb", Dir.pwd)
196
+ if File.exists?(runner_file) == false
197
+ puts "I can't run this project. Did you mess with the '#{RUNNER_DIR}' folder?"
198
+ return false
199
+ end
200
+
201
+ return true
202
+ end
203
+
204
+ private
205
+ def source_path()
206
+ File.expand_path("../sources", File.dirname(__FILE__))
207
+ end
208
+ end
209
+
210
+ MoveToGoCommandLine.start(ARGV)
@@ -0,0 +1,29 @@
1
+
2
+ module MoveToGo
3
+ class CanBecomeImmutable
4
+ def self.immutable_accessor(name)
5
+ define_method(name) do
6
+ return instance_variable_get("@#{name}")
7
+ end
8
+
9
+ define_method("#{name}=") do |value|
10
+ raise_if_immutable
11
+ instance_variable_set("@#{name}", value)
12
+ end
13
+ end
14
+
15
+ def raise_if_immutable
16
+ if @is_immutable
17
+ raise ObjectIsImmutableError
18
+ end
19
+ end
20
+
21
+ def set_is_immutable()
22
+ @is_immutable = true
23
+ end
24
+
25
+ def is_immutable()
26
+ @is_immutable
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,47 @@
1
+ require "csv"
2
+ module MoveToGo
3
+ module CsvHelper
4
+
5
+ # @example Detect column separator and transform to hashes
6
+ # hashes = MoveToGo::CsvHelper.text_to_hashes(text)
7
+ #
8
+ # @example Use specific column separator and transform to hashes
9
+ # column_separator = ','
10
+ # hashes = MoveToGo::CsvHelper.text_to_hashes(text, column_separator)
11
+ def self.text_to_hashes(text, column_separator = nil, row_separator = :auto, quote_char = '"')
12
+ if !text
13
+ raise "Missing text"
14
+ end
15
+
16
+ if !column_separator
17
+ column_separator = self.detect_col_sep text
18
+ end
19
+
20
+ rows = CSV.parse(text.strip,{:col_sep => column_separator,
21
+ :row_sep => row_separator, :quote_char => quote_char})
22
+ map = {}
23
+ first = rows.first
24
+ (0 .. first.length-1).each do |i|
25
+ map[i] = first[i]
26
+ end
27
+ rs = []
28
+ (1 .. rows.length-1).each do |i|
29
+ r={}
30
+ (0 .. map.length-1).each do |j|
31
+ r[map[j]] = rows[i][j]
32
+ end
33
+ rs.push(r)
34
+ end
35
+ return rs
36
+ end
37
+
38
+ private
39
+ def self.detect_col_sep(text)
40
+ firstline = text.split('\n').first
41
+ col_seps = [';','\t',',']
42
+ return col_seps.find do |c|
43
+ firstline.include? c
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,14 @@
1
+ require "sixarm_ruby_email_address_validation"
2
+
3
+ module MoveToGo
4
+ # The EmailHelper helps you validate email addresses.
5
+ class EmailHelper
6
+ def self.is_valid?(email)
7
+ begin
8
+ return (email =~ EmailAddressValidation::Pattern) ? true : false
9
+ rescue
10
+ return false
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,31 @@
1
+ module MoveToGo
2
+ class AlreadyAddedError < StandardError
3
+ end
4
+
5
+ class IntegrationIdIsRequiredError < StandardError
6
+ end
7
+
8
+ class InvalidCustomFieldError < StandardError
9
+ end
10
+
11
+ class InvalidRelationError < StandardError
12
+ end
13
+
14
+ class InvalidValueError < StandardError
15
+ def initalize(value)
16
+ super("#{value} is not a valid value.")
17
+ end
18
+ end
19
+
20
+ class InvalidDealStatusError < StandardError
21
+ end
22
+
23
+ class InvalidHistoryClassificationError < StandardError
24
+ def initalize(classification)
25
+ super("#{classification} is not a valid history classification")
26
+ end
27
+ end
28
+
29
+ class ObjectIsImmutableError < StandardError
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ module MoveToGo
2
+ # The ExcelHelper just makes it a little bit easier to open an
3
+ # excel file in the imports. With ExcelHelper you don't need to
4
+ # know anything about Roo and RooHelper.
5
+ class ExcelHelper
6
+ def self.Open(excel_filename)
7
+ return RooHelper.new(Roo::Excelx.new(excel_filename))
8
+ end
9
+ end
10
+ end