lolita-first-data 1.0.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.
- data/.rspec +2 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +140 -0
- data/LICENSE.txt +20 -0
- data/README.md +89 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/app/controllers/lolita/first_data/common_controller.rb +25 -0
- data/app/controllers/lolita/first_data/test_controller.rb +78 -0
- data/app/controllers/lolita/first_data/transaction_controller.rb +49 -0
- data/app/models/lolita/first_data/transaction.rb +55 -0
- data/config/locales/en.yml +109 -0
- data/config/locales/lv.yml +109 -0
- data/config/routes.rb +5 -0
- data/lib/generators/lolita_first_data/install_generator.rb +14 -0
- data/lib/generators/lolita_first_data/templates/migration.rb +21 -0
- data/lib/lolita-first-data.rb +6 -0
- data/lib/lolita-first-data/billing.rb +37 -0
- data/lib/lolita-first-data/custom_logger.rb +10 -0
- data/lib/lolita-first-data/gateway.rb +160 -0
- data/lib/lolita-first-data/rails.rb +6 -0
- data/lib/tasks/first_data_tasks.rake +78 -0
- data/lolita-first-data.gemspec +95 -0
- data/spec/cert.pem +63 -0
- data/spec/fabricators/reservation_fabricator.rb +4 -0
- data/spec/fabricators/transaction_fabricator.rb +7 -0
- data/spec/first_data_spec.rb +67 -0
- data/spec/spec_helper.rb +101 -0
- data/spec/support/rails.rb +16 -0
- metadata +189 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module Lolita::FirstData
|
2
|
+
class Transaction < ActiveRecord::Base
|
3
|
+
set_table_name :first_data_transactions
|
4
|
+
belongs_to :paymentable, :polymorphic => true
|
5
|
+
after_save :touch_paymentable
|
6
|
+
|
7
|
+
def ip
|
8
|
+
IPAddr.new(self[:ip], Socket::AF_INET).to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
def ip=(x)
|
12
|
+
self[:ip] = IPAddr.new(x).to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_answer rs, gateway, request
|
16
|
+
self.status = (rs.success?) ? 'completed' : 'rejected'
|
17
|
+
self.transaction_code = rs.params['RESULT_CODE']
|
18
|
+
begin
|
19
|
+
self.save!
|
20
|
+
rescue Exception => e
|
21
|
+
fdp_error = "#{e.to_s}\n\n#{$@.join("\n")}"
|
22
|
+
if rs.success?
|
23
|
+
begin
|
24
|
+
gateway.reverse(fdp.transaction_id,fdp.paymentable.price)
|
25
|
+
rescue Exception => reverse_exception
|
26
|
+
reverse_error = "#{reverse_exception.to_s}\n\n#{$@.join("\n")}"
|
27
|
+
ExceptionNotifier::Notifier.exception_notification(request.env, reverse_exception).deliver if defined?(ExceptionNotifier)
|
28
|
+
gateway.log :error, reverse_error
|
29
|
+
end
|
30
|
+
end
|
31
|
+
ExceptionNotifier::Notifier.exception_notification(request.env, e).deliver if defined?(ExceptionNotifier)
|
32
|
+
gateway.log :error, fdp_error
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# add new transaction in Checkout
|
38
|
+
def self.add payment, request, rs
|
39
|
+
Lolita::FirstData::Transaction.create!(
|
40
|
+
:transaction_id => rs.params['TRANSACTION_ID'],
|
41
|
+
:status => 'processing',
|
42
|
+
:paymentable_id => payment.id,
|
43
|
+
:paymentable_type => payment.class.to_s,
|
44
|
+
:ip => request.remote_ip
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# trigger "fd_trx_saved" on our paymentable model
|
51
|
+
def touch_paymentable
|
52
|
+
paymentable.fd_trx_saved(self) if paymentable
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
en:
|
2
|
+
fd:
|
3
|
+
unknown_error: Unknown error
|
4
|
+
no_trans_id: No transaction ID
|
5
|
+
wrong_request: Wrong request
|
6
|
+
purchase_failed: "Failed to create a payment, please try again."
|
7
|
+
response:
|
8
|
+
code_914: "Rejected, can not return to\n original transaction"
|
9
|
+
code_003: "Confirmed VIP"
|
10
|
+
code_102: "Rejected, possible fraud detected"
|
11
|
+
code_201: "Take away, card expired"
|
12
|
+
code_300: "Status message: file action successful"
|
13
|
+
code_123: "Rejected, exceeded money\n issue frequency limit"
|
14
|
+
code_XXX: "Code to be replaced by card status code or stoplist insertion reason code"
|
15
|
+
code_915: "Rejected, reconciliation reconnection\n or checkpoint error"
|
16
|
+
code_004: "Confirmed, corrected 3rd path"
|
17
|
+
code_103: "Rejected, card holder is\n required to contact receiver bank"
|
18
|
+
code_202: "Take away, possible fraud detected"
|
19
|
+
code_301: "Status message: file action not supported by receiver"
|
20
|
+
code_400: "Confirmed (For reservation)"
|
21
|
+
code_124: "Rejected, violation of the law"
|
22
|
+
code_916: "Rejected, incorrect MAC"
|
23
|
+
code_005: "Accepted, account is selected\n by card issuer"
|
24
|
+
code_104: "Rejected, card has limits"
|
25
|
+
code_203: "Take away, card holder is\n required to contact receiver bank"
|
26
|
+
code_302: "Status message: unable to locate record on file"
|
27
|
+
code_500: "Status message: reconciled, in balance"
|
28
|
+
code_125: "Rejected, card is not valid"
|
29
|
+
code_917: "Rejected, MAC key\n synchronization error"
|
30
|
+
code_600: "Accepted (Administrative info)"
|
31
|
+
code_126: "Rejected, incorrect PIN"
|
32
|
+
code_006: "Accepted for partial sum, account\n type selected by card issuer"
|
33
|
+
code_105: "Rejected, card receiver is required\n to call the security department of the issuer bank"
|
34
|
+
code_204: "Take away, card with limits"
|
35
|
+
code_303: "Status message: duplicate record, old record replaced"
|
36
|
+
code_501: "Status message: reconciled, out of balance"
|
37
|
+
code_700: "Confirmed (commission collection)"
|
38
|
+
code_601: "Status message: impossible to trace back original transaction"
|
39
|
+
code_007: "Confirmed, corrected ICC"
|
40
|
+
code_106: "Rejected, PIN entry retry\n count exceeded"
|
41
|
+
code_205: "Take away, card receiver is required\n to call the security department of the issuer bank"
|
42
|
+
code_304: "Status message: file record field edit error"
|
43
|
+
code_502: "Status message: amount not reconciled, totals provided"
|
44
|
+
code_127: "Rejected, PIN too long"
|
45
|
+
code_920: "Rejected, security software\n error, try again"
|
46
|
+
code_918: "Rejected, no\n usable transport keys "
|
47
|
+
code_800: "Confirmed (Network management)"
|
48
|
+
code_602: "Status message: invalid transaction reference number"
|
49
|
+
code_107: "Rejected, contact\n card issuer bank"
|
50
|
+
code_206: "Take away, PIN entry\n retry count exceeded"
|
51
|
+
code_305: "Status message: file locked out"
|
52
|
+
code_503: "Status message: totals for reconciliation not available"
|
53
|
+
code_128: "Rejected, PIN key synchronization error"
|
54
|
+
code_921: "Rejected, security software error"
|
55
|
+
code_919: "Rejected, encryption key\n synchronization error"
|
56
|
+
code_900: "Message accepted, accept without\n financial responsibility"
|
57
|
+
code_603: "Status message: reference number/PAN incompatible"
|
58
|
+
code_108: "Rejected, contact card\n issuer bank, special conditions apply"
|
59
|
+
code_207: "Take away, special conditions apply"
|
60
|
+
code_306: "Status message: file action not successful"
|
61
|
+
code_504: "Status message: not reconciled, totals provided"
|
62
|
+
code_129: "Rejected, suspected counterfeit card"
|
63
|
+
code_922: "Rejected, message number\n does not comply with the order"
|
64
|
+
code_901: "Message accepted, accept with\n financial responsibility"
|
65
|
+
code_604: "Status message: POS photograph is not available"
|
66
|
+
code_110: "Rejected, incorrect amount"
|
67
|
+
code_109: "Rejected, incorrect merchant"
|
68
|
+
code_208: "Take away, lost card"
|
69
|
+
code_307: "Status message: file data format error"
|
70
|
+
code_923: "Request is being processed"
|
71
|
+
code_902: "Rejected, incorrect transaction"
|
72
|
+
code_605: "Status message: requested item supplied"
|
73
|
+
code_111: "Rejected, incorrect card number"
|
74
|
+
code_210: "Take away, suspected counterfeit card"
|
75
|
+
code_209: "Take away, card stolen"
|
76
|
+
code_308: "Status message: duplicate record, new record rejected"
|
77
|
+
code_903: "Enter transaction again"
|
78
|
+
code_606: "Status message: request cannot be\n fulfilled - required documentation is not available"
|
79
|
+
code_112: "Rejected, PIN required"
|
80
|
+
code_309: "Status message: unknown file"
|
81
|
+
code_197: "Rejected, call AMEX"
|
82
|
+
code_904: "Rejected, format error"
|
83
|
+
code_113: "Rejected, unacceptable commission"
|
84
|
+
code_198: "Rejected, contact card processing center"
|
85
|
+
code_905: "Rejected, receiving bank has no connection"
|
86
|
+
code_114: "Rejected, account type not requested"
|
87
|
+
code_906: "Rejected, currently switching"
|
88
|
+
code_115: "Rejected, requested function\n not supported"
|
89
|
+
code_950: "Rejected, business agreement breach"
|
90
|
+
code_116: "Rejected, insufficient funds"
|
91
|
+
code_907: "Rejected, issuer bank or connection\n not working"
|
92
|
+
code_117: "Rejected, incorrect PIN"
|
93
|
+
code_910: "Rejected, card issuer bank turned off"
|
94
|
+
code_908: "Rejected, transaction addressee\n not found"
|
95
|
+
code_118: "Rejected, card entry not found"
|
96
|
+
code_911: "Rejected, kartes izdevējbanka\n laicīgi nesniedz atbildi"
|
97
|
+
code_909: "Rejected, system malfunction"
|
98
|
+
code_000: "Confirmed"
|
99
|
+
code_120: "Rejected, transaction not allowed\n for terminal"
|
100
|
+
code_119: "Rejected, transaction not allowed\n for card user"
|
101
|
+
code_912: "Rejected, can not connect to\n card issuer bank"
|
102
|
+
code_001: "Confirmed, if identity can be approved"
|
103
|
+
code_100: "Rejected (General, without specification)"
|
104
|
+
code_121: "Rejected, exceeded monet\n issue limit"
|
105
|
+
code_913: "Rejected, double transmission"
|
106
|
+
code_002: "Confirmed for partial amount"
|
107
|
+
code_101: "Rejected, card expired"
|
108
|
+
code_200: "Take away card (General, without specification)"
|
109
|
+
code_122: "Rejected, security breach"
|
@@ -0,0 +1,109 @@
|
|
1
|
+
lv:
|
2
|
+
fd:
|
3
|
+
unknown_error: nezināma kļūda
|
4
|
+
no_trans_id: Nav transakcijas ID
|
5
|
+
wrong_request: Nepareizs pieprasījums
|
6
|
+
purchase_failed: "Neizdevās izveidot maksājumu, lūdzu mēģiniet vēlreiz."
|
7
|
+
response:
|
8
|
+
code_914: "Atteikts, nevar atgriezties pie\n oriģinālās transakcijas"
|
9
|
+
code_003: "Apstirināts VIP"
|
10
|
+
code_102: "Atteikts, aizdomas par krāpniecību"
|
11
|
+
code_201: "Atņemt, beidzies kartes derīguma termiņš"
|
12
|
+
code_300: "Status message: file action successful"
|
13
|
+
code_123: "Atteikts, pārsniegts naudas\n izdošanas biežuma limits"
|
14
|
+
code_XXX: "Code to be replaced by card status code or stoplist insertion reason code"
|
15
|
+
code_915: "Atteikts, rekonsilācijas pārslēgšana\n vai kontrolpunkta kļūda"
|
16
|
+
code_004: "Apstiprināts, koriģēts 3 celiņš"
|
17
|
+
code_103: "Atteikts, kartes pieņēmējam\n jāsazinās ar pieņēmējbanku"
|
18
|
+
code_202: "Atņemt, aizdomas par krāpšanu"
|
19
|
+
code_301: "Status message: file action not supported by receiver"
|
20
|
+
code_400: "Apstiprināts (Reversēšanai)"
|
21
|
+
code_124: "Atteikts, likuma pārkāpums"
|
22
|
+
code_916: "Atteikts, nepareizs MAC"
|
23
|
+
code_005: "Apstiprināts, konta tipu norāda\n kartes izdevējs"
|
24
|
+
code_104: "Atteiks, karte ar ierobežojumu"
|
25
|
+
code_203: "Atņemt, kartes pieņēmējam jāsazinās\n ar pieņēmējbanku"
|
26
|
+
code_302: "Status message: unable to locate record on file"
|
27
|
+
code_500: "Status message: reconciled, in balance"
|
28
|
+
code_125: "Atteikts, karte nav derīga"
|
29
|
+
code_917: "Atteikts, MAC atslēgu\n sinhronizācijas kļūda"
|
30
|
+
code_600: "Apstiprināts (Administratīvais info)"
|
31
|
+
code_126: "Atteikts, nepareizs PIN bloks"
|
32
|
+
code_006: "Apstiprināts par daļēju summu, konta\n tipu norāda kartes izdevējs"
|
33
|
+
code_105: "Atteikts, kartes pieņēmējam jāzvana\n izdevējbankas drošības departamentam"
|
34
|
+
code_204: "Atņemt, karte ar ierobežojumiem"
|
35
|
+
code_303: "Status message: duplicate record, old record replaced"
|
36
|
+
code_501: "Status message: reconciled, out of balance"
|
37
|
+
code_700: "Apstiprināts (komisiju savākšana)"
|
38
|
+
code_601: "Status message: impossible to trace back original transaction"
|
39
|
+
code_007: "Apstiprināts, koriģēts ICC"
|
40
|
+
code_106: "Atteikts, pieļaujamais PIN\n ievadīšanas skaits izsmelts"
|
41
|
+
code_205: "Atņemt, kartes pieņēmējam jāzvana\n izdevējbankas drošības departamentam"
|
42
|
+
code_304: "Status message: file record field edit error"
|
43
|
+
code_502: "Status message: amount not reconciled, totals provided"
|
44
|
+
code_127: "Atteikts, PIN garuma kļūda"
|
45
|
+
code_920: "Atteikts, drošības programmatūras\n kļūda, mēģiniet atkārtoti"
|
46
|
+
code_918: "Atteikts, nav\n lietojamu transporta atslēgu "
|
47
|
+
code_800: "Apstiprināts (Tīkla vadībai)"
|
48
|
+
code_602: "Status message: invalid transaction reference number"
|
49
|
+
code_107: "Atteikts, griezties pie kartes\n izdevējbankas"
|
50
|
+
code_206: "Atņemt, pārsniegts atļauto PIN\n ievažu skaits"
|
51
|
+
code_305: "Status message: file locked out"
|
52
|
+
code_503: "Status message: totals for reconciliation not available"
|
53
|
+
code_128: "Atteikts, PIN atslēgu sinhronizācijas kļūda"
|
54
|
+
code_921: "Atteikts, drošības programmatūras kļūda"
|
55
|
+
code_919: "Atteikts, kriptēšanas atslēgu\n sinhronizācijas kļūda"
|
56
|
+
code_900: "Paziņojums atzīts, pieņemt bez\n finansiālas atbildības"
|
57
|
+
code_603: "Status message: reference number/PAN incompatible"
|
58
|
+
code_108: "Atteikts, griezties pie kartes\n izdevējbankas, īpaši nosacījumi"
|
59
|
+
code_207: "Atņemt, īpaši nosacījumi"
|
60
|
+
code_306: "Status message: file action not successful"
|
61
|
+
code_504: "Status message: not reconciled, totals provided"
|
62
|
+
code_129: "Atteikts, aizdomas par kartes viltojumu"
|
63
|
+
code_922: "Atteikts, ziņojuma numurs neatbilst\n secībai"
|
64
|
+
code_901: "Paziņojums atzīts, pieņemt ar\n finansiālu atbildību"
|
65
|
+
code_604: "Status message: POS photograph is not available"
|
66
|
+
code_110: "Atteikts, nepareiza summa"
|
67
|
+
code_109: "Atteikts, nepareizs tirgotājs"
|
68
|
+
code_208: "Atņemt, pazaudēta karte"
|
69
|
+
code_307: "Status message: file data format error"
|
70
|
+
code_923: "Pieprasījums tiek apstrādāts"
|
71
|
+
code_902: "Atteikts, nepareiza transakcija"
|
72
|
+
code_605: "Status message: requested item supplied"
|
73
|
+
code_111: "Atteikts, nepareizs kartes numurs"
|
74
|
+
code_210: "Atņemt, aizdomas par kartes viltojumu"
|
75
|
+
code_209: "Atņemt, zagta karte"
|
76
|
+
code_308: "Status message: duplicate record, new record rejected"
|
77
|
+
code_903: "Vēlreiz ievadi transakciju"
|
78
|
+
code_606: "Status message: request cannot be\n fulfilled - required documentation is not available"
|
79
|
+
code_112: "Atteikts, PIN dati nepieciešami"
|
80
|
+
code_309: "Status message: unknown file"
|
81
|
+
code_197: "Atteikts, zvaniet AMEX"
|
82
|
+
code_904: "Atteikts, formāta kļūda"
|
83
|
+
code_113: "Atteikts, nepieņemama komisija"
|
84
|
+
code_198: "Atteikts, zvaniet Karšu apstrādes centram"
|
85
|
+
code_905: "Atteikts, pieņēmējbankai nav pieslēguma"
|
86
|
+
code_114: "Atteikts, nav pieprasīts konta tips"
|
87
|
+
code_906: "Atteikts, notiek pārslēgšana"
|
88
|
+
code_115: "Atteikts, pieprasītā funkcija netiek\n atbalstīta"
|
89
|
+
code_950: "Atteikts, biznesa vienošanās pārkāpums"
|
90
|
+
code_116: "Atteikts, nepietiek līdzekļu"
|
91
|
+
code_907: "Atteikts, nedarbojas izdevējbanka\n vai pieslēgums"
|
92
|
+
code_117: "Atteikts, nepareizs PIN kods"
|
93
|
+
code_910: "Atteikts, kartes izdevējbankas izslēgta"
|
94
|
+
code_908: "Atteikts, nevar atrast\n transakcijas adresātu"
|
95
|
+
code_118: "Atteikts, nav kartes ieraksta"
|
96
|
+
code_911: "Atteikts, kartes izdevējbanka\n laicīgi nesniedz atbildi"
|
97
|
+
code_909: "Atteikts, sistēmas nepareiza darbība"
|
98
|
+
code_000: "Apstiprināts"
|
99
|
+
code_120: "Atteikts, transakcija nav atļauta\n terminālam"
|
100
|
+
code_119: "Atteikts, transakcija nav atļauta\n kartes lietotājam"
|
101
|
+
code_912: "Atteikts, kartes izdevējbankas nav\n sasniedzama"
|
102
|
+
code_001: "Apstiprināts, ja var apliecināt identitāti"
|
103
|
+
code_100: "Atteikts (Vispārīgs, bez komentāriem)"
|
104
|
+
code_121: "Atteikts, pārsniegts naudas\n izdošanas limits"
|
105
|
+
code_913: "Atteikts, dubulta pārraide"
|
106
|
+
code_002: "Apstiprināts par daļēju summu"
|
107
|
+
code_101: "Atteikts, beidzies kartes derīguma termiņš"
|
108
|
+
code_200: "Atņemt karti (Vispārīgs, bez komnetāriem)"
|
109
|
+
code_122: "Atteikts, drošības pārkāpums"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
match '/first_data/checkout', :as => "checkout_first_data", :controller => 'Lolita::FirstData::Transaction', :action => 'checkout'
|
3
|
+
match '/first_data/answer', :as => "answer_first_data", :controller => 'Lolita::FirstData::Transaction', :action => 'answer'
|
4
|
+
match '/first_data_test/:action', :controller => 'Lolita::FirstData::Test'
|
5
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module LolitaFirstData
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
include Lolita::Generators::FileHelper
|
5
|
+
source_root File.expand_path("../templates", __FILE__)
|
6
|
+
desc "Create migrations. "
|
7
|
+
|
8
|
+
def copy_migration
|
9
|
+
copy_file "migration.rb", "db/migrate/#{Time.now.strftime("%Y%m%d%H%M%S")}_create_lolita_first_data_transaction.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateLolitaFirstDataTransaction < ActiveRecord::Migration
|
2
|
+
class << self
|
3
|
+
def up
|
4
|
+
create_table :first_data_transactions do |t|
|
5
|
+
t.string :transaction_id, :length => 28
|
6
|
+
t.string :transaction_code, :length => 3
|
7
|
+
t.string :status, :default => "processing"
|
8
|
+
t.references :paymentable, :polymorphic => true
|
9
|
+
t.string :ip, :length => 10
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
|
14
|
+
add_index :first_data_transactions, [:paymentable_type,:paymentable_id], :name => "fd_trx_paymentable_type_paymentable_id"
|
15
|
+
end
|
16
|
+
|
17
|
+
def down
|
18
|
+
drop_table :first_data_transactions
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Lolita
|
2
|
+
module FirstData
|
3
|
+
module Billing
|
4
|
+
def self.included(base)
|
5
|
+
base.has_many :fd_transactions, :as => :paymentable, :class_name => "Lolita::FirstData::Transaction", :dependent => :destroy
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.class_eval do
|
8
|
+
# returns true if exists transaction with status 'completed'
|
9
|
+
# and updates status if needed
|
10
|
+
def paid?
|
11
|
+
self.fd_transactions.count(:conditions => {:status => 'completed', :transaction_code => '000'}) >= 1
|
12
|
+
end
|
13
|
+
|
14
|
+
def fd_error_message
|
15
|
+
if !fd_transactions.empty? && fd_transactions.last.transaction_code
|
16
|
+
I18n.t("fd.response.code_#{fd_transactions.last.transaction_code}", :default => I18n.t('fd.unknown_error'))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
# Closes business day
|
24
|
+
# should be executed every day ~midnight
|
25
|
+
# Like "ruby script/runner <YourBillingModel>.close_business_day"
|
26
|
+
def close_business_day
|
27
|
+
gw = ActiveMerchant::Billing::FirstDataGateway.new(
|
28
|
+
:pem => File.open(FD_PEM).read,
|
29
|
+
:pem_password => FD_PASS
|
30
|
+
)
|
31
|
+
rs =gw.close_day
|
32
|
+
rs.success? or raise("FirstData close day: #{rs.message}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Lolita
|
2
|
+
module FirstData
|
3
|
+
# custom log formatter for FirstData gateway
|
4
|
+
class LogFormatter < Logger::Formatter
|
5
|
+
def call(severity, time, program_name, message)
|
6
|
+
"%5s [%s] (%s) %s :: %s\n" % [severity,I18n.l(time), $$, program_name, message]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class FirstDataGateway < Gateway
|
4
|
+
TEST_DOMAIN = 'https://secureshop-test.firstdata.lv'
|
5
|
+
LIVE_DOMAIN = 'https://secureshop.firstdata.lv'
|
6
|
+
|
7
|
+
# The homepage URL of the gateway
|
8
|
+
self.homepage_url = 'http://www.firstdata.lv/'
|
9
|
+
|
10
|
+
# The name of the gateway
|
11
|
+
self.display_name = 'FirstData'
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
requires!(options, :pem, :pem_password)
|
15
|
+
@options = options
|
16
|
+
@logger = Logger.new(defined?(Rails) ? "#{Rails.root}/log/first_data.log" : "/tmp/fd.log", 2, 1024**2)
|
17
|
+
@logger.formatter = Lolita::FirstData::LogFormatter.new
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def authorize(money, currency ,ip, description)
|
22
|
+
commit('authorize',{
|
23
|
+
'command' => 'a',
|
24
|
+
'msg_type' => 'DMS',
|
25
|
+
'amount' => money,
|
26
|
+
'currency' => currency,
|
27
|
+
'client_ip_addr'=> ip,
|
28
|
+
'description' => description[0,125],
|
29
|
+
'language' => language
|
30
|
+
})
|
31
|
+
end
|
32
|
+
|
33
|
+
def complete(trans_id,amount,currency,ip,description)
|
34
|
+
commit('complete',{
|
35
|
+
'command' => 't',
|
36
|
+
'msg_type' => 'DMS',
|
37
|
+
'trans_id' => trans_id,
|
38
|
+
'amount' => amount,
|
39
|
+
'currency' => currency,
|
40
|
+
'client_ip_addr'=> ip,
|
41
|
+
'description' => description[0,125]
|
42
|
+
})
|
43
|
+
end
|
44
|
+
|
45
|
+
def purchase(money, currency ,ip, description)
|
46
|
+
commit('purchase',{
|
47
|
+
'command' => 'v',
|
48
|
+
'amount' => money,
|
49
|
+
'currency' => currency,
|
50
|
+
'client_ip_addr'=> ip,
|
51
|
+
'description' => description[0,125],
|
52
|
+
'language' => language
|
53
|
+
})
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_trans_result(ip,trans_id)
|
57
|
+
commit('result',{
|
58
|
+
'command' => 'c',
|
59
|
+
'trans_id' => trans_id,
|
60
|
+
'client_ip_addr'=> ip
|
61
|
+
})
|
62
|
+
end
|
63
|
+
|
64
|
+
def reverse(trans_id, amount)
|
65
|
+
commit('reverse',{
|
66
|
+
'command' => 'r',
|
67
|
+
'trans_id' => trans_id,
|
68
|
+
'amount' => amount
|
69
|
+
})
|
70
|
+
end
|
71
|
+
|
72
|
+
def close_day
|
73
|
+
commit('close',{
|
74
|
+
'command' => 'b'
|
75
|
+
})
|
76
|
+
end
|
77
|
+
|
78
|
+
def go_out
|
79
|
+
raise I18n.t('fd.no_trans_id') unless @trans_id
|
80
|
+
url = get_domain + "/ecomm/ClientHandler?trans_id=#{CGI.escape @trans_id}"
|
81
|
+
url
|
82
|
+
end
|
83
|
+
|
84
|
+
# log to default logger and if possible to payment logger
|
85
|
+
def log severity, message
|
86
|
+
@logger.send(severity,message)
|
87
|
+
@options[:payment].log(severity,message) if @options[:payment].respond_to?(:log)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def language
|
93
|
+
I18n.locale.to_s.sub('-','_').downcase
|
94
|
+
end
|
95
|
+
|
96
|
+
def test?
|
97
|
+
ActiveMerchant::Billing::Base.mode == :test
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_domain
|
101
|
+
test? ? TEST_DOMAIN : LIVE_DOMAIN
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse(body)
|
105
|
+
body.to_s.strip
|
106
|
+
end
|
107
|
+
|
108
|
+
# Return Response object
|
109
|
+
# Use the response:
|
110
|
+
# rs.success? - returns true|false
|
111
|
+
# rs.message - returns String with message
|
112
|
+
# rs.params - returns Hash with {'TRANSACTION_ID': 'jl2j4l2j423423=3-3423-4'} or {'RESULT_CODE' => '000'} ...
|
113
|
+
def commit(action,parameters)
|
114
|
+
url = get_domain + ":8443/ecomm/MerchantHandler"
|
115
|
+
data = post_data(action, parameters)
|
116
|
+
log :info, "#{url} + #{data}"
|
117
|
+
rs = parse(post(url, data))
|
118
|
+
log :info, rs
|
119
|
+
data = {}
|
120
|
+
rs.scan(/[0-9A-Z_]+:\s[^\s]+/){|item|
|
121
|
+
item =~ /([0-9A-Z_]+):\s(.+)/
|
122
|
+
data[$1] = $2
|
123
|
+
}
|
124
|
+
case action
|
125
|
+
when /purchase|authorize/
|
126
|
+
@trans_id = data['TRANSACTION_ID']
|
127
|
+
Response.new(data['TRANSACTION_ID'],rs,data)
|
128
|
+
when /result|reverse|complete|close/
|
129
|
+
Response.new(data['RESULT'] == "OK",rs,data)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# this posts data to FirstData server
|
134
|
+
def post url, data, headers = {}
|
135
|
+
begin
|
136
|
+
ssl_post(url, data, headers)
|
137
|
+
rescue Exception => e
|
138
|
+
log :error, "#{e.to_s}\n\n#{$@.join("\n")}"
|
139
|
+
"ERROR POSTING DATA"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def pem_password
|
144
|
+
@options[:pem_password]
|
145
|
+
end
|
146
|
+
|
147
|
+
def ssl_strict
|
148
|
+
false
|
149
|
+
end
|
150
|
+
|
151
|
+
def post_data(action, parameters = {})
|
152
|
+
parameters.to_query
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.get_code_msg k
|
156
|
+
I18n.t("fd.code._#{k}", :default => I18n.t('fd.unknown_error'))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|