lolita-first-data 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|