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 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
@@ -0,0 +1,3 @@
1
+ module Payfast
2
+ VERSION = '0.0.0'
3
+ end
data/lib/payfast.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "payfast/attributes"
2
+ require "payfast/client"
3
+ require "payfast/errors"
4
+ require "payfast/config"
5
+ require "payfast/payment_builder"
6
+ require "payfast/payment_methods"
7
+ require "payfast/payment"
8
+ require "payfast/signature_generator"
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: []