payfast_za 0.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.
- checksums.yaml +7 -0
- data/config/initializers/payfast.rb +25 -0
- data/lib/generators/payfast/install_generator.rb +15 -0
- data/lib/payfast/attributes.rb +68 -0
- data/lib/payfast/client.rb +68 -0
- data/lib/payfast/config.rb +25 -0
- data/lib/payfast/errors.rb +15 -0
- data/lib/payfast/payment.rb +64 -0
- data/lib/payfast/payment_builder.rb +69 -0
- data/lib/payfast/payment_methods.rb +20 -0
- data/lib/payfast/signature_generator.rb +26 -0
- data/lib/payfast/version.rb +3 -0
- data/lib/payfast.rb +8 -0
- data/lib/payfast_za.rb +1 -0
- metadata +69 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b973493a34161391e4ab35b8edbe3fd177a5c8a8ecbbcfe5ab97a0de4d7fab06
|
|
4
|
+
data.tar.gz: 46012f1ad0e3b04a9a309d3d6db4a1ae0c783d27b48661543c9522d23b3d7060
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 076cb4e6505960d7b62afea1184ac6abda5dba0acb802d88ee6b95634b10f274e24b3f200a9012b59a1f563bf23aa6a870c16a8e266c8bb87389f8f1df6e54ba
|
|
7
|
+
data.tar.gz: 35828488a21633a5fadfd73b65b568351802fc6aa7b4ee31dab9580fb3a3742dc8b8c969a399e4848eb0a95506faccb737ee03dc522903fe1961b0412483810d
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#Use this hook to configure the parameters necessary for your payments to work
|
|
2
|
+
#Uncomment all the commented configs and use values applicable to your own application
|
|
3
|
+
#Payfast credentials can be obtained from the Payfast website
|
|
4
|
+
#Consider using rails credentials for sensitive secrets
|
|
5
|
+
Payfast.setup do |config|
|
|
6
|
+
|
|
7
|
+
# ==> Configure Payfast Secrets
|
|
8
|
+
#config.payment_url = Rails.application.credentials.payfast[:payment_url]
|
|
9
|
+
|
|
10
|
+
#config.merchant_id = Rails.application.credentials.payfast[:merchant_id]
|
|
11
|
+
#config.merchant_key = Rails.application.credentials.payfast[:merchant_key]
|
|
12
|
+
|
|
13
|
+
#config.passphrase = Rails.application.credentials.payfast[:passphrase]
|
|
14
|
+
|
|
15
|
+
# ==> Configure Payfast Urls
|
|
16
|
+
#config.return_url = Rails.application.credentials.payfast[:return_url]
|
|
17
|
+
#config.cancel_url = Rails.application.credentials.payfast[:cancel_url]
|
|
18
|
+
#config.notify_url = Rails.application.credentials.payfast[:notify_url]
|
|
19
|
+
|
|
20
|
+
# ==> Configure Payfast confirmation email, if you've set email confirmation to true
|
|
21
|
+
#config.email_confirmation_address = Rails.application.credentials.payfast[:email_confirmation_address]
|
|
22
|
+
|
|
23
|
+
# ==> Configure Payfast payment methods, if you only want to use a specific payment method
|
|
24
|
+
#config.payment_method = Rails.application.credentials.payfast[:payment_method]
|
|
25
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
|
|
3
|
+
module Payfast
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path("../../../..", __FILE__)
|
|
7
|
+
|
|
8
|
+
desc "Create Payfast configuration file"
|
|
9
|
+
|
|
10
|
+
def copy_config
|
|
11
|
+
directory "config/initializers", "config/initializers"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Payfast
|
|
2
|
+
class Attributes
|
|
3
|
+
REQUIRED_FIELDS = {
|
|
4
|
+
merchant: [
|
|
5
|
+
'merchant_id',
|
|
6
|
+
'merchant_key'
|
|
7
|
+
],
|
|
8
|
+
transaction: [
|
|
9
|
+
'amount',
|
|
10
|
+
'item_name'
|
|
11
|
+
]
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
OPTIONAL_FIELDS = {
|
|
15
|
+
merchant: [
|
|
16
|
+
'return_url',
|
|
17
|
+
'cancel_url',
|
|
18
|
+
'notify_url',
|
|
19
|
+
'fica_idnumber',
|
|
20
|
+
],
|
|
21
|
+
customer: [
|
|
22
|
+
'name_first',
|
|
23
|
+
'name_last',
|
|
24
|
+
'email_address',
|
|
25
|
+
'cell_number'
|
|
26
|
+
],
|
|
27
|
+
transaction: [
|
|
28
|
+
'm_payment_id',
|
|
29
|
+
'item_description',
|
|
30
|
+
'custom_int1',
|
|
31
|
+
'custom_int2',
|
|
32
|
+
'custom_int3',
|
|
33
|
+
'custom_int4',
|
|
34
|
+
'custom_int5',
|
|
35
|
+
'custom_str1',
|
|
36
|
+
'custom_str2',
|
|
37
|
+
'custom_str3',
|
|
38
|
+
'custom_str4',
|
|
39
|
+
'custom_str5'
|
|
40
|
+
],
|
|
41
|
+
transaction_options: [
|
|
42
|
+
'email_confirmation'
|
|
43
|
+
],
|
|
44
|
+
payment_methods: [
|
|
45
|
+
'payment_method'
|
|
46
|
+
]
|
|
47
|
+
}.freeze
|
|
48
|
+
|
|
49
|
+
PAYFAST_RESPONSE = [
|
|
50
|
+
'uuid'
|
|
51
|
+
],
|
|
52
|
+
|
|
53
|
+
HTTP_RESPONSE = [
|
|
54
|
+
'status',
|
|
55
|
+
'message'
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
class << self
|
|
59
|
+
def required_fields
|
|
60
|
+
REQUIRED_FIELDS.values.flatten
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def all_fields
|
|
64
|
+
(REQUIRED_FIELDS.values + OPTIONAL_FIELDS.values + PAYFAST_RESPONSE + HTTP_RESPONSE).flatten
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Payfast
|
|
5
|
+
class Client
|
|
6
|
+
attr_reader :payment_params
|
|
7
|
+
|
|
8
|
+
def self.create_payment(payment_params)
|
|
9
|
+
new(payment_params).create_payment
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(payment_params)
|
|
13
|
+
@payment_params = payment_params
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def create_payment
|
|
17
|
+
logger.info("[PAYFAST] STARTED POST to #{uri}")
|
|
18
|
+
|
|
19
|
+
response = Net::HTTP.post(uri, payment_data, headers)
|
|
20
|
+
|
|
21
|
+
if response.code =~ /^[4-5]/
|
|
22
|
+
raise Payfast::PaymentError, "[PAYFAST] Error: Failed POST to #{uri}. HTTP #{response.code} - #{response.message}"
|
|
23
|
+
else
|
|
24
|
+
logger.info("[PAYFAST] COMPLETED POST to #{uri} - status: #{response.code}, message: #{response.message}")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
endpoint_response = JSON.parse(response.body).transform_keys(&:to_sym)
|
|
28
|
+
|
|
29
|
+
response_hash = { uuid: endpoint_response[:uuid], status: response.code, message: response.message }
|
|
30
|
+
|
|
31
|
+
payment.new(payload.merge(response_hash))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def uri
|
|
37
|
+
URI(Payfast.payment_url)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def payment_data
|
|
41
|
+
URI.encode_www_form(payload.merge({signature: signature}))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def signature
|
|
45
|
+
Payfast::SignatureGenerator.new(payload).digest
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def payload
|
|
49
|
+
payment_builder.build(payment_params)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def headers
|
|
53
|
+
{ 'Content-Type' => 'application/x-www-form-urlencoded', 'Accept' => 'application/json' }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def logger
|
|
57
|
+
Payfast::Config.logger
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def payment_builder
|
|
61
|
+
Payfast::PaymentBuilder
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def payment
|
|
65
|
+
Payfast::Payment
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "logger"
|
|
2
|
+
|
|
3
|
+
module Payfast
|
|
4
|
+
class << self
|
|
5
|
+
attr_accessor :merchant_id, :merchant_key, :passphrase, :payment_url, :cancel_url, :notify_url, :return_url, :payment_method
|
|
6
|
+
|
|
7
|
+
def setup(&block)
|
|
8
|
+
instance_eval(&block)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Config
|
|
13
|
+
attr_writer :logger
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
def logger
|
|
17
|
+
@logger ||= Logger.new($stdout)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def client
|
|
21
|
+
Payfast::Client
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Payfast
|
|
2
|
+
class PaymentError < StandardError; end
|
|
3
|
+
|
|
4
|
+
class UnknownValueError < StandardError
|
|
5
|
+
def initialize(msg="Unknown. Refer to docs")
|
|
6
|
+
super
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class MissingAttributeError < StandardError
|
|
11
|
+
def initialize(msg="Required Attribute is missing. Refer to docs")
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module Payfast
|
|
2
|
+
class Payment
|
|
3
|
+
ATTRIBUTES = Payfast::Attributes.all_fields.map(&:to_sym)
|
|
4
|
+
|
|
5
|
+
attr_reader(*ATTRIBUTES)
|
|
6
|
+
|
|
7
|
+
def initialize(args = {})
|
|
8
|
+
args.each do |k,v|
|
|
9
|
+
run_validations(args)
|
|
10
|
+
variable_name = "@#{k}"
|
|
11
|
+
instance_variable_set(variable_name,v) unless v.nil?
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.create(args = {})
|
|
16
|
+
Payfast::Config.client.create_payment(args)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def success?
|
|
20
|
+
status == '200' && message == 'OK'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def failed?
|
|
24
|
+
!success?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def run_validations(args)
|
|
30
|
+
filter_attributes(args)
|
|
31
|
+
check_required_attributes(args)
|
|
32
|
+
check_payment_method(args)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def filter_attributes(args)
|
|
36
|
+
valid_attributes = Payfast::Attributes.all_fields.map(&:to_sym)
|
|
37
|
+
invalid_keys = args.keys - valid_attributes
|
|
38
|
+
|
|
39
|
+
unless invalid_keys.empty?
|
|
40
|
+
raise KeyError, "Unknown attribute(s): #{invalid_keys.join(', ')}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def check_required_attributes(args)
|
|
45
|
+
required_fields = Payfast::Attributes.required_fields.map(&:to_sym)
|
|
46
|
+
missing_fields = required_fields - args.keys
|
|
47
|
+
|
|
48
|
+
unless missing_fields.empty?
|
|
49
|
+
raise KeyError, "Missing required attribute(s): #{missing_fields.join(', ')}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def check_payment_method(args)
|
|
54
|
+
if args.key?(:payment_method)
|
|
55
|
+
payment_method = args[:payment_method]
|
|
56
|
+
accepted_methods = Payfast::PaymentMethods::ACCEPTED.keys.map(&:to_sym)
|
|
57
|
+
|
|
58
|
+
unless accepted_methods.include?(payment_method)
|
|
59
|
+
raise UnknownValueError, "Unknown payment method: #{payment_method}. Accepted methods are #{accepted_methods.join(', ')}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module Payfast
|
|
2
|
+
class PaymentBuilder
|
|
3
|
+
attr_reader :params
|
|
4
|
+
|
|
5
|
+
def self.build(params)
|
|
6
|
+
new(params).build
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(params)
|
|
10
|
+
@params = params
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def build
|
|
14
|
+
merchant_details.merge(customer_details, transaction_details, payment_methods).compact
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def merchant_details
|
|
20
|
+
{
|
|
21
|
+
merchant_id: Payfast.merchant_id,
|
|
22
|
+
merchant_key: Payfast.merchant_key,
|
|
23
|
+
return_url: Payfast.return_url,
|
|
24
|
+
cancel_url: Payfast.cancel_url,
|
|
25
|
+
notify_url: Payfast.notify_url,
|
|
26
|
+
fica_idnumber: params[:fica_idnumber]
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def customer_details
|
|
31
|
+
{
|
|
32
|
+
name_first: params[:first_name],
|
|
33
|
+
name_last: params[:last_name],
|
|
34
|
+
email_address: params[:email],
|
|
35
|
+
cell_number: params[:cell_number]
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def transaction_details
|
|
40
|
+
{
|
|
41
|
+
amount: sprintf('%.2f', params[:amount]),
|
|
42
|
+
item_name: params[:item_name],
|
|
43
|
+
m_payment_id: params[:payment_id],
|
|
44
|
+
item_description: params[:description],
|
|
45
|
+
custom_int1: params[:metadata_int1],
|
|
46
|
+
custom_int2: params[:metadata_int2],
|
|
47
|
+
custom_int3: params[:metadata_int3],
|
|
48
|
+
custom_int4: params[:metadata_int4],
|
|
49
|
+
custom_int5: params[:metadata_int5],
|
|
50
|
+
custom_str1: params[:metadata_str1],
|
|
51
|
+
custom_str2: params[:metadata_str2],
|
|
52
|
+
custom_str3: params[:metadata_str3],
|
|
53
|
+
custom_str4: params[:metadata_str4],
|
|
54
|
+
custom_str5: params[:metadata_str5]
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def transaction_options
|
|
59
|
+
{
|
|
60
|
+
email_confirmation: params[:email_confirmation],
|
|
61
|
+
confirmation_address: Payfast.email_confirmation_address
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def payment_methods
|
|
66
|
+
{ payment_method: Payfast.payment_method }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Payfast
|
|
2
|
+
class PaymentMethods
|
|
3
|
+
ACCEPTED = {
|
|
4
|
+
ef: 'EFT',
|
|
5
|
+
cc: 'Credit card',
|
|
6
|
+
dc: 'Debit card',
|
|
7
|
+
mp: 'Masterpass Scan to Pay',
|
|
8
|
+
mc: 'Mobicred',
|
|
9
|
+
sc: 'SCode',
|
|
10
|
+
ss: 'SnapScan',
|
|
11
|
+
zp: 'Zapper',
|
|
12
|
+
mt: 'MoreTyme',
|
|
13
|
+
rc: 'Store card',
|
|
14
|
+
mu: 'Mukuru',
|
|
15
|
+
ap: 'Apple Pay',
|
|
16
|
+
sp: 'Samsung Pay',
|
|
17
|
+
cp: 'Capitec Pay'
|
|
18
|
+
}.freeze
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'digest/md5'
|
|
3
|
+
|
|
4
|
+
module Payfast
|
|
5
|
+
class SignatureGenerator
|
|
6
|
+
attr_reader :payment_params
|
|
7
|
+
|
|
8
|
+
def initialize(payment_params)
|
|
9
|
+
@payment_params = payment_params
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def digest
|
|
13
|
+
Digest::MD5.hexdigest(encoded_params)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def encoded_params
|
|
19
|
+
URI.encode_www_form(payment_params.merge(passphrase: passphrase))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def passphrase
|
|
23
|
+
Payfast.passphrase
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/payfast.rb
ADDED
data/lib/payfast_za.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_relative "payfast"
|
metadata
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: payfast_za
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Blessing Muchaya
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2024-12-13 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 6.0.0
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 6.0.0
|
|
27
|
+
description:
|
|
28
|
+
email: btmuchaya@gmail.com
|
|
29
|
+
executables: []
|
|
30
|
+
extensions: []
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
files:
|
|
33
|
+
- config/initializers/payfast.rb
|
|
34
|
+
- lib/generators/payfast/install_generator.rb
|
|
35
|
+
- lib/payfast.rb
|
|
36
|
+
- lib/payfast/attributes.rb
|
|
37
|
+
- lib/payfast/client.rb
|
|
38
|
+
- lib/payfast/config.rb
|
|
39
|
+
- lib/payfast/errors.rb
|
|
40
|
+
- lib/payfast/payment.rb
|
|
41
|
+
- lib/payfast/payment_builder.rb
|
|
42
|
+
- lib/payfast/payment_methods.rb
|
|
43
|
+
- lib/payfast/signature_generator.rb
|
|
44
|
+
- lib/payfast/version.rb
|
|
45
|
+
- lib/payfast_za.rb
|
|
46
|
+
homepage: https://rubygems.org/gems/payfast_za
|
|
47
|
+
licenses:
|
|
48
|
+
- MIT
|
|
49
|
+
metadata: {}
|
|
50
|
+
post_install_message:
|
|
51
|
+
rdoc_options: []
|
|
52
|
+
require_paths:
|
|
53
|
+
- lib
|
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '0'
|
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '0'
|
|
64
|
+
requirements: []
|
|
65
|
+
rubygems_version: 3.4.10
|
|
66
|
+
signing_key:
|
|
67
|
+
specification_version: 4
|
|
68
|
+
summary: Payments with Payfast for Ruby on Rails apps in South Africa
|
|
69
|
+
test_files: []
|