sf_migrate 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/README.md +2 -0
- data/bin/sf_migrate +10 -0
- data/config/credentials.yaml.example +13 -0
- data/lib/export.rb +146 -0
- data/lib/fields.rb +14 -0
- data/lib/import.rb +553 -0
- data/lib/mailer.rb +117 -0
- data/lib/sf_migrate.rb +77 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e862896e87413a3c8447dcb85efa73fea0f1c761
|
4
|
+
data.tar.gz: 4ee2a6e915659d3e257cb9f0dc13222835839439
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6bc6c9a71e565aad931468ab34c143d700a3113b084d57128dc0f608db0567a0f3915c35ab57e27db14cf25a2587486b630de28a5d500d9e2ce084119f77c187
|
7
|
+
data.tar.gz: 90b2079df5066ae955500f2ab3b2ce04effc6a84362decf2e96d60d021e847800a5c9a8db82a84145fdf46ee970144a11a604e60fd004a1995e87e467e390b0d
|
data/Gemfile
ADDED
data/README.md
ADDED
data/bin/sf_migrate
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
4
|
+
require "pathname"
|
5
|
+
bin_file = Pathname.new(__FILE__).realpath
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", bin_file)
|
8
|
+
require 'sf_migrate'
|
9
|
+
|
10
|
+
SalesforceMigration::Runner.start
|
@@ -0,0 +1,13 @@
|
|
1
|
+
sugar_url: <url>
|
2
|
+
sugar_username: <username>
|
3
|
+
sugar_password: <password>
|
4
|
+
|
5
|
+
salesforce_consumer_key: <SF_consumer_key>
|
6
|
+
salesforce_consumer_secret: <SF_consumer_secret>
|
7
|
+
salesforce_username: <SF_username>
|
8
|
+
salesforce_password: <SF_password>
|
9
|
+
|
10
|
+
db_type: mysql2
|
11
|
+
db_user: <db_user>
|
12
|
+
db_password: <db_password>
|
13
|
+
db_database: <schema_name>
|
data/lib/export.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
module SalesforceMigration
|
4
|
+
class Export
|
5
|
+
# Initilize migration export object, authenticates to SalesForce and start the export
|
6
|
+
#
|
7
|
+
# @param [Hash] options hash representing passed command line options
|
8
|
+
def initialize(options)
|
9
|
+
credentials = YAML.load_file(options[:config_file])
|
10
|
+
consumer_key = credentials['salesforce_consumer_key']
|
11
|
+
consumer_secret = credentials['salesforce_consumer_secret']
|
12
|
+
username = credentials['salesforce_username']
|
13
|
+
password = credentials['salesforce_password']
|
14
|
+
@csv_dir = options[:csv_dir]
|
15
|
+
@action = options[:action]
|
16
|
+
@logger = SalesforceMigration::Runner::create_logger
|
17
|
+
@logger.info("Export action started")
|
18
|
+
@client = Databasedotcom::Client.new :client_id => consumer_key, :client_secret => consumer_secret
|
19
|
+
@client.authenticate :username => username, :password => password
|
20
|
+
|
21
|
+
@logger.info("Authentication to SalesForce successfull")
|
22
|
+
start
|
23
|
+
@logger.info("Export action ended successfully")
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def start
|
28
|
+
%w(ISOs__c Agent__c Account Payment_Methods__c Banks__c MerchantToAPM__c ccrmbasic__Email__c Email_Association__c).each do |type|
|
29
|
+
@logger.info "Writing CSV for #{type}"
|
30
|
+
write_to_csv type
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Generate and save CSV file for given type
|
35
|
+
#
|
36
|
+
# @param [String] type export type name
|
37
|
+
def write_to_csv(type)
|
38
|
+
fields = return_fields(type)
|
39
|
+
records = get_records(type)
|
40
|
+
file_name = generate_name(type)
|
41
|
+
|
42
|
+
CSV.open(file_name, "wb:UTF-8") do |file|
|
43
|
+
@logger.info "Opened #{file_name} for export"
|
44
|
+
file << fields
|
45
|
+
records.each do |record|
|
46
|
+
arr = []
|
47
|
+
fields.each do |field|
|
48
|
+
arr << record.send(field)
|
49
|
+
arr.map!(&method(:remove_quotes))
|
50
|
+
end
|
51
|
+
file << arr
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# In order to fix the Invalid Session Id in SugarCRM we need to remove all
|
57
|
+
# quotes from text fields, because they mess up the JSON object which comunicate with
|
58
|
+
# our SugarCRM instance.
|
59
|
+
# Note that on Mac we don`t need this method.
|
60
|
+
def remove_quotes(field)
|
61
|
+
field.gsub(/'/, "").strip if field.is_a? String
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Return the header fields
|
66
|
+
def return_fields(type)
|
67
|
+
return constantize "SalesforceMigration::Fields::#{type.slice(0..-4).upcase}_FIELDS" if type.end_with?("__c")
|
68
|
+
return constantize "SalesforceMigration::Fields::#{type.upcase}_FIELDS"
|
69
|
+
end
|
70
|
+
|
71
|
+
# Get all records for specific type of object
|
72
|
+
#
|
73
|
+
# @param [String] type export type name
|
74
|
+
#
|
75
|
+
# @return [Databasedotcom::Collection] the requested records
|
76
|
+
def get_records(type)
|
77
|
+
if @action == 'initial_run'
|
78
|
+
@logger.info "Getting all records from SalesForce for #{type}"
|
79
|
+
records = get_all_sobjects(type)
|
80
|
+
else
|
81
|
+
@logger.info "Getting records for yesterday from SalesForce for #{type}"
|
82
|
+
records = @client.materialize(type)
|
83
|
+
|
84
|
+
datetime = DateTime.now
|
85
|
+
datetime = datetime -= 1
|
86
|
+
records.query("lastmodifieddate >= #{datetime}")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Generates a name for CSV file depending on the action
|
91
|
+
#
|
92
|
+
# @param [String] type export type name
|
93
|
+
#
|
94
|
+
# @return [String] generated filename
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
# @action = 'update'
|
98
|
+
# @csv_dir = '/tmp'
|
99
|
+
# generate_name('Account') #=> '/tmp/update/2012-07-07/Account_export.csv'
|
100
|
+
def generate_name(type)
|
101
|
+
if @action == 'initial_run'
|
102
|
+
FileUtils.mkdir_p("#{@csv_dir}/initial/") unless Dir.exists? "#{@csv_dir}/initial/"
|
103
|
+
"#{@csv_dir}/initial/#{type}_export.csv"
|
104
|
+
else
|
105
|
+
today = lambda { Date.today.to_s }
|
106
|
+
dir = "#{@csv_dir}/update/#{today.call}"
|
107
|
+
FileUtils.mkdir_p(dir) unless Dir.exists? dir
|
108
|
+
"#{dir}/#{type}_export.csv"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Borrowed from activesupport/lib/active_support/inflector/methods.rb, line 212
|
113
|
+
def constantize(camel_cased_word)
|
114
|
+
names = camel_cased_word.split('::')
|
115
|
+
names.shift if names.empty? || names.first.empty?
|
116
|
+
constant = Object
|
117
|
+
names.each do |name|
|
118
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
119
|
+
end
|
120
|
+
constant
|
121
|
+
end
|
122
|
+
|
123
|
+
# Get all objects of given type. Databasedotcom pulls only 250 records by query
|
124
|
+
#
|
125
|
+
# @param [String] type type of sobject
|
126
|
+
#
|
127
|
+
# @return [Array<Databasedotcom::Sobject::Sobject>] All available sobjects
|
128
|
+
# Some objects, like Merchants and Emails are exported VIA a certain criteria
|
129
|
+
def get_all_sobjects(type)
|
130
|
+
case type
|
131
|
+
when 'Account'
|
132
|
+
records = @client.materialize(type).query("Agents__c != ''")
|
133
|
+
when 'ccrmbasic__Email__c'
|
134
|
+
records = @client.materialize(type).query("ccrmbasic__Contact__c != ''")
|
135
|
+
else
|
136
|
+
records = @client.materialize(type).all
|
137
|
+
end
|
138
|
+
sobjects = records.dup.to_a
|
139
|
+
while records.next_page?
|
140
|
+
sobjects += records.next_page
|
141
|
+
records = records.next_page
|
142
|
+
end
|
143
|
+
sobjects
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/fields.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module SalesforceMigration
|
2
|
+
class Fields
|
3
|
+
# Salesforce objects and the fields for import
|
4
|
+
ISOS_FIELDS = %w{Active__c Address__c Adult_Chargeback_Fee__c Adult_Commission__c Adult_Transaction_Fee__c Agreement_Received__c Background_Check_Complete__c Business_Phone_Number__c Cell_Phone_Number__c Comments__c CreatedBy CreatedById CreatedDate Curren__c CurrencyIsoCode Email_Address__c Fax_Number__c Gambling_Chargeback_Fee__c Gambling_Commission_Fee__c Gambling_Transaction_Fee__c General_Conventional_Chargeback_Fee__c General_Conventional_Commission_Fee__c General_Conventional_Transaction_Fee__c General_Non_Conventional_Chargeback_Fee__c General_Non_Conventional_Commission_Fee__c General_Non_Conventional_Transaction_Fee__c ISO_ID_Assigned__c ISO_ID_Number__c ISO_Owner_Name__c Id KYC_Gathered__c LastActivityDate LastModifiedBy LastModifiedById LastModifiedDate Name New_Hire_Package_Received__c Owner OwnerId Pharmacy_Chargeback_Fee__c Pharmacy_Commission_Fee__c Pharmacy_Transaction_Fee__c Projected_Deals_Count__c Recruiter__c Region__c System_Access_Granted__c Training_Completed__c Welcome_Call_Completed__c Welcome_Package_Sent__c eMerchantPay_ISO_ID__c}
|
5
|
+
AGENT_FIELDS = %w{Id Name LastActivityDate CreatedBy CreatedDate CreatedById LastModifiedDate LastModifiedById LastModifiedBy Owner OwnerId Agent_Billing_Address__c Agent_Cell_Phone__c Agent_Id__c Agent_Phone__c Agent_Skype__c Agreement_Received__c Agreement_Sent__c Background_Check_Complete__c Business_Phone_Number__c Comments__c Commission_Fee__c Email_Address__c eMerchantPay_Agent_ID__c Fee_Comments__c ISO_Company__c New_Hire_Package_Received__c One_Time_Commission_Currency__c Recruiter__c Region__c Split_percentage__c System_Access_Granted__c Title__c Transaction_Fee__c}
|
6
|
+
ACCOUNT_FIELDS = %w{Additional_Url__c Agents__c AnnualRevenue Approval_Citeria__c Approve_1__c Approve_2__c Approve_3__c BillingCity BillingCountry BillingPostalCode BillingState BillingStreet City__c Comment__c CreatedBy CreatedById CreatedDate Credit_Card__c Curren__c CurrencyIsoCode Current_Volume__c Description Descriptor__c FD_Merchant_Number__c Fax ISO_Name__c Id Industry Info_Capture__c Integration__c Iovation__c IsPartner Jigsaw LastModifiedBy LastModifiedById LastModifiedDate Merchant_Email__c Merchant_Type__c Name NumberOfEmployees Overlying_Company__c Owner OwnerId Phone Projected_Monthly_Volume__c Recruiter__c Secondary_FD_Merchant_Number__c ShippingCity ShippingCountry ShippingPostalCode ShippingState ShippingStreet Status_Comments__c Status__c Threat_Metrix__c Type__c Url__c VBV_MC3D__c Vacation1__c Website}
|
7
|
+
PAYMENT_METHODS_FIELDS = %w{Accounts__c Business_Contact__c Business_Type_Coments__c Business_type__c Buy_Rates__c Chargeback_Comments__c Chargeback__c Client_Integration__c Countries2__c Countries__c CreatedBy CreatedById CreatedDate CurrencyIsoCode Id Integration__c LastModifiedBy LastModifiedById LastModifiedDate Name Our_Buy_Rates__c Owner OwnerId Proccessing_Currency__c Processing_Currency__c Rebilling_Comments__c Rebilling__c Refund_Comments__c Refund__c Release_Date__c Settlement_Currency__c Settlement_Cycle__c Settlement__c Tech_Contact__c Type__c V_terminal_Comments__c V_terminal__c}
|
8
|
+
BANKS_FIELDS = %w{Account_Number__c BIC_Code__c Merchant_2__c Bank_Address__c Bank_Name__c Contract__c CreatedBy CreatedById CreatedDate CurrencyIsoCode Holder_Address__c IBAN__c Id LastActivityDate LastModifiedBy LastModifiedById LastModifiedDate Name Owner OwnerId Processing_Currency__c Routing_Number__c SWIFT__c Settlement_Currency__c}
|
9
|
+
MERCHANTTOAPM_FIELDS = %w{Merchant__c Payment_Methods__c}
|
10
|
+
CCRMBASIC__EMAIL_FIELDS = %w{ccrmbasic__To__c ccrmbasic__Cc__c ccrmbasic__Body__c Id Name}
|
11
|
+
EMAIL_ASSOCIATION_FIELDS= %w{Merchant_Name__c Email__c}
|
12
|
+
SYSTEM_FIELDS = %w{id owner ownerid createddate createdby createdbyid lastactivitydate lastmodifieddate lastmodifiedby lastmodifiedbyid recruiter region}
|
13
|
+
end
|
14
|
+
end
|
data/lib/import.rb
ADDED
@@ -0,0 +1,553 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
module SalesforceMigration
|
4
|
+
# Workflow for import of specific object
|
5
|
+
#
|
6
|
+
# import_agents -> load_file_for_import -> transform_csv_file -> prefix_sf_attribute_names
|
7
|
+
# -> transform_agents
|
8
|
+
# -> populate_sugar -> get_sugarcrm_module_type
|
9
|
+
# -> convert_string_to_datetime
|
10
|
+
# -> create_association -> find_sugarcrm_object
|
11
|
+
# -> create_user
|
12
|
+
class Import
|
13
|
+
|
14
|
+
# Initialize migration import object and start the import
|
15
|
+
#
|
16
|
+
# @param [Hash] options hash representing passed command line options
|
17
|
+
def initialize(options)
|
18
|
+
credentials = YAML.load_file(options[:config_file])
|
19
|
+
url = credentials['sugar_url']
|
20
|
+
username = credentials['sugar_username']
|
21
|
+
password = credentials['sugar_password']
|
22
|
+
@csv_dir = options[:csv_dir]
|
23
|
+
SugarCRM.connect(url, username, password)
|
24
|
+
@action = options[:action]
|
25
|
+
@isos, @agents, @merchants, @bank_accounts, @agent_users, @iso_users, @emails = [], [], [], [], [], [], []
|
26
|
+
@payment_to_merchants, @emails_to_merchants = [], []
|
27
|
+
@logger = SalesforceMigration::Runner::create_logger
|
28
|
+
@logger.info("Import action started")
|
29
|
+
start
|
30
|
+
@logger.info("Import action ended successfully")
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def start
|
36
|
+
import_emails
|
37
|
+
import_payment_methods
|
38
|
+
import_isos
|
39
|
+
import_agents
|
40
|
+
import_merchants
|
41
|
+
import_settlement_bank_accounts
|
42
|
+
|
43
|
+
associate_records_to_groups
|
44
|
+
end
|
45
|
+
|
46
|
+
# Import methods. They load the csv file, for the given type
|
47
|
+
# get rid of unnecessary information, transforms other fields, so
|
48
|
+
# they can match the one in SugarCRM and calls for the populate_sugar method
|
49
|
+
# which start the actual import. Keep in mind, that the order of the imports is important
|
50
|
+
def import_isos
|
51
|
+
records = load_file_for_import 'ISOs__c'
|
52
|
+
records = transform_isos(records)
|
53
|
+
populate_sugar(records, "iso")
|
54
|
+
end
|
55
|
+
|
56
|
+
def import_agents
|
57
|
+
records = load_file_for_import 'Agent__c'
|
58
|
+
records = transform_agents(records)
|
59
|
+
populate_sugar(records, "agent")
|
60
|
+
end
|
61
|
+
|
62
|
+
def import_merchants
|
63
|
+
records = load_file_for_import 'Account'
|
64
|
+
records = transform_merchants(records)
|
65
|
+
populate_sugar(records, "merchant")
|
66
|
+
end
|
67
|
+
|
68
|
+
def import_settlement_bank_accounts
|
69
|
+
records = load_file_for_import 'Banks__c'
|
70
|
+
records = transform_settlement_bank_accounts(records)
|
71
|
+
populate_sugar(records, "settlement_bank_account")
|
72
|
+
end
|
73
|
+
|
74
|
+
def import_payment_methods
|
75
|
+
records = load_file_for_import 'Payment_Methods__c'
|
76
|
+
junction_records = load_file_for_import 'MerchantToAPM__c'
|
77
|
+
# We don`t need db table to save the many-to-many associations between Merchant and Payment Method,
|
78
|
+
# so we just store them in an array and use it later on
|
79
|
+
junction_records.each do |jrecord|
|
80
|
+
@payment_to_merchants << jrecord
|
81
|
+
end
|
82
|
+
populate_sugar(records, "payment_method")
|
83
|
+
end
|
84
|
+
|
85
|
+
def import_emails
|
86
|
+
records = load_file_for_import 'ccrmbasic__Email__c'
|
87
|
+
records = transform_emails(records)
|
88
|
+
junction_records = load_file_for_import 'Email_Association__c'
|
89
|
+
# We don`t need db table to save the many-to-many associations between Merchant and Payment Method,
|
90
|
+
# so we just store them in an array and use it later on
|
91
|
+
junction_records.each do |jrecord|
|
92
|
+
@emails_to_merchants << jrecord
|
93
|
+
end
|
94
|
+
populate_sugar(records, "email")
|
95
|
+
end
|
96
|
+
|
97
|
+
# Load CSV for import
|
98
|
+
#
|
99
|
+
# @param [String] module_name name of the module
|
100
|
+
#
|
101
|
+
# @return [Array] parsed CSV file
|
102
|
+
def load_file_for_import(module_name)
|
103
|
+
if @action == 'initial_run'
|
104
|
+
filename = "#{@csv_dir}/initial/#{module_name}_export.csv"
|
105
|
+
else
|
106
|
+
today = lambda { Date.today.to_s }
|
107
|
+
dir = "#{@csv_dir}/update/#{today.call}"
|
108
|
+
filename = "#{dir}/#{module_name}_export.csv"
|
109
|
+
end
|
110
|
+
@logger.error("Could not create or find a csv filename for module #{module_name}") unless defined? filename
|
111
|
+
@logger.info("Loading CSV file #{filename} for import")
|
112
|
+
csv_file = ::CSV.read(filename, :encoding => 'utf-8')
|
113
|
+
transform_csv_file(csv_file)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Load CSV file, removes headers and create a hash with the headers as keys
|
117
|
+
#
|
118
|
+
# @param [Array] file parsed CSV file
|
119
|
+
#
|
120
|
+
# @return [Array] transformed CSV file
|
121
|
+
def transform_csv_file(csv_file)
|
122
|
+
@logger.info("Transforming CSV file")
|
123
|
+
transformed = []
|
124
|
+
headers = csv_file.shift
|
125
|
+
headers.map!(&method(:prepare_custom_headers))
|
126
|
+
|
127
|
+
csv_file.each do |row|
|
128
|
+
transformed << Hash[headers.zip row]
|
129
|
+
end
|
130
|
+
prefix_sf_attribute_names transformed
|
131
|
+
end
|
132
|
+
|
133
|
+
#Remove the __c and lowercase the custom header fields, exported from Salesforce.
|
134
|
+
#
|
135
|
+
# @param [String] header
|
136
|
+
def prepare_custom_headers(header)
|
137
|
+
header.end_with?("__c") ? header.slice(0..-4).downcase : header.downcase
|
138
|
+
end
|
139
|
+
|
140
|
+
# Add sf_ prefix to all auto-generated attribute names from Salesforce
|
141
|
+
#
|
142
|
+
# @param [Array<SugarCRM::Namespace::Object>] records records to be prefixed
|
143
|
+
#
|
144
|
+
# @return [Array<SugarCRM::Namespace::Object>] returns the records
|
145
|
+
def prefix_sf_attribute_names(records)
|
146
|
+
sf_attribute_names = SalesforceMigration::Fields::SYSTEM_FIELDS
|
147
|
+
records.each do |r|
|
148
|
+
sf_attribute_names.each do |field|
|
149
|
+
r["sf_#{field.downcase}"] = r[field]
|
150
|
+
r.delete(field)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
records
|
154
|
+
end
|
155
|
+
|
156
|
+
def transform_isos(records)
|
157
|
+
@logger.info("Transforming ISO fields")
|
158
|
+
records.each do |record|
|
159
|
+
record['general_c_chargeback_fee'] = record['general_conventional_chargeback_fee']
|
160
|
+
record['general_c_commission_fee'] = record['general_conventional_commission_fee']
|
161
|
+
record['general_c_transaction_fee'] = record['general_conventional_transaction_fee']
|
162
|
+
record['general_nc_chargeback_fee'] = record['general_non_conventional_chargeback_fee']
|
163
|
+
record['general_nc_commission_fee'] = record['general_non_conventional_commission_fee']
|
164
|
+
record['general_nc_transaction_fee'] = record['general_non_conventional_transaction_fee']
|
165
|
+
record.delete 'general_conventional_chargeback_fee'
|
166
|
+
record.delete 'general_conventional_commission_fee'
|
167
|
+
record.delete 'general_conventional_transaction_fee'
|
168
|
+
record.delete 'general_non_conventional_chargeback_fee'
|
169
|
+
record.delete 'general_non_conventional_commission_fee'
|
170
|
+
record.delete 'general_non_conventional_transaction_fee'
|
171
|
+
end
|
172
|
+
records
|
173
|
+
end
|
174
|
+
|
175
|
+
def transform_agents(records)
|
176
|
+
@logger.info("Transforming fields")
|
177
|
+
records.each do |record|
|
178
|
+
record['sf_iso'] = record['iso_company']
|
179
|
+
record.delete 'iso_company'
|
180
|
+
end
|
181
|
+
records
|
182
|
+
end
|
183
|
+
|
184
|
+
def transform_merchants(records)
|
185
|
+
@logger.info("Transforming Merchant fields")
|
186
|
+
records.each do |record|
|
187
|
+
record['sf_agent'] = record['agents']
|
188
|
+
record['url'] = record['url'].to_s.gsub(/<[^>]*>|^[\n\r]*/, '')
|
189
|
+
record['additional_url'] = record['additional_url'].to_s.gsub(/(<[^>]*>|^[\n\r]*)/, '')
|
190
|
+
record.delete 'agents'
|
191
|
+
record.delete 'sf_lastactivitydate'
|
192
|
+
record.delete 'sf_lastmodifieddate'
|
193
|
+
record.delete 'sf_region'
|
194
|
+
end
|
195
|
+
records
|
196
|
+
end
|
197
|
+
|
198
|
+
def transform_settlement_bank_accounts(records)
|
199
|
+
@logger.info("Transforming Settlement Bank Account fields")
|
200
|
+
records.each do |record|
|
201
|
+
record['sf_iso'] = record['iso']
|
202
|
+
record['sf_contract'] = record['contract']
|
203
|
+
record['sf_merchant'] = record['merchant_2']
|
204
|
+
record.delete 'merchant_2'
|
205
|
+
record.delete 'iso'
|
206
|
+
record.delete 'contract'
|
207
|
+
record.delete 'sf_recruiter'
|
208
|
+
record.delete 'sf_region'
|
209
|
+
end
|
210
|
+
records
|
211
|
+
end
|
212
|
+
|
213
|
+
def transform_emails(records)
|
214
|
+
@logger.info("Transforming Email fields")
|
215
|
+
records.each do |record|
|
216
|
+
record['receiver'] = record['ccrmbasic__to']
|
217
|
+
record['cc'] = record['ccrmbasic__cc']
|
218
|
+
record['body'] = convert_characters(record['ccrmbasic__body']) unless record['ccrmbasic__body'].nil?
|
219
|
+
|
220
|
+
record.delete 'ccrmbasic__to'
|
221
|
+
record.delete 'ccrmbasic__cc'
|
222
|
+
record.delete 'ccrmbasic__body'
|
223
|
+
end
|
224
|
+
records
|
225
|
+
end
|
226
|
+
|
227
|
+
# Convert all string datetime attributes to DateTime objects
|
228
|
+
#
|
229
|
+
# @param [SugarCRM::Namespace::Object] record the record which attributes must be converted
|
230
|
+
#
|
231
|
+
# @return [SugarCRM::Namespace::Object] the record
|
232
|
+
def convert_string_to_datetime(record)
|
233
|
+
record['sf_lastmodifieddate'] = record['sf_lastmodifieddate'].to_datetime if record['sf_lastmodifieddate']
|
234
|
+
record['sf_createddate'] = record['sf_createddate'].to_datetime if record['sf_createddate']
|
235
|
+
record['sf_lastactivitydate'] = record['sf_lastactivitydate'].to_date if record['sf_lastactivitydate']
|
236
|
+
record
|
237
|
+
end
|
238
|
+
|
239
|
+
def convert_characters(string)
|
240
|
+
string.gsub!(/\'/, ''')
|
241
|
+
string.gsub!(/'/, '')
|
242
|
+
string.gsub!(/"/, '')
|
243
|
+
string.gsub!(/\"/, '"')
|
244
|
+
string
|
245
|
+
end
|
246
|
+
|
247
|
+
# Populate SugarCRM with records
|
248
|
+
# If it's initial run, it will create all records from the CSV file
|
249
|
+
# If it's update, it will update existing records and create new if necessary
|
250
|
+
#
|
251
|
+
# @param [Array] records records to be inserted in SugarCRM
|
252
|
+
# @param [String] type type of the object
|
253
|
+
def populate_sugar(records, type)
|
254
|
+
module_type = get_sugarcrm_module_type(type)
|
255
|
+
case @action
|
256
|
+
when 'initial_run'
|
257
|
+
@logger.info("Creating new records for #{type} type")
|
258
|
+
records.each do |record|
|
259
|
+
create_sugar_record(module_type, record, type)
|
260
|
+
end
|
261
|
+
when 'update'
|
262
|
+
records.each do |record|
|
263
|
+
record = convert_string_to_datetime(record)
|
264
|
+
existing_record = find_sugarcrm_object(type, 'sf_id', record['sf_id'])
|
265
|
+
existing_record = existing_record.first if existing_record.is_a?(Array)
|
266
|
+
if existing_record
|
267
|
+
#TODO Nil values are not handled properly by SugarCRM in update_attributes, so we must transform them into blank values
|
268
|
+
#remove this loop and use the main one!!
|
269
|
+
record.each do |key, val|
|
270
|
+
record[key] = "" if val.nil?
|
271
|
+
end
|
272
|
+
@logger.info("Updating record for #{type} #{record['name']}")
|
273
|
+
existing_record.update_attributes!(record)
|
274
|
+
else
|
275
|
+
@logger.info("Creating new record for #{type} #{record['name']}")
|
276
|
+
create_sugar_record(module_type, record, type)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
# Create the actual records and users in SugarCRM. Populates the var_pool
|
283
|
+
def create_sugar_record(module_type, record, type)
|
284
|
+
record = convert_string_to_datetime(record)
|
285
|
+
|
286
|
+
obj = module_type.new(record)
|
287
|
+
obj.save!
|
288
|
+
obj = create_association(obj, type) unless %(email payment_method).include? type
|
289
|
+
create_security_group_iso obj if type == 'iso'
|
290
|
+
|
291
|
+
create_user(obj, type) if %(iso agent).include? type
|
292
|
+
populate_var_pool(obj, type)
|
293
|
+
end
|
294
|
+
|
295
|
+
# Populates variables with SugarCRM objects.
|
296
|
+
# We use them later on, when associating objects with Security Groups
|
297
|
+
# Actually we don`t use @bank_accounts & @emails for now, but it`s probably a good idea to store the objects
|
298
|
+
# @param [SugarCRM::Namespace::Object] obj object for which a user will be created
|
299
|
+
# @param [String] type type of the object
|
300
|
+
def populate_var_pool(obj, type)
|
301
|
+
case type
|
302
|
+
when 'merchant'
|
303
|
+
@merchants << obj
|
304
|
+
when 'settlement_bank_account'
|
305
|
+
@bank_accounts << obj
|
306
|
+
when 'iso'
|
307
|
+
@isos << obj
|
308
|
+
when 'agent'
|
309
|
+
@agents << obj
|
310
|
+
when 'email'
|
311
|
+
@emails << obj
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# Create association for agent, merchant, settlement bank Account, Email, Payment Method
|
316
|
+
# If it is agent, it will find the ISO by id and create the association
|
317
|
+
# If it is merchant, it will find the Agent, Payment Method, User and create the associations
|
318
|
+
# If it is Settlement Bank Account it will find the Merchant and create the associations
|
319
|
+
# @param [SugarCRM::Namespace::Object] obj the object for which an association will be created
|
320
|
+
# @param [String] type type of the object
|
321
|
+
#
|
322
|
+
# @return [SugarCRM::Namespace::Object] the object
|
323
|
+
def create_association(obj, type)
|
324
|
+
@logger.info("Creating association for #{type} #{obj.name}")
|
325
|
+
case type
|
326
|
+
when "agent"
|
327
|
+
iso = find_sugarcrm_object('iso', 'sf_id', obj.sf_iso)
|
328
|
+
obj.associate! iso if iso
|
329
|
+
when "merchant"
|
330
|
+
|
331
|
+
payment_method_id = find_payment_method_id(obj.sf_id)
|
332
|
+
if payment_method_id
|
333
|
+
payment_method = find_sugarcrm_object('payment_method', 'sf_id', payment_method_id)
|
334
|
+
obj.associate! payment_method
|
335
|
+
end
|
336
|
+
|
337
|
+
email_id = find_email_id(obj.sf_id)
|
338
|
+
if email_id
|
339
|
+
email = find_sugarcrm_object('email', 'sf_id', email_id)
|
340
|
+
obj.associate! email
|
341
|
+
end
|
342
|
+
|
343
|
+
agent = find_sugarcrm_object('agent', 'sf_id', obj.sf_agent)
|
344
|
+
if agent
|
345
|
+
obj.associate! agent
|
346
|
+
obj.assigned_user_id = agent.assigned_user_id
|
347
|
+
end
|
348
|
+
|
349
|
+
when "settlement_bank_account"
|
350
|
+
merchant = find_sugarcrm_object('merchant', 'sf_id', obj.sf_merchant)
|
351
|
+
obj.associate! merchant if merchant
|
352
|
+
end
|
353
|
+
obj
|
354
|
+
end
|
355
|
+
|
356
|
+
# Create user associated with SugarCRM object
|
357
|
+
# Default email: mail@example.com, default password: 123456
|
358
|
+
#
|
359
|
+
# @param [SugarCRM::Namespace::Object] obj object for which a user will be created
|
360
|
+
# @param [String] type type of the object
|
361
|
+
def create_user(obj, type)
|
362
|
+
@logger.info("Creating user for #{type} #{obj.name}")
|
363
|
+
user = SugarCRM::User.new
|
364
|
+
user.user_name = (type == 'agent') ? obj.emerchantpay_agent_id : obj.emerchantpay_iso_id
|
365
|
+
user.user_name ||= "EMP"
|
366
|
+
user.last_name = obj.name
|
367
|
+
user.type_c = type
|
368
|
+
#user.email1 = obj.email_address || "mail@example.com"
|
369
|
+
user.email1 = 'stefan@emerchantpay.com'
|
370
|
+
user.status = 'Inactive'
|
371
|
+
user.system_generated_password = false
|
372
|
+
user.save!
|
373
|
+
obj.assigned_user_id = user.id
|
374
|
+
obj.save!
|
375
|
+
|
376
|
+
populate_user_pool(user, type)
|
377
|
+
end
|
378
|
+
|
379
|
+
# Populates Users as SugarCRM objects.
|
380
|
+
# We use them later on, when associating objects with Security Groups
|
381
|
+
# @param [SugarCRM::Namespace::Object] Already created user object
|
382
|
+
# @param [String] type type of the object
|
383
|
+
def populate_user_pool(user, type)
|
384
|
+
case type
|
385
|
+
when 'iso'
|
386
|
+
@iso_users << user
|
387
|
+
when 'agent'
|
388
|
+
@agent_users << user
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# Find records(payment methods, emails) in the junction object arrays, given the merchant_id
|
393
|
+
# Both payment methods and emails have a many-to-many relationship with the merchant in Salesforce
|
394
|
+
def find_payment_method_id(merchant_id)
|
395
|
+
@payment_to_merchants.each do |record|
|
396
|
+
return record['payment_methods'] if record['merchant'] == merchant_id.to_s
|
397
|
+
end
|
398
|
+
false
|
399
|
+
end
|
400
|
+
|
401
|
+
def find_email_id(merchant_id)
|
402
|
+
@emails_to_merchants.each do |record|
|
403
|
+
return record['email'] if record['merchant_name'] == merchant_id.to_s
|
404
|
+
end
|
405
|
+
false
|
406
|
+
end
|
407
|
+
|
408
|
+
#Creates the Security Group object in SugarCRM
|
409
|
+
# @param [SugarCRM::Namespace::EmpIso] Iso object
|
410
|
+
def create_security_group_iso(iso)
|
411
|
+
@logger.info("Creating SecurityGroup #{iso.name}")
|
412
|
+
sg = SugarCRM::SecurityGroup.new(:name => iso.name) unless find_sugarcrm_object('security_group','name', iso.name)
|
413
|
+
sg.save! if sg
|
414
|
+
end
|
415
|
+
|
416
|
+
# Assign all records, that need to be in a Security Group, to the Group
|
417
|
+
def associate_records_to_groups
|
418
|
+
put_isos_into_iso_group
|
419
|
+
put_agents_into_iso_group
|
420
|
+
put_merchants_into_iso_group
|
421
|
+
end
|
422
|
+
|
423
|
+
def put_isos_into_iso_group
|
424
|
+
if @isos
|
425
|
+
@logger.info("Puting ISOs into ISO groups")
|
426
|
+
role = SugarCRM::ACLRole.find_by_name("isos")
|
427
|
+
@isos.each do |iso|
|
428
|
+
sg = find_sugarcrm_object('security_group','name', iso.name)
|
429
|
+
user = SugarCRM::User.find_by_last_name(iso.name)
|
430
|
+
iso.associate! sg
|
431
|
+
user.associate! sg
|
432
|
+
role.associate! sg
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
def put_agents_into_iso_group
|
438
|
+
if @agents
|
439
|
+
@logger.info("Putting agent records, agent users and agent role into ISO groups")
|
440
|
+
@agents.each do |agent|
|
441
|
+
sg = find_sugarcrm_object('security_group','name', agent.emp_iso.first.name) unless agent.emp_iso.empty?
|
442
|
+
role = SugarCRM::ACLRole.find_by_name('agents')
|
443
|
+
if sg
|
444
|
+
user = SugarCRM::User.find_by_last_name(agent.name)
|
445
|
+
@logger.info("Puting Agent #{agent.name} in Security Group #{sg.name}")
|
446
|
+
agent.associate! sg
|
447
|
+
user.associate! sg
|
448
|
+
role.associate! sg
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
# Bank accounts, Emails and Payment Methods must be inserted from this method, not separately,
|
455
|
+
# because we need to use the merchant object loop, which provides us with the ready merchant id, with which
|
456
|
+
# we can check if a merchant has one or more bank acounts, emails, pm, etc.. Otherwise we have to
|
457
|
+
# make a separate merchant select in every other method.
|
458
|
+
def put_merchants_into_iso_group
|
459
|
+
if @merchants
|
460
|
+
@logger.info("Puting merchants into ISO groups")
|
461
|
+
@merchants.each do |merchant|
|
462
|
+
unless (merchant.emp_agent.empty? || merchant.emp_agent.first.emp_iso.empty?)
|
463
|
+
sg = find_sugarcrm_object('security_group','name', merchant.emp_agent.first.emp_iso.first.name)
|
464
|
+
@logger.info("Puting merchant #{merchant.name} into ISO group")
|
465
|
+
|
466
|
+
if sg
|
467
|
+
merchant.associate! sg
|
468
|
+
put_email_objects_into_iso_group(sg, merchant.sf_id)
|
469
|
+
put_payment_methods_objects_into_iso_group(sg, merchant.sf_id)
|
470
|
+
end
|
471
|
+
|
472
|
+
bank = find_sugarcrm_object('settlement_bank_account', 'sf_merchant', merchant.sf_id)
|
473
|
+
if (bank)
|
474
|
+
@logger.info("Puting Bank Account for #{merchant.name} into ISO group")
|
475
|
+
put_bank_accounts_into_iso_group(bank, sg)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
def put_bank_accounts_into_iso_group(banks, sg)
|
483
|
+
if banks.is_a?(Array)
|
484
|
+
banks.each do |bank|
|
485
|
+
bank.associate! sg
|
486
|
+
end
|
487
|
+
else
|
488
|
+
banks.associate! sg
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
def put_email_objects_into_iso_group(sg, merchant_id)
|
493
|
+
@logger.info("Puting Emails into ISO group")
|
494
|
+
email_id = find_email_id(merchant_id)
|
495
|
+
if email_id
|
496
|
+
email = find_sugarcrm_object('email', 'sf_id', email_id)
|
497
|
+
if email
|
498
|
+
if email.is_a?(Array)
|
499
|
+
email.each do |e|
|
500
|
+
e.associate! sg
|
501
|
+
end
|
502
|
+
else
|
503
|
+
email.associate! sg
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
def put_payment_methods_objects_into_iso_group(sg, merchant_id)
|
510
|
+
@logger.info("Puting Payment Methods into ISO group")
|
511
|
+
payment_method_id = find_payment_method_id(merchant_id)
|
512
|
+
if payment_method_id
|
513
|
+
payment_method = find_sugarcrm_object('payment_method', 'sf_id', payment_method_id)
|
514
|
+
if payment_method
|
515
|
+
if payment_method.is_a?(Array)
|
516
|
+
payment_method.each do |pm|
|
517
|
+
pm.associate! sg
|
518
|
+
end
|
519
|
+
else
|
520
|
+
payment_method.associate! sg
|
521
|
+
end
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
# Returns the SugarCRM module namespace
|
527
|
+
# @param [String] type type of the module object
|
528
|
+
def get_sugarcrm_module_type(type)
|
529
|
+
modules = {
|
530
|
+
"iso" => SugarCRM::EmpIso,
|
531
|
+
"agent" => SugarCRM::EmpAgent,
|
532
|
+
"merchant" => SugarCRM::EmpMerchant,
|
533
|
+
"payment_method" => SugarCRM::EmpPaymentmethod,
|
534
|
+
"settlement_bank_account" => SugarCRM::EmpSettlementBankAccount,
|
535
|
+
"security_group" => SugarCRM::SecurityGroup,
|
536
|
+
"email" => SugarCRM::EmpEmail
|
537
|
+
}
|
538
|
+
modules[type]
|
539
|
+
end
|
540
|
+
|
541
|
+
# Find a SugarCRM object
|
542
|
+
#
|
543
|
+
# @param [String] type type of the module object
|
544
|
+
# @param [String] attribute name of the attribute to search by
|
545
|
+
# @param [String] search_string string used in WHERE clause
|
546
|
+
# find_sugarcrm_object('emp_ISO', 'sf_id', 'a073000000SSTEYAA5') # => #<SugarCRM::Namespace0::EmpIso ... >
|
547
|
+
def find_sugarcrm_object(type, attribute, search_string)
|
548
|
+
module_type = get_sugarcrm_module_type(type)._module.name
|
549
|
+
SugarCRM.connection.get_entry_list(module_type, "#{module_type.downcase}.#{attribute} = '#{search_string}'")
|
550
|
+
end
|
551
|
+
|
552
|
+
end
|
553
|
+
end
|
data/lib/mailer.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
module SalesforceMigration
|
4
|
+
|
5
|
+
class Mailer
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@@config = YAML.load_file(options[:config_file])
|
9
|
+
@logger = SalesforceMigration::Runner::create_logger
|
10
|
+
|
11
|
+
# Ugly way to fix the bug with user_hash update
|
12
|
+
# We set up a connection and update it manually.update_attributes does not work.
|
13
|
+
# The issue is forwarded to sugarcrm gem crew
|
14
|
+
ActiveRecord::Base.establish_connection(
|
15
|
+
:adapter => @@config['db_type'],
|
16
|
+
:host => "localhost",
|
17
|
+
:username => @@config['db_user'],
|
18
|
+
:password => @@config['db_password'],
|
19
|
+
:database => @@config['db_database']
|
20
|
+
)
|
21
|
+
|
22
|
+
@logger.info("Starting the mailer")
|
23
|
+
start
|
24
|
+
@logger.info("Mailer finished")
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
#Search the agent portal database for all users, who are inactive
|
30
|
+
#This is the script, that activates them
|
31
|
+
def start
|
32
|
+
inactive_users = SugarCRM::User.find_all_by_status('Inactive')
|
33
|
+
|
34
|
+
if inactive_users
|
35
|
+
inactive_users.each do |user|
|
36
|
+
@logger.info("Sending email to #{user.last_name}")
|
37
|
+
|
38
|
+
plain_password = generate_password
|
39
|
+
hash_password = Digest::MD5.hexdigest plain_password
|
40
|
+
|
41
|
+
sm = send_mail(user.email1, user.user_name, plain_password)
|
42
|
+
if sm
|
43
|
+
query = "UPDATE users SET user_hash='#{hash_password}', status='Active' WHERE id='#{user.id}'"
|
44
|
+
ActiveRecord::Base.connection.execute(query);
|
45
|
+
|
46
|
+
@logger.info("Updated user #{user.last_name} status to active")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
#Send the welcoming email to the user
|
53
|
+
#We need the welcoming text
|
54
|
+
#@param [String] the email address
|
55
|
+
def send_mail(email, username, password)
|
56
|
+
mail = Mail.new do
|
57
|
+
from 'agentportal@emerchantpay.com'
|
58
|
+
to email
|
59
|
+
subject 'Welcome to Emerchantpay Agent Portal'
|
60
|
+
html_part do
|
61
|
+
body Mailer::create_template(username, password)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
mail.delivery_method :smtp, {:address => "emp-ldn-exch01.emp.internal.com",
|
65
|
+
:port => 25,
|
66
|
+
:domain => "emp.internal.com",
|
67
|
+
:authentication => nil,
|
68
|
+
:enable_starttls_auto => true}
|
69
|
+
|
70
|
+
if mail.deliver!
|
71
|
+
true
|
72
|
+
else
|
73
|
+
@logger.error("Email for user #{last_name} failed!")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Generates the plain text password that is going to be
|
78
|
+
# send to the user in the email
|
79
|
+
# ActiveSupport::SecureRandom is deprecated in Rails > 3.1
|
80
|
+
def generate_password
|
81
|
+
str = SecureRandom.hex(6)
|
82
|
+
str
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.create_template(username, password)
|
86
|
+
email_template = <<-TEMPLATE
|
87
|
+
Dear valued partner,<br/><br/>
|
88
|
+
|
89
|
+
We have created an account for you to access the newly created eMerchantPay <a href="#{@@config["sugar_url"]}">Agent Portal</a><br/><br/>
|
90
|
+
|
91
|
+
Your account data is:<br/><br/>
|
92
|
+
|
93
|
+
Login: <b>#{username}</b><br/>
|
94
|
+
Password: <b>#{password}</b><br/><br/>
|
95
|
+
|
96
|
+
Features:<br/>
|
97
|
+
|
98
|
+
<ul>
|
99
|
+
<li>Based on the acclaimed SugarCRM, check details <a href="http://www.sugarcrm.com">here</a></li>
|
100
|
+
<li>Exports of merchants and various data items in different formats for further processing</li>
|
101
|
+
<li>Viewing information for your Merchants and the associated resources - bank accounts, emails, payment methods, etc.</li>
|
102
|
+
<li>Homepage customization for personalization and access</li>
|
103
|
+
<li>Can be accessed by mobile phone</li>
|
104
|
+
<li>And many others...</li>
|
105
|
+
</ul>
|
106
|
+
|
107
|
+
<br/>
|
108
|
+
If you have any questions, send an email to support@emerchantpay.com (also available by clicking the Support link from the main menu in the <a href="#{@@config["sugar_url"]}">Agent Portal</a>)
|
109
|
+
<br/><br/>
|
110
|
+
---<br/><br/>
|
111
|
+
|
112
|
+
Your <a href="http://www.emerchantpay.com">eMerchantPay</a> team<br/><br/>
|
113
|
+
TEMPLATE
|
114
|
+
email_template
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/lib/sf_migrate.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'csv'
|
5
|
+
require 'yaml'
|
6
|
+
require 'logger'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'databasedotcom'
|
9
|
+
require 'sugarcrm'
|
10
|
+
require 'mail'
|
11
|
+
require 'active_support/core_ext'
|
12
|
+
require 'active_record'
|
13
|
+
require 'fields'
|
14
|
+
require 'export'
|
15
|
+
require 'import'
|
16
|
+
require 'mailer'
|
17
|
+
|
18
|
+
module SalesforceMigration
|
19
|
+
module Runner
|
20
|
+
extend self
|
21
|
+
|
22
|
+
# Start the migration dependening on command line argument: `initial_run` or `update`
|
23
|
+
def start
|
24
|
+
options = {}
|
25
|
+
# Where do we need to store the csvs?
|
26
|
+
options[:csv_dir] = "/var/sugarcrm/csv"
|
27
|
+
options[:log_dir] = "/var/log/sugarcrm"
|
28
|
+
options[:config_file] = File.join(File.dirname(__FILE__), "../config/credentials.yaml")
|
29
|
+
@log_dir = options[:log_dir]
|
30
|
+
create_logger
|
31
|
+
optparse = OptionParser.new do |opts|
|
32
|
+
opts.banner = "Usage: sf_migrate [options]"
|
33
|
+
opts.on("-a", "--action NAME", "Start the initial_run or the daily update") do |action|
|
34
|
+
options[:action] = action
|
35
|
+
end
|
36
|
+
opts.on("-f", "--config_file CONFIG_FILE", "Supply an optional config file") do |f|
|
37
|
+
options[:config_file] = File.expand_path(f) if File.exists? f
|
38
|
+
end
|
39
|
+
opts.on("-c", "--csv_dir CSV_DIR", "Set the directory in which exported csv from Salesforce will be kept") do |c|
|
40
|
+
options[:csv_dir] = c
|
41
|
+
end
|
42
|
+
opts.on("-l", "--log_dir LOG_DIR", "Set the directory in which the logger will reside") do |l|
|
43
|
+
options[:log_dir] = l
|
44
|
+
end
|
45
|
+
opts.on("-m", "--send_mail", "Send activation email to every new user") do |m|
|
46
|
+
options[:send_mail] = m
|
47
|
+
end
|
48
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
49
|
+
puts opts
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
optparse.parse!
|
54
|
+
begin
|
55
|
+
SalesforceMigration::Export.new(options)
|
56
|
+
SalesforceMigration::Import.new(options)
|
57
|
+
SalesforceMigration::Mailer.new(options) if options[:send_mail]
|
58
|
+
rescue => e
|
59
|
+
@logger.error(e)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_logger
|
64
|
+
original_formatter = Logger::Formatter.new
|
65
|
+
today = lambda { Date.today.to_s }
|
66
|
+
dir = "#{@log_dir}/#{today.call}"
|
67
|
+
file = "#{dir}/migration.log"
|
68
|
+
FileUtils.mkdir_p(dir) unless Dir.exists? dir
|
69
|
+
@logger = Logger.new(file)
|
70
|
+
@logger.formatter = proc { |severity, datetime, progname, msg|
|
71
|
+
original_formatter.call("IMPORT", datetime, progname, msg)
|
72
|
+
}
|
73
|
+
@logger
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sf_migrate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dimitar KostovStefan Slaveykov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2013-05-30 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sugarcrm_emp
|
16
|
+
prerelease: false
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.10.1
|
22
|
+
type: :runtime
|
23
|
+
version_requirements: *id001
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: databasedotcom_emp
|
26
|
+
prerelease: false
|
27
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ~>
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 1.3.1
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id002
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: activesupport
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 3.2.6
|
42
|
+
type: :runtime
|
43
|
+
version_requirements: *id003
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: activerecord
|
46
|
+
prerelease: false
|
47
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ~>
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 3.2.13
|
52
|
+
type: :runtime
|
53
|
+
version_requirements: *id004
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: mail
|
56
|
+
prerelease: false
|
57
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.5.3
|
62
|
+
type: :runtime
|
63
|
+
version_requirements: *id005
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: roo
|
66
|
+
prerelease: false
|
67
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ~>
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 1.10.2
|
72
|
+
type: :runtime
|
73
|
+
version_requirements: *id006
|
74
|
+
description: SalesForce to SugarCRM migration tool
|
75
|
+
email:
|
76
|
+
- stefan@emerchantpay.com
|
77
|
+
executables:
|
78
|
+
- sf_migrate
|
79
|
+
extensions: []
|
80
|
+
|
81
|
+
extra_rdoc_files: []
|
82
|
+
|
83
|
+
files:
|
84
|
+
- README.md
|
85
|
+
- Gemfile
|
86
|
+
- bin/sf_migrate
|
87
|
+
- lib/fields.rb
|
88
|
+
- lib/export.rb
|
89
|
+
- lib/import.rb
|
90
|
+
- lib/mailer.rb
|
91
|
+
- lib/sf_migrate.rb
|
92
|
+
- config/credentials.yaml.example
|
93
|
+
homepage:
|
94
|
+
licenses: []
|
95
|
+
|
96
|
+
metadata: {}
|
97
|
+
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- &id007
|
106
|
+
- ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- *id007
|
112
|
+
requirements: []
|
113
|
+
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.0.3
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Makes a bridge between Salesforce and SugarCRM
|
119
|
+
test_files: []
|
120
|
+
|