sf_migrate 1.0.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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