sf_migrate 1.0.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/lib/export.rb +22 -15
  2. data/lib/fields.rb +13 -9
  3. data/lib/import.rb +685 -269
  4. data/lib/sf_migrate.rb +14 -12
  5. metadata +48 -7
data/lib/export.rb CHANGED
@@ -6,18 +6,18 @@ module SalesforceMigration
6
6
  #
7
7
  # @param [Hash] options hash representing passed command line options
8
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]
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
+ @last_modified_date = options[:last_modified_date]
16
17
  @logger = SalesforceMigration::Runner::create_logger
17
18
  @logger.info("Export action started")
18
19
  @client = Databasedotcom::Client.new :client_id => consumer_key, :client_secret => consumer_secret
19
20
  @client.authenticate :username => username, :password => password
20
-
21
21
  @logger.info("Authentication to SalesForce successfull")
22
22
  start
23
23
  @logger.info("Export action ended successfully")
@@ -25,7 +25,7 @@ module SalesforceMigration
25
25
 
26
26
  private
27
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|
28
+ %w(ISOs__c Agent__c Account Acquirer__c Contract Payment_Methods__c Banks__c MerchantToAPM__c ccrmbasic__Email__c Email_Association__c User).each do |type|
29
29
  @logger.info "Writing CSV for #{type}"
30
30
  write_to_csv type
31
31
  end
@@ -45,7 +45,7 @@ module SalesforceMigration
45
45
  records.each do |record|
46
46
  arr = []
47
47
  fields.each do |field|
48
- arr << record.send(field)
48
+ arr << record.send(field).to_s
49
49
  arr.map!(&method(:remove_quotes))
50
50
  end
51
51
  file << arr
@@ -75,14 +75,21 @@ module SalesforceMigration
75
75
  # @return [Databasedotcom::Collection] the requested records
76
76
  def get_records(type)
77
77
  if @action == 'initial_run'
78
- @logger.info "Getting all records from SalesForce for #{type}"
78
+ @logger.info "Getting all records from SalesForce for #{type} object"
79
79
  records = get_all_sobjects(type)
80
80
  else
81
- @logger.info "Getting records for yesterday from SalesForce for #{type}"
81
+ @logger.info "Getting records for yesterday from SalesForce for #{type} object"
82
82
  records = @client.materialize(type)
83
-
84
- datetime = DateTime.now
85
- datetime = datetime -= 1
83
+
84
+ begin
85
+ datetime = DateTime.parse(@last_modified_date)
86
+ rescue
87
+ if defined? @last_modified_date == nil
88
+ datetime = DateTime.now
89
+ else
90
+ raise ArgumentError, "Invalid Date", caller
91
+ end
92
+ end
86
93
  records.query("lastmodifieddate >= #{datetime}")
87
94
  end
88
95
  end
data/lib/fields.rb CHANGED
@@ -1,14 +1,18 @@
1
1
  module SalesforceMigration
2
2
  class Fields
3
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}
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 IsDeleted 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 IsDeleted 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 CurrencyIsoCode Current_Volume__c Description Descriptor__c FD_Merchant_Number__c Fax ISO_Name__c Id IsDeleted Industry Info_Capture__c Integration__c Integrator__c Integrator_2__c Iovation__c IPSP__c IPSP_Name2__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 Risk_Analyst__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} # OwnerName OwnerPhone OwnerEmail}
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 IsDeleted 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 IsDeleted 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{Actual_Subject__c Agent__c ccrmbasic__Account__c ccrmbasic__Body__c ccrmbasic__Cc__c ccrmbasic__Direction__c ccrmbasic__From__c ccrmbasic__Internal_Contact__c ccrmbasic__To__c Id IsDeleted Name}
11
+ EMAIL_ASSOCIATION_FIELDS = %w{Merchant_Name__c Email__c}
12
+ CONTRACT_FIELDS = %w{Id IsDeleted AccountId CurrencyIsoCode StartDate EndDate BillingStreet BillingCity BillingState BillingPostalCode BillingCountry ContractTerm OwnerId Status StatusCode ContractNumber CreatedDate CreatedById LastModifiedDate LastModifiedById SystemModstamp LastActivityDate Commission_Fee__c Transaction_Fee_Approved__c Transaction_Fee_Declined__c Charge_Back_Fee__c Rolling_Reserve__c Rolling_Reserve_Period__c VBV_Fee__c Wiring_Fee__c PCI_Compliance_Test_Fee__c Billing_Period_Duration_Weekly__c Discover__c Delay_in_Payment_Weeks__c Amex__c Guaranty__c Amount_Number__c Currency__c Treasury_Executive__c Acquirer__c Proccessing_Start_Date__c Proccessing_End_Date__c Acquirer_Approval_Timeframe__c Url__c Date_of_Submission_to_the_Acquirer__c Date_of_Approval__c Refund_Fee__c Registration_Fee__c Integrator_1__c Integrator_2__c Descriptor__c City_Field__c Acquirer_Rejection_Timeframe__c Date_of_Rejection__c Date_of_Issuing_the_MID__c Date_of_Terminal_Setup__c Date_of_Activation__c Deactivation_Date__c Comments__c Threat_Matrix__c Iovation__c Info_Capture__c VBV_MC3D__c PCI_Compliance__c Website_Compliance__c Reason_of_Deactivation__c VISA__c MC__c JCB__c UATP__c Integration_Type__c Payment_Status__c Payment_Suspension_Reason__c IPSP_name__c Visa_MCC_Code__c MC_MCC_Code__c Rejection_Reason__c Type_Of_Agreement__c}
13
+ ACQUIRER_FIELDS = %w{Id IsDeleted OwnerId Owner Name CurrencyIsoCode CreatedDate CreatedById CreatedBy LastModifiedDate LastModifiedById LastModifiedBy SystemModstamp LastActivityDate Acquirer_Address__c Acquirer_Country__c SPLIT__c Chargeback_Fee__c One_time_Setup_Fee__c Swift_Wire_Transfer_Fee__c Card_Type__c Card_Scheme__c Currency__c Risk_Level__c Transaction__c Fees_Approved__c Fees_Declined__c Fees_other__c Flat_Commision_Fee__c EUR_Interchange__c Non_EUR_Interchange__c }
14
+ SYSTEM_FIELDS = %w{id acquirer ownerid createddate createdbyid integrator integrator_1 integrator_2 ipsp iso lastactivitydate lastmodifieddate lastmodifiedbyid systemmodstamp recruiter region risk_analyst}
15
+ SYSTEM_READABLE_FIELDS = %w{id acquirer_id owner_id created_date created_by_id integrator_id integrator_id integrator_2_id ipsp_id iso_id last_activity_date last_modified_date last_modified_by_id system_modstamp recruiter_id region_id risk_analyst_id}
16
+ USER_FIELDS = %w{Id FirstName LastName Phone Email}
13
17
  end
14
18
  end
data/lib/import.rb CHANGED
@@ -7,7 +7,7 @@ module SalesforceMigration
7
7
  # -> transform_agents
8
8
  # -> populate_sugar -> get_sugarcrm_module_type
9
9
  # -> convert_string_to_datetime
10
- # -> create_association -> find_sugarcrm_object
10
+ # -> create_associations -> find_sugarcrm_object
11
11
  # -> create_user
12
12
  class Import
13
13
 
@@ -23,11 +23,11 @@ module SalesforceMigration
23
23
  SugarCRM.connect(url, username, password)
24
24
  @action = options[:action]
25
25
  @isos, @agents, @merchants, @bank_accounts, @agent_users, @iso_users, @emails = [], [], [], [], [], [], []
26
- @payment_to_merchants, @emails_to_merchants = [], []
26
+ @payment_to_merchants, @emails_to_merchants, @acquirers, @contracts, @users = [], [], [], [], []
27
27
  @logger = SalesforceMigration::Runner::create_logger
28
- @logger.info("Import action started")
28
+ @logger.info("Import action started!")
29
29
  start
30
- @logger.info("Import action ended successfully")
30
+ @logger.info("Import action completed!")
31
31
  end
32
32
 
33
33
  private
@@ -35,11 +35,14 @@ module SalesforceMigration
35
35
  def start
36
36
  import_emails
37
37
  import_payment_methods
38
+ import_settlement_bank_accounts
39
+ import_acquirers
40
+ import_contracts
41
+ import_users
38
42
  import_isos
39
43
  import_agents
40
44
  import_merchants
41
- import_settlement_bank_accounts
42
-
45
+
43
46
  associate_records_to_groups
44
47
  end
45
48
 
@@ -47,66 +50,93 @@ module SalesforceMigration
47
50
  # get rid of unnecessary information, transforms other fields, so
48
51
  # they can match the one in SugarCRM and calls for the populate_sugar method
49
52
  # which start the actual import. Keep in mind, that the order of the imports is important
53
+
54
+ def import_emails
55
+ records = load_file_for_import 'ccrmbasic__Email__c'
56
+ transform_emails! records
57
+ populate_sugar(records, "email")
58
+ load_email_to_merchant_associations
59
+ end
60
+
61
+ def load_email_to_merchant_associations
62
+ # Use the Email_Association CSV relation (Merchant.SalesForceId - Payment_Method.SalesForceId)
63
+ records = load_file_for_import 'Email_Association__c'
64
+ transform_email_to_merchants! records
65
+ @emails_to_merchants = records
66
+ end
67
+
68
+ def import_payment_methods
69
+ records = load_file_for_import 'Payment_Methods__c'
70
+ transform_payment_methods! records
71
+ populate_sugar(records, "payment_method")
72
+ load_payment_methods_to_merchant_associations
73
+ end
74
+
75
+ def load_payment_methods_to_merchant_associations
76
+ # Use the MerchantToAPM CSV relation (Merchant.SalesForceId - Payment_Method.SalesForceId)
77
+ records = load_file_for_import 'MerchantToAPM__c'
78
+ transform_apm_to_merchants! records
79
+ @payment_to_merchants = records
80
+ end
81
+
82
+ def import_settlement_bank_accounts
83
+ records = load_file_for_import 'Banks__c'
84
+ transform_settlement_bank_accounts! records
85
+ populate_sugar(records, "settlement_bank_account")
86
+ end
87
+
88
+ def import_acquirers
89
+ records = load_file_for_import 'Acquirer__c'
90
+ transform_acquirers! records
91
+ populate_sugar(records, "acquirer")
92
+ end
93
+
94
+ def import_contracts
95
+ records = load_file_for_import 'Contract'
96
+ transform_contracts! records
97
+ populate_sugar(records, "contract")
98
+ end
99
+
100
+ def import_users
101
+ records = load_file_for_import 'User'
102
+ transform_users! records
103
+ populate_sugar(records, "user")
104
+ end
105
+
50
106
  def import_isos
51
107
  records = load_file_for_import 'ISOs__c'
52
- records = transform_isos(records)
108
+ transform_isos! records
53
109
  populate_sugar(records, "iso")
54
110
  end
55
111
 
56
112
  def import_agents
57
113
  records = load_file_for_import 'Agent__c'
58
- records = transform_agents(records)
114
+ transform_agents! records
59
115
  populate_sugar(records, "agent")
60
116
  end
61
117
 
62
118
  def import_merchants
63
119
  records = load_file_for_import 'Account'
64
- records = transform_merchants(records)
120
+ transform_merchants! records
65
121
  populate_sugar(records, "merchant")
66
122
  end
67
123
 
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
124
  # Load CSV for import
98
125
  #
99
126
  # @param [String] module_name name of the module
100
127
  #
101
128
  # @return [Array] parsed CSV file
102
129
  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"
130
+
131
+ case @action
132
+ when "initial_run"
133
+ filename = "#{@csv_dir}/initial/#{module_name}_export.csv"
134
+ when "update"
135
+ today = lambda { Date.today.to_s }
136
+ dir = "#{@csv_dir}/update/#{today.call}"
137
+ filename = "#{dir}/#{module_name}_export.csv"
109
138
  end
139
+
110
140
  @logger.error("Could not create or find a csv filename for module #{module_name}") unless defined? filename
111
141
  @logger.info("Loading CSV file #{filename} for import")
112
142
  csv_file = ::CSV.read(filename, :encoding => 'utf-8')
@@ -137,23 +167,165 @@ module SalesforceMigration
137
167
  header.end_with?("__c") ? header.slice(0..-4).downcase : header.downcase
138
168
  end
139
169
 
140
- # Add sf_ prefix to all auto-generated attribute names from Salesforce
170
+ # Add sf_ prefix to all SalesForce-related fields and rename them (if applicable)
141
171
  #
142
- # @param [Array<SugarCRM::Namespace::Object>] records records to be prefixed
172
+ # @param [Array<SugarCRM::Namespace::Object>] records - records to be prefixed
143
173
  #
144
- # @return [Array<SugarCRM::Namespace::Object>] returns the records
174
+ # @return [Array<SugarCRM::Namespace::Object>] records
145
175
  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)
176
+ field_names_default = SalesforceMigration::Fields::SYSTEM_FIELDS
177
+ field_names_readable = SalesforceMigration::Fields::SYSTEM_READABLE_FIELDS
178
+
179
+ records.each do |record|
180
+ field_names_default.each_with_index do |field, index|
181
+ if record.key?(field)
182
+ record["sf_#{field_names_readable[index].downcase}"] = record[field]
183
+ record.delete(field)
184
+ end
151
185
  end
186
+ # Set the "deleted" flag according to SugarCRM's default fields
187
+ record['deleted'] = record['isdeleted'] unless record['isdeleted'].nil?
152
188
  end
153
189
  records
154
190
  end
155
191
 
156
- def transform_isos(records)
192
+
193
+ def transform_emails!(records)
194
+ @logger.info("Transforming Email fields")
195
+ records.each do |record|
196
+ record['sf_agent_id'] = record['agent']
197
+ record['sf_merchant_id'] = record['ccrmbasic__account']
198
+ record['direction'] = record['ccrmbasic__direction']
199
+ record['sender'] = record['ccrmbasic__from']
200
+ record['internal_contact'] = record['ccrmbasic__internal_contact']
201
+ record['receiver'] = record['ccrmbasic__to']
202
+ record['cc'] = record['ccrmbasic__cc']
203
+ record['name'] = record['actual_subject'] unless record['actual_subject'].blank?
204
+ record['body'] = convert_characters(record['ccrmbasic__body']) unless record['ccrmbasic__body'].nil?
205
+
206
+ record.delete 'agent'
207
+ record.delete 'ccrmbasic__to'
208
+ record.delete 'ccrmbasic__cc'
209
+ record.delete 'actual_subject'
210
+ record.delete 'ccrmbasic__body'
211
+ record.delete 'ccrmbasic__from'
212
+ record.delete 'ccrmbasic__account'
213
+ record.delete 'ccrmbasic__direction'
214
+ record.delete 'ccrmbasic__internal_contact'
215
+ end
216
+ end
217
+
218
+ def transform_payment_methods!(records)
219
+ @logger.info("Transforming Payment Method's fields")
220
+ records.each do |record|
221
+ record['business_type_comments'] = record['business_type_coments']
222
+
223
+ record.delete 'business_type_coments'
224
+ end
225
+ end
226
+
227
+
228
+ def transform_settlement_bank_accounts!(records)
229
+ @logger.info("Transforming Settlement Bank Account fields")
230
+ records.each do |record|
231
+ record['sf_contract_id'] = record['contract']
232
+ record['sf_merchant_id'] = record['merchant_2']
233
+
234
+ record.delete 'merchant_2'
235
+ record.delete 'contract'
236
+ end
237
+ end
238
+
239
+ def transform_acquirers!(records)
240
+ @logger.info("Transforming Acquirer fields")
241
+ records.each do |record|
242
+ record['currency_iso_code'] = record['currencyisocode']
243
+ record['fees_transaction'] = record['transaction']
244
+
245
+ record.delete 'currencyisocode'
246
+ record.delete 'transaction'
247
+ end
248
+ end
249
+
250
+ def transform_contracts!(records)
251
+ @logger.info("Transforming Contract fields")
252
+ records.each do |record|
253
+ record['name'] = record['contractnumber']
254
+ record['sf_account_id'] = record['accountid']
255
+ record['currency_iso_code'] = record['currencyisocode']
256
+ record['start_date'] = record['startdate']
257
+ record['end_date'] = record['enddate']
258
+ record['billing_street'] = record['billingstreet']
259
+ record['billing_city'] = record['billingcity']
260
+ record['billing_state'] = record['billingstate']
261
+ record['billing_postal_code'] = record['billingpostalcode']
262
+ record['billing_country'] = record['billingcountry']
263
+ record['contract_term'] = record['contractterm']
264
+ record['status_code'] = record['statuscode']
265
+ record['contract_number'] = record['contractnumber']
266
+ record['guarantee'] = record['guaranty']
267
+ record['guaranteed_amount'] = record['amount_number']
268
+ record['treasury_executive_sf_id'] = record['treasury_executive']
269
+ record['processing_start_date'] = record['proccessing_start_date']
270
+ record['processing_end_date'] = record['proccessing_end_date']
271
+ record['date_of_submission_to_acqirer'] = record['date_of_submission_to_the_acquirer']
272
+ record['chargeback_fee'] = record['charge_back_fee']
273
+ record['billing_period_duration'] = record['billing_period_duration_weekly']
274
+ record['payment_delay'] = record['delay_in_payment_weeks']
275
+ record['integrator1_sf_id'] = record['integrator_1']
276
+ record['integrator2_sf_id'] = record['integrator_2']
277
+ record['date_of_issuing_mid'] = record['date_of_issuing_the_mid']
278
+ record['date_of_deactivation'] = record['deactivation_date']
279
+ record['threatmetrix'] = record['threat_matrix']
280
+ record['deactivation_reason'] = record['reason_of_deactivation']
281
+ record['mastercard'] = record['mc']
282
+ record['ipsp_name_sf_id'] = record['ipsp_name']
283
+ record['mastercard_mcc_code'] = record['mc_mcc_code']
284
+
285
+ record.delete 'contractnumber'
286
+ record.delete 'accountid'
287
+ record.delete 'currencyisocode'
288
+ record.delete 'startdate'
289
+ record.delete 'enddate'
290
+ record.delete 'billingstreet'
291
+ record.delete 'billingcity'
292
+ record.delete 'billingstate'
293
+ record.delete 'billingpostalcode'
294
+ record.delete 'billingcountry'
295
+ record.delete 'contractterm'
296
+ record.delete 'statuscode'
297
+ record.delete 'guaranty'
298
+ record.delete 'amount_number'
299
+ record.delete 'treasury_executive'
300
+ record.delete 'proccessing_start_date'
301
+ record.delete 'proccessing_end_date'
302
+ record.delete 'date_of_submission_to_the_acquirer'
303
+ record.delete 'charge_back_fee'
304
+ record.delete 'billing_period_duration_weekly'
305
+ record.delete 'delay_in_payment_weeks'
306
+ record.delete 'integrator_1'
307
+ record.delete 'integrator_2'
308
+ record.delete 'date_of_issuing_the_mid'
309
+ record.delete 'deactivation_date'
310
+ record.delete 'threat_matrix'
311
+ record.delete 'reason_of_deactivation'
312
+ record.delete 'mc'
313
+ record.delete 'ipsp_name'
314
+ record.delete 'mc_mcc_code'
315
+ end
316
+ end
317
+
318
+ def transform_users!(records)
319
+ @logger.info("Transforming User fields")
320
+ records.each do |record|
321
+ record['name'] = "#{record['firstname']} #{record['lastname']}"
322
+
323
+ record.delete 'firstname'
324
+ record.delete 'lastname'
325
+ end
326
+ end
327
+
328
+ def transform_isos!(records)
157
329
  @logger.info("Transforming ISO fields")
158
330
  records.each do |record|
159
331
  record['general_c_chargeback_fee'] = record['general_conventional_chargeback_fee']
@@ -162,6 +334,7 @@ module SalesforceMigration
162
334
  record['general_nc_chargeback_fee'] = record['general_non_conventional_chargeback_fee']
163
335
  record['general_nc_commission_fee'] = record['general_non_conventional_commission_fee']
164
336
  record['general_nc_transaction_fee'] = record['general_non_conventional_transaction_fee']
337
+
165
338
  record.delete 'general_conventional_chargeback_fee'
166
339
  record.delete 'general_conventional_commission_fee'
167
340
  record.delete 'general_conventional_transaction_fee'
@@ -169,80 +342,152 @@ module SalesforceMigration
169
342
  record.delete 'general_non_conventional_commission_fee'
170
343
  record.delete 'general_non_conventional_transaction_fee'
171
344
  end
172
- records
173
345
  end
174
346
 
175
- def transform_agents(records)
176
- @logger.info("Transforming fields")
347
+ def transform_agents!(records)
348
+ @logger.info("Transforming Agent fields")
177
349
  records.each do |record|
178
- record['sf_iso'] = record['iso_company']
350
+ record['sf_iso_id'] = record['iso_company']
351
+
179
352
  record.delete 'iso_company'
180
353
  end
181
- records
182
354
  end
183
355
 
184
- def transform_merchants(records)
356
+ def transform_merchants!(records)
185
357
  @logger.info("Transforming Merchant fields")
186
358
  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]*)/, '')
359
+ record['sf_agent_id'] = record['agents']
360
+ record['ipsp_name'] = record['ipsp_name2']
361
+ record['url'] = record['url'].to_s.gsub(/<[^>]*>|^[\n\r]*/, '')
362
+ record['additional_url'] = record['additional_url'].to_s.gsub(/(<[^>]*>|^[\n\r]*)/, '')
363
+
190
364
  record.delete 'agents'
191
- record.delete 'sf_lastactivitydate'
192
- record.delete 'sf_lastmodifieddate'
193
365
  record.delete 'sf_region'
366
+ record.delete 'ipsp_name2'
194
367
  end
195
- records
196
368
  end
197
369
 
198
- def transform_settlement_bank_accounts(records)
199
- @logger.info("Transforming Settlement Bank Account fields")
370
+ def transform_email_to_merchants!(records)
371
+ @logger.info("Transforming Emails to Merchant fields");
200
372
  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'
373
+ record['sf_id'] = record['email']
374
+ record['sf_merchant_id'] = record['merchant_name']
375
+
376
+ record.delete 'email'
377
+ record.delete 'merchant_name'
209
378
  end
210
- records
211
379
  end
212
-
213
- def transform_emails(records)
214
- @logger.info("Transforming Email fields")
380
+
381
+ def transform_apm_to_merchants!(records)
382
+ @logger.info("Transforming APM to Merchant fields");
215
383
  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'
384
+ record['sf_id'] = record['payment_methods']
385
+ record['sf_merchant_id'] = record['merchant']
386
+
387
+ record.delete 'payment_methods'
388
+ record.delete 'merchant'
223
389
  end
224
- records
225
390
  end
226
391
 
227
- # Convert all string datetime attributes to DateTime objects
392
+ # Correct/Sanitize field types in a record (Boolean, Date/DateTime, nil)
393
+ #
394
+ # @param [SugarCRM::Namespace::Object] record - the record we want to process
395
+ #
396
+ # @return [SugarCRM::Namespace::Object] record
397
+ def correct_field_types!(record)
398
+ strip_empty_arrays!(record)
399
+
400
+ replace_invalid_ids!(record)
401
+
402
+ convert_string_to_boolean!(record)
403
+
404
+ convert_string_to_datetime!(record)
405
+
406
+ strip_nil_to_empty_string!(record)
407
+ end
408
+
409
+
410
+ # Convert all fields with date/modstamp in their names to DateTime objects
228
411
  #
229
- # @param [SugarCRM::Namespace::Object] record the record which attributes must be converted
412
+ # @param [SugarCRM::Namespace::Object] record - the record, where we look for date/stamp values and make them DB-Compatible
230
413
  #
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
414
+ # @return [SugarCRM::Namespace::Object] record
415
+ def convert_string_to_datetime!(record)
416
+ record.each do |field_name, field_value|
417
+ if field_name =~ /(.*)date(.*)|modstamp/
418
+ record[field_name] = DateTime.parse(field_value).to_s(:db) rescue nil
419
+ end
420
+ end
237
421
  end
238
-
422
+
423
+ # Convert all string fields to Boolean objects
424
+ #
425
+ # @param [SugarCRM::Namespace::Object] record - the record, where we look for boolean variables in string format
426
+ #
427
+ # @return [SugarCRM::Namespace::Object] record
428
+ def convert_string_to_boolean!(record)
429
+ record.each do |field_name, field_value|
430
+ case field_value
431
+ when /\Atrue\Z/i;
432
+ record[field_name] = true
433
+ when /\Afalse\Z/i;
434
+ record[field_name] = false
435
+ when /\Anil\Z/i, /\ANULL\Z/;
436
+ record[field_name] = nil
437
+ end
438
+ end
439
+ end
440
+
441
+ # Replace all empty arrays with empty strings
442
+ #
443
+ # @param [SugarCRM::Namespace::Object] record - the record, where we look for empty arrays
444
+ #
445
+ # @return [SugarCRM::Namespace::Object] record
446
+ def strip_empty_arrays!(record)
447
+ record.each do |field_name, field_value|
448
+ if field_value == "[]"
449
+ record[field_name] = ""
450
+ end
451
+ end
452
+ end
453
+
454
+ # nil (null) Values are not properly handled by SugarCRM, thus convert them to empty strings
455
+ #
456
+ # @param [SugarCRM::Namespace::Object] record - the record, where we look for empty arrays
457
+ #
458
+ # @return [SugarCRM::Namespace::Object] record
459
+ def strip_nil_to_empty_string!(record)
460
+ record.each do |field_name, field_value|
461
+ record[field_name] = "" if record[field_name].nil?
462
+ end
463
+ end
464
+
465
+ # Sometimes a record, may have an invalid id or a new owner, but the change might not be reflected in SalesForce thus we need to change it manually
466
+ #
467
+ # @param [SugarCRM::Namespace::Object] record - the record, where we look for empty arrays
468
+ #
469
+ # @return [SugarCRM::Namespace::Object] record
470
+ def replace_invalid_ids!(record)
471
+ valid_ids = %w{005300000057piVAAQ}
472
+ invalid_ids = %w{0053000000567TbAAI}
473
+
474
+ record.each do |field_name, field_value|
475
+ invalid_ids.each_with_index { |invalid_id, index| record[field_name] = valid_ids[index] if compare_salesforce_ids(record[field_value], invalid_id) }
476
+ end
477
+ end
478
+
479
+ # SQL escape string
480
+ #
481
+ # @param String string
482
+ #
483
+ # @return String string
239
484
  def convert_characters(string)
240
485
  string.gsub!(/\'/, '&apos;')
241
486
  string.gsub!(/'/, '')
242
487
  string.gsub!(/"/, '')
243
488
  string.gsub!(/\"/, '&quot;')
244
489
  string
245
- end
490
+ end
246
491
 
247
492
  # Populate SugarCRM with records
248
493
  # If it's initial run, it will create all records from the CSV file
@@ -252,40 +497,46 @@ module SalesforceMigration
252
497
  # @param [String] type type of the object
253
498
  def populate_sugar(records, type)
254
499
  module_type = get_sugarcrm_module_type(type)
500
+
255
501
  case @action
256
- when 'initial_run'
257
- @logger.info("Creating new records for #{type} type")
502
+ when 'initial_run'
503
+ @logger.info("Creating new records for #{type} type")
504
+ records.each do |record|
505
+ create_sugar_record(module_type, record, type)
506
+ end
507
+ when 'update'
258
508
  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?
509
+ correct_field_types! record
510
+
511
+ existing_record = find_sugarcrm_object(type, 'sf_id', record['sf_id'])
512
+
513
+ if existing_record
514
+ if existing_record.is_a?(Array)
515
+ @logger.error("More than one record for #{type} #{record['name']} - SalesForce Id (#{record['sf_id']}")
516
+ existing_record = existing_record.first
517
+ end
518
+
519
+ @logger.info("Updating record for #{type} #{record['name']}")
520
+ existing_record.update_attributes!(record)
521
+ else
522
+ @logger.info("Creating new record for #{type} #{record['name']}")
523
+ create_sugar_record(module_type, record, type)
271
524
  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
525
  end
278
- end
279
526
  end
280
527
  end
281
528
 
282
529
  # Create the actual records and users in SugarCRM. Populates the var_pool
530
+ #
531
+ # @param module_type
532
+ # @param record [SugarCRM::Namespace::Object]
533
+ # @param type
283
534
  def create_sugar_record(module_type, record, type)
284
- record = convert_string_to_datetime(record)
535
+ correct_field_types!(record)
285
536
 
286
537
  obj = module_type.new(record)
287
538
  obj.save!
288
- obj = create_association(obj, type) unless %(email payment_method).include? type
539
+ obj = create_associations(obj, type) unless %(email payment_method).include? type
289
540
  create_security_group_iso obj if type == 'iso'
290
541
 
291
542
  create_user(obj, type) if %(iso agent).include? type
@@ -295,21 +546,28 @@ module SalesforceMigration
295
546
  # Populates variables with SugarCRM objects.
296
547
  # We use them later on, when associating objects with Security Groups
297
548
  # 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
549
+ #
550
+ # @param [SugarCRM::Namespace::Object] obj - object for which a user will be created
551
+ # @param [String] type - type of the object
300
552
  def populate_var_pool(obj, type)
301
553
  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
554
+ when 'email'
555
+ @emails << obj
556
+ when 'settlement_bank_account'
557
+ @bank_accounts << obj
558
+ when 'acquirer'
559
+ @acquirers << obj
560
+ when 'contract'
561
+ @contracts << obj
562
+ when 'user'
563
+ @users << obj
564
+ when 'iso'
565
+ @isos << obj
566
+ when 'agent'
567
+ @agents << obj
568
+ when 'merchant'
569
+ @merchants << obj
570
+ end
313
571
  end
314
572
 
315
573
  # Create association for agent, merchant, settlement bank Account, Email, Payment Method
@@ -317,119 +575,243 @@ module SalesforceMigration
317
575
  # If it is merchant, it will find the Agent, Payment Method, User and create the associations
318
576
  # If it is Settlement Bank Account it will find the Merchant and create the associations
319
577
  # @param [SugarCRM::Namespace::Object] obj the object for which an association will be created
320
- # @param [String] type type of the object
578
+ # @param [String] type - type of the object
321
579
  #
322
- # @return [SugarCRM::Namespace::Object] the object
323
- def create_association(obj, type)
324
- @logger.info("Creating association for #{type} #{obj.name}")
580
+ # @return [SugarCRM::Namespace::Object] - the object
581
+ def create_associations(obj, type)
582
+ # You need to save! the object before passing it, as it won't create associations
583
+ @logger.info("Creating associations for #{type} #{obj.name}")
584
+
325
585
  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
586
+ when "agent"
587
+ associate_with!('iso', @isos, 'sf_id', obj)
588
+
589
+ associate_with!('email', @emails, 'sf_agent_id', obj)
590
+ when "merchant"
591
+ associate_with!('agent', @agents, 'sf_id', obj)
592
+
593
+ associate_with!('contract', @contracts, 'sf_account_id', obj)
594
+
595
+ associate_with!('email', @emails_to_merchants, 'sf_merchant_id', obj)
596
+
597
+ associate_with!('payment_method', @payment_to_merchants, 'sf_merchant_id', obj)
598
+
599
+ associate_with!('settlement_bank_account', @bank_accounts, 'sf_merchant_id', obj)
600
+
601
+ assign_user_as_owner_to_record(obj, obj)
352
602
  end
353
603
  obj
354
604
  end
355
605
 
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
606
+ # Associate an object with selected ids
607
+ def associate_module_by_ids!(obj, type, list_of_ids, assign_to_user = false, reverse_association = false)
608
+ if list_of_ids.is_a?(Array)
609
+ list_of_ids.each do |record_id|
610
+ sugar_object = find_sugarcrm_object(type, 'sf_id', record_id)
611
+ if reverse_association
612
+ sugar_object.associate! obj if sugar_object
613
+ else
614
+ obj.associate! sugar_object if sugar_object
615
+ end
616
+ assign_user_as_owner_to_record(object, sugar_object) if assign_to_user
617
+ end
389
618
  end
390
619
  end
391
620
 
392
621
  # Find records(payment methods, emails) in the junction object arrays, given the merchant_id
393
622
  # 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
623
+
624
+ def associate_with!(type, relation_data, relation_field, object)
625
+ return unless type and relation_data and relation_field and object
626
+
627
+ case type
628
+ when "iso"
629
+ related_to_id = object.sf_iso_id
630
+ when "agent"
631
+ related_to_id = object.sf_agent_id
632
+ else
633
+ related_to_id = object.sf_id
634
+ end
635
+
636
+ relation_data = (@action == "update") ? type : relation_data
637
+
638
+ found_records = find_related_records(relation_data, relation_field, related_to_id)
639
+
640
+ return if found_records.blank?
641
+
642
+ if %(contract email settlement_bank_account).include? type
643
+ associate_module_by_ids!(obj, type, found_records, true, false)
644
+ else
645
+ associate_module_by_ids!(obj, type, found_records, false, false)
397
646
  end
398
- false
399
647
  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
648
+
649
+ def find_related_records(relation_data, relation_field, related_to_id)
650
+ return unless relation_data and relation_field and related_to_id
651
+
652
+ search_results = []
653
+
654
+ case @action
655
+ when "initial_run"
656
+ relation_data.each do |record|
657
+ # Check if we are dealing with file-relations (stored as Array)
658
+ # OR if we're using SugarCRM records (store as Object)
659
+
660
+ record_id = (relation_data.first.is_a?(Hash)) ? record['sf_id'] : record.sf_id
661
+ relate_id = (relation_data.first.is_a?(Hash)) ? record[relation_field] : record.send(relation_field.to_sym)
662
+
663
+ search_results << record_id if compare_salesforce_ids(relate_id, related_to_id)
664
+ end
665
+ when "update"
666
+ # Check if we are dealing with file-relations (stored as Array)
667
+ if relation_data.first.is_a?(Hash)
668
+ relation_data.each { |record| search_results << record['sf_id'] if compare_salesforce_ids(record[relation_field], related_to_id) }
669
+ # OR extract the objects from SugarCRM
670
+ else
671
+ records = find_sugarcrm_object(relation_data, relation_field, related_to_id)
672
+
673
+ if records.is_a?(Array)
674
+ records.each { |record| search_results << record.sf_id }
675
+ else
676
+ search_results << records.sf_id
677
+ end
678
+ end
679
+ end
680
+
681
+ return search_results
682
+ end
683
+
684
+ # Assign user to an object, by providing a source and target objects
685
+ #
686
+ # @param [Object] id_object - An object holding the User Id
687
+ # @param [Object] target_object - The object we want to associate to this user
688
+ #
689
+ def assign_user_as_owner_to_record(id_object, object_to_assign)
690
+ return unless id_object and object_to_assign
691
+
692
+ salesforce_id = (id_object.sf_agent_id.blank?) ? id_object.sf_id : id_object.sf_agent_id
693
+
694
+ user = find_sugarcrm_object('users', 'salesforce_id', salesforce_id)
695
+
696
+ return if user.blank?
697
+
698
+ # Warn the user that we might've stumbbled upon some duplication or non-empty database (SalesForce Ids shoud be unique)
699
+ if user.is_a?(Array)
700
+ @logger.error("We found a SalesForce Id with two created SugarCRM users.")
701
+ user = user.first
404
702
  end
703
+
704
+ @logger.info("Assigning #{user.last_name} as owner to #{object_to_assign.name}")
705
+
706
+ object_to_assign.assigned_user_id = user.id
707
+ object_to_assign.save!
708
+ end
709
+
710
+ # Compare SalesForce Ids - SalesForce have two type of ids - 15 digit case-sensitive and 18-digit case-insensitive
711
+ #
712
+ # @param [String] salesforce_id - salesforce id to compare to
713
+ # @param [String] target_id - id
714
+ #
715
+ # @return [Boolean] true on match, every other case - false
716
+ def compare_salesforce_ids(salesforce_id, target_id)
717
+ return false unless salesforce_id and target_id
718
+
719
+ case salesforce_id.length
720
+ when 15
721
+ if target_id.length == 18
722
+ target_id = target_id[0..-4]
723
+ end
724
+ if salesforce_id == target_id
725
+ return true
726
+ end
727
+ when 18
728
+ if target_id.length == 15
729
+ salesforce_id = salesforce_id[0..-4]
730
+ end
731
+ if salesforce_id.casecmp(target_id) == 0
732
+ return true
733
+ end
734
+ end
735
+
405
736
  false
406
737
  end
407
738
 
408
- #Creates the Security Group object in SugarCRM
739
+ # Creates the Security Group object in SugarCRM
740
+ #
409
741
  # @param [SugarCRM::Namespace::EmpIso] Iso object
410
742
  def create_security_group_iso(iso)
411
743
  @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
744
+ security_group = SugarCRM::SecurityGroup.new(:name => iso.name) unless find_sugarcrm_object('security_group','name', iso.name)
745
+ security_group.save!
414
746
  end
415
747
 
416
- # Assign all records, that need to be in a Security Group, to the Group
748
+ # Assign all records, to their ISO's SecurityGroup
417
749
  def associate_records_to_groups
418
750
  put_isos_into_iso_group
419
751
  put_agents_into_iso_group
420
752
  put_merchants_into_iso_group
421
753
  end
422
754
 
755
+ # Create user associated with SugarCRM object
756
+ # Default email: mail@example.com, default password: 123456
757
+ #
758
+ # @param [SugarCRM::Namespace::Object] obj object for which a user will be created
759
+ # @param [String] type type of the object
760
+ def create_user(obj, type)
761
+ @logger.info("Creating user for #{type} #{obj.name}")
762
+ if (defined?(obj.emerchantpay_iso_id) && (obj.emerchantpay_iso_id.blank? || obj.email_address.blank?)) ||
763
+ (defined?(obj.emerchantpay_agent_id) && (obj.emerchantpay_agent_id.blank? || obj.email_address.blank?))
764
+ @logger.error("Record |#{obj.name}| with type |#{type}| have empty fields (which are required), thus its skipped!")
765
+ else
766
+ user = SugarCRM::User.new
767
+ user.user_name = (type == 'agent') ? obj.emerchantpay_agent_id : obj.emerchantpay_iso_id
768
+ user.last_name = obj.name
769
+ user.emp_type = type
770
+ user.email1 = obj.email_address || ""
771
+ user.status = 'Inactive'
772
+ user.salesforce_id = obj.sf_id
773
+ user.system_generated_password = false
774
+ user.save!
775
+ obj.assigned_user_id = user.id
776
+ obj.save!
777
+
778
+ populate_user_pool(user, type)
779
+ end
780
+ end
781
+
782
+ # Populates Users as SugarCRM objects.
783
+ # We use them later on, when associating objects with Security Groups
784
+ # @param [SugarCRM::Namespace::Object] Already created user object
785
+ # @param [String] type type of the object
786
+ def populate_user_pool(user, type)
787
+ case type
788
+ when 'iso'
789
+ @iso_users << user
790
+ when 'agent'
791
+ @agent_users << user
792
+ end
793
+ end
794
+
423
795
  def put_isos_into_iso_group
424
796
  if @isos
425
797
  @logger.info("Puting ISOs into ISO groups")
426
798
  role = SugarCRM::ACLRole.find_by_name("isos")
427
799
  @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
800
+ security_group = find_sugarcrm_object('security_group','name', iso.name)
801
+
802
+ if security_group
803
+ user = SugarCRM::User.find_by_last_name(iso.name)
804
+ iso.associate! security_group
805
+ role.associate! security_group
806
+
807
+ if user.nil?
808
+ @logger.error("ISO (#{iso.name}) doesn't have a user record")
809
+ else
810
+ user.associate! security_group
811
+ end
812
+ else
813
+ @logger.error("Couldn't find a SecurityGroup for ISO - #{iso.name}")
814
+ end
433
815
  end
434
816
  end
435
817
  end
@@ -438,15 +820,24 @@ module SalesforceMigration
438
820
  if @agents
439
821
  @logger.info("Putting agent records, agent users and agent role into ISO groups")
440
822
  @agents.each do |agent|
441
- sg = find_sugarcrm_object('security_group','name', agent.emp_iso.first.name) unless agent.emp_iso.empty?
823
+ security_group = find_sugarcrm_object('security_group','name', agent.emp_iso.first.name) unless agent.emp_iso.empty?
442
824
  role = SugarCRM::ACLRole.find_by_name('agents')
443
- if sg
825
+ if security_group
444
826
  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
827
+
828
+ if user.nil?
829
+ @logger.error("Agent (#{agent.emp_iso.first.name}) doesn't have a user record")
830
+ else
831
+ user.associate! security_group
832
+ end
833
+
834
+ @logger.info("Puting Agent #{agent.name} in Security Group #{security_group.name}")
835
+ agent.associate! security_group
836
+ role.associate! security_group
837
+ put_email_objects_into_iso_group(security_group, 'agent', agent)
838
+ else
839
+ @logger.error("Couldn't find a ISO SecurityGroup for Agent - #{agent.emp_iso.first.name}")
840
+ end
450
841
  end
451
842
  end
452
843
  end
@@ -459,81 +850,94 @@ module SalesforceMigration
459
850
  if @merchants
460
851
  @logger.info("Puting merchants into ISO groups")
461
852
  @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
853
+ unless (merchant.emp_agent.blank? || merchant.emp_agent.first.emp_iso.blank?)
854
+ security_group = find_sugarcrm_object('security_group','name', merchant.emp_agent.first.emp_iso.first.name)
471
855
 
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)
856
+ if security_group
857
+ @logger.info("Puting merchant #{merchant.name} into ISO group")
858
+ merchant.associate! security_group
859
+ put_bank_accounts_into_iso_group(security_group, merchant)
860
+ put_email_objects_into_iso_group(security_group, 'merchant', merchant)
861
+ put_payment_methods_objects_into_iso_group(security_group, merchant)
862
+ else
863
+ @logger.error("Couldn't find a ISO SecurityGroup for Merchant - #{merchant.name}")
476
864
  end
477
865
  end
478
866
  end
479
867
  end
480
868
  end
481
869
 
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
870
+ def put_bank_accounts_into_iso_group(security_group, merchant)
871
+ return unless security_group and merchant
872
+
873
+ @logger.info("Puting Bank Account for #{merchant.name} into ISO group")
874
+
875
+ case @action
876
+ when "initial_run"
877
+ bank_accounts_for_merchant_id = find_related_records(@bank_accounts, 'sf_merchant_id', merchant.sf_id)
878
+ when "update"
879
+ bank_accounts_for_merchant_id = find_related_records('settlement_bank_account', 'sf_merchant_id', merchant.sf_id)
489
880
  end
881
+
882
+ return if bank_accounts_for_merchant_id.blank?
883
+
884
+ associate_module_by_ids!(security_group, 'settlement_bank_account', bank_accounts_for_merchant_id, false, true)
490
885
  end
491
886
 
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
887
+ def put_email_objects_into_iso_group(security_group, type, obj)
888
+ return unless security_group and type and obj
889
+
890
+ @logger.info("Puting Emails for #{obj.name} into ISO group")
891
+
892
+ case type
893
+ when "agent"
894
+ case @action
895
+ when "initial_run"
896
+ email_ids_for_object = find_related_records(@emails, 'sf_agent_id', obj.sf_id)
897
+ when "update"
898
+ email_ids_for_object = find_related_records('email', 'sf_agent_id', obj.sf_id)
899
+ end
900
+ when "merchant"
901
+ case @action
902
+ when "initial_run"
903
+ email_ids_for_object = find_related_records(@emails_to_merchants, 'sf_merchant_id', obj.sf_id)
904
+ when "update"
905
+ email_ids_for_object = find_related_records('email', 'sf_merchant_id', obj.sf_id)
504
906
  end
505
- end
506
907
  end
908
+
909
+ return if email_ids_for_object.blank?
910
+
911
+ associate_module_by_ids!(security_group, 'email', email_ids_for_object, false, true)
507
912
  end
508
913
 
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
914
+ def put_payment_methods_objects_into_iso_group(security_group, merchant)
915
+ return unless security_group and merchant
916
+
917
+ @logger.info("Puting Payment Methods for #{merchant.name} into ISO group")
918
+
919
+ payment_methods = find_related_records(@payment_to_merchants, 'sf_merchant_id', merchant.sf_id)
920
+
921
+ return if payment_methods.blank?
922
+
923
+ associate_module_by_ids!(security_group, 'payment_method', payment_methods, false, true)
524
924
  end
525
925
 
526
926
  # Returns the SugarCRM module namespace
527
927
  # @param [String] type type of the module object
528
928
  def get_sugarcrm_module_type(type)
529
929
  modules = {
530
- "iso" => SugarCRM::EmpIso,
930
+ "acquirer" => SugarCRM::EmpAcquirer,
531
931
  "agent" => SugarCRM::EmpAgent,
932
+ "contract" => SugarCRM::EmpContract,
933
+ "email" => SugarCRM::EmpEmail,
934
+ "iso" => SugarCRM::EmpIso,
532
935
  "merchant" => SugarCRM::EmpMerchant,
533
936
  "payment_method" => SugarCRM::EmpPaymentmethod,
534
937
  "settlement_bank_account" => SugarCRM::EmpSettlementBankAccount,
938
+ "user" => SugarCRM::EmpUser,
535
939
  "security_group" => SugarCRM::SecurityGroup,
536
- "email" => SugarCRM::EmpEmail
940
+ "users" => SugarCRM::User,
537
941
  }
538
942
  modules[type]
539
943
  end
@@ -549,5 +953,17 @@ module SalesforceMigration
549
953
  SugarCRM.connection.get_entry_list(module_type, "#{module_type.downcase}.#{attribute} = '#{search_string}'")
550
954
  end
551
955
 
956
+ # Populates the var_pool with Sugar Objects.
957
+ # Reason being, is that if you abort the current process (error or some other reason)
958
+ # You won't be able to continue from the same place and be able to correctly associate the objects
959
+ # To prevent this, we can just load back every object for every type and continue uninterrupted
960
+ #
961
+ # @param [String] id - SalesForce id of the object, that we want to retrieve
962
+ # @param [String] type - type of the object, that we want to retrieve (module type)
963
+ def populate_var_poll_from_sugar(id, type)
964
+ obj = find_sugarcrm_object(type, 'sf_id', id)
965
+ populate_var_pool(obj, type) if obj
966
+ end
967
+
552
968
  end
553
969
  end