allinpay 0.1.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
+ SHA1:
3
+ metadata.gz: 19b0dd054a0b1c2d9649eee3914ce54e9aa5059f
4
+ data.tar.gz: f0bbb5215e09e201dd1c118264edaa9dd0c50c9a
5
+ SHA512:
6
+ metadata.gz: 9e31f2c609d3eea074782c21eda2abd9f158a118b1827797d4df3953bacdc9eb137f2b124e640c9eedb0cab1c27aae853445c79cf02c48488caf4b7893e7f82e
7
+ data.tar.gz: c08c10e3d229171b96e5c86a02de665c372cbaa2d1b737b787c6ccea4a96ae32839425e20749a6adb102d1903a31495d2fe30165a2370e91aa0d6b2b77048821
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.swp
11
+ *.swo
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in allinpay.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Allinpay
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/allinpay`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'allinpay'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install allinpay
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/allinpay.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/allinpay.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "allinpay/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "allinpay"
8
+ spec.version = Allinpay::VERSION
9
+ spec.authors = ["ye.li"]
10
+ spec.email = ["ye.li@mdslife.com"]
11
+
12
+ spec.summary = %q{Allinpay payment client}
13
+ spec.description = %q{Allinpay payment client}
14
+ spec.homepage = "https://github.com/yeeli/allinpay"
15
+
16
+ if spec.respond_to?(:metadata)
17
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
+ else
19
+ raise "RubyGems 2.0 or newer is required to protect against " \
20
+ "public gem pushes."
21
+ end
22
+
23
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
24
+ f.match(%r{^(test|spec|features)/})
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.15"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_dependency "faraday"
33
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "allinpay"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/allinpay.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'allinpay/version'
2
+ require 'active_support/core_ext/hash'
3
+ require 'active_support/core_ext/array'
4
+ require 'active_support/concern'
5
+ require 'faraday'
6
+
7
+ module Allinpay
8
+ # Your code goes here...
9
+ autoload :Client, 'allinpay/client'
10
+ autoload :Signature, 'allinpay/signature'
11
+ autoload :Service, 'allinpay/service'
12
+ autoload :Account, 'allinpay/account'
13
+ autoload :Payment, 'allinpay/payment'
14
+ autoload :Query, 'allinpay/query'
15
+
16
+ Client.include Account
17
+ Client.include Payment
18
+ Client.include Query
19
+ end
20
+
@@ -0,0 +1,50 @@
1
+ ###
2
+ # 财务接口
3
+ # 1. 账户充值
4
+ #
5
+ ###
6
+
7
+ module Allinpay
8
+ module Account
9
+ extend ActiveSupport::Concern
10
+ included do
11
+
12
+ # 询商户在通联的虚拟账户基本信息
13
+ #
14
+
15
+ def account(account_number = nil)
16
+ params = set_infomation('300000',{ REQTIME: timestamps, LEVEL: 9 })
17
+ params[:ACQUERYREQ] = { ACCTNO: account_number} if account_number
18
+ res = conn.request(params)
19
+ return result_wrap(:fail, res, params) if res["INFO"]["RET_CODE"] != "0000"
20
+ return result_wrap(:success, res, params)
21
+ end
22
+
23
+ # 账户充值接口
24
+ #
25
+ # Paramters:
26
+ #
27
+ # bank_account 银行账户
28
+ # amount 充值金额
29
+ # business_code 业务代码 默认 100005
30
+ # options
31
+ # summary 网银交易备注
32
+ # remark 商户交易备注
33
+
34
+ def charge(bank_account, amount, business_code = '19900', options = {})
35
+ params = set_infomation('300006',{ REQTIME: timestamps, LEVEL: 9 })
36
+ charge_info = {
37
+ BUSINESS_CODE: business_code,
38
+ BANKACCT: bank_account,
39
+ AMOUNT: amount
40
+ }
41
+ charge_info[:SUMMARY] = options[:summary] if options[:summary]
42
+ charge_info[:REMARK] = options[:remark] if options[:remark]
43
+ params[:CHARGEREQ] = charge_info
44
+ res = conn.request(params)
45
+ return result_wrap(:fail, res, params) if res["INFO"]["RET_CODE"] != "0000"
46
+ return result_wrap(:success, res, params)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,43 @@
1
+ module Allinpay
2
+ class Client
3
+ attr_accessor :merchant, :username, :password, :conn
4
+
5
+ class << self
6
+ attr_accessor :private_path, :public_path, :private_password
7
+ end
8
+
9
+ def initialize(options)
10
+ @merchant = options[:merchant]
11
+ @username = options[:username]
12
+ @password = options[:password]
13
+ env = options[:env] || 'development'
14
+ @conn = Allinpay::Service.connection(env, options)
15
+ end
16
+
17
+ private
18
+
19
+ def set_infomation(code, options = {})
20
+ info = {
21
+ TRX_CODE: code,
22
+ VERSION: '03',
23
+ DATA_TYPE: '2',
24
+ USER_NAME: username,
25
+ USER_PASS: password,
26
+ REQ_SN: req_sn
27
+ }.merge(options)
28
+ return { INFO: info }
29
+ end
30
+
31
+ def req_sn
32
+ merchant + timestamps + rand(1000).to_s.ljust(4, '0')
33
+ end
34
+
35
+ def timestamps
36
+ Time.now.strftime('%Y%m%d%H%M%S')
37
+ end
38
+
39
+ def result_wrap(status, data, request = nil)
40
+ return { "status" => status.to_s, "data" => data, "request" => request }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,68 @@
1
+ ###
2
+ # 交易接口
3
+ # 1. 单笔实时支付
4
+ #
5
+ ###
6
+
7
+
8
+ module Allinpay
9
+ module Payment
10
+ extend ActiveSupport::Concern
11
+ included do
12
+
13
+ # 通联支付单笔实时支付
14
+ def pay(tran, options = {})
15
+ params = set_infomation('100014')
16
+ tran_body = {
17
+ BUSINESS_CODE: options[:business_code] || '09900',
18
+ MERCHANT_ID: merchant,
19
+ SUBMIT_TIME: timestamps,
20
+ E_USER_CODE: 1,
21
+ BANK_CODE: tran[:bank_code],
22
+ ACCOUNT_TYPE: tran[:account_type],
23
+ ACCOUNT_NO: tran[:account_number],
24
+ ACCOUNT_NAME: tran[:account_name],
25
+ ACCOUNT_PROP: tran[:account_prop]
26
+ }
27
+ params[:TRANS] = tran_body
28
+ res = conn.request(params)
29
+ return result_wrap(:fail, res, params) if res_info["RET_CODE"] != "0000"
30
+ return result_wrap(:success, res, params)
31
+ end
32
+
33
+ # 通联支付批量付款
34
+ def batch_pay(trans, options = {})
35
+ params = set_infomation('100002', {LEVEL: 9})
36
+ details = []
37
+ index = 1
38
+ trans_sum = {
39
+ BUSINESS_CODE: options[:business_code] || '09900',
40
+ MERCHANT_ID: merchant,
41
+ SUBMIT_TIME: timestamps
42
+ }
43
+ trans_sum[:TOTAL_SUM] = trans.inject(0) do |sum, item|
44
+ sn = index.to_s.rjust(4, '0')
45
+ amount = (item[:amount].to_f * 100).to_i
46
+ details << {
47
+ SN: item[:number] || sn,
48
+ E_USER_CODE: 1,
49
+ BANK_CODE: item[:bank_code],
50
+ ACCOUNT_TYPE: item[:account_type],
51
+ ACCOUNT_NO: item[:account_number],
52
+ ACCOUNT_NAME: item[:account_name],
53
+ ACCOUNT_PROP: item[:account_prop],
54
+ AMOUNT: amount
55
+ }
56
+ index += 1
57
+ amount + sum
58
+ end
59
+ trans_sum[:TOTAL_ITEM] = index - 1
60
+ params[:BODY] = { TRANS_SUM: trans_sum, TRANS_DETAILS: details }
61
+ res = conn.request(params)
62
+ res_info = res["INFO"]
63
+ return result_wrap(:fail, res, params) if res_info["RET_CODE"] != "0000"
64
+ return result_wrap(:success, res, params)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,34 @@
1
+ ###
2
+ # 交易查询接
3
+ # 1.支付交易结果查询
4
+ #
5
+ ###
6
+
7
+
8
+ module Allinpay
9
+ module Query
10
+ extend ActiveSupport::Concern
11
+ included do
12
+
13
+ # 支付交易结果查询
14
+ #
15
+ # Paramters:
16
+ #
17
+ # sn: 交易序号
18
+ # options:
19
+
20
+ def query_batch_pay(sn, options = {})
21
+ params = set_infomation('200004')
22
+ tran_body = { MERCHANT_ID: merchant, QUERY_SN: sn }
23
+ rean_body[:TYPE] = options[:type] if options[:type]
24
+ rean_body[:STATUS] = options[:status] if options[:status]
25
+ rean_body[:START_DAY] = options[:start_day] if options[:start_day]
26
+ rean_body[:END_DAY] = options[:end_day] if options[:end_day]
27
+ params[:QTRANSREQ] = tran_body
28
+ res = conn.request(params)
29
+ return result_wrap(:fail, res) if res["INFO"]["RET_CODE"] != "0000"
30
+ return result_wrap(:success, res, params)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,64 @@
1
+ module Allinpay
2
+ module Service
3
+ def self.connection(env, options)
4
+ set_signature_infomation(options)
5
+ ssl_options = {}
6
+ if env.to_s == "development" || env.to_s == "test"
7
+ ssl_options = {verify: false}
8
+ end
9
+ klass = Class.new do
10
+ include Allinpay::Service
11
+ attr_accessor :gateway_url, :conn
12
+
13
+ def initialize(env, ssl_options)
14
+ @gateway_url = set_gateway_url(env)
15
+ @conn = Faraday.new gateway_url, ssl: ssl_options
16
+ end
17
+ end.new(env, ssl_options)
18
+ end
19
+
20
+ def request(params)
21
+ params[:INFO][:SIGNED_MSG] = Signature.generate(parse_xml(params)).unpack('H*').first
22
+ body = parse_xml(params)
23
+ response = conn.post do |req|
24
+ req.headers['Content-Type'] = 'text/xml'
25
+ req.body = body
26
+ end
27
+ return raise "HTTP Connection has error." if response.status != 200
28
+ result = response.body
29
+ result_xml = Hash.from_xml(result)
30
+ return raise "Signature verify failed." if !verify_signature?(result, result_xml)
31
+ return result_xml['AIPG']
32
+ end
33
+
34
+ private
35
+
36
+ def verify_signature?(res, result)
37
+ signed = result["AIPG"]["INFO"]["SIGNED_MSG"]
38
+ xml_body = res.encode('utf-8', 'gbk').gsub(/<SIGNED_MSG>.*<\/SIGNED_MSG>/, '')
39
+ Signature.verify?(xml_body.encode('gbk', 'utf-8'), [signed].pack("H*"))
40
+ end
41
+
42
+ def parse_xml(data, indent = 0)
43
+ data_xml = data.to_xml(root: 'AIPG', skip_types: true, dasherize: false, indent: indent).sub('UTF-8', 'GBK')
44
+ data_xml.encode! 'gbk','utf-8'
45
+ data_xml
46
+ end
47
+
48
+ def set_gateway_url(env)
49
+ if env.to_s == "development" || env.to_s == "test"
50
+ return 'https://113.108.182.3/aipg/ProcessServlet'
51
+ else
52
+ return 'https://tlt.allinpay.com/aipg/ProcessServlet'
53
+ end
54
+ end
55
+
56
+ def self.set_signature_infomation(options)
57
+ raise "Allinpay private key not exists" if !File.exists?(options[:private_path])
58
+ raise "Allinpay public key not exists" if !File.exists?(options[:public_path])
59
+ Allinpay::Client.private_path = options[:private_path]
60
+ Allinpay::Client.private_password = options[:private_password]
61
+ Allinpay::Client.public_path = options[:public_path]
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,19 @@
1
+ require 'openssl'
2
+
3
+ module Allinpay
4
+ class Signature
5
+ def self.generate(str)
6
+ private_file = File.open(Allinpay::Client.private_path)
7
+ private_key= OpenSSL::PKCS12.new(private_file, Allinpay::Client.private_password).key.export
8
+ rsa = OpenSSL::PKey::RSA.new private_key
9
+ rsa.sign("sha1", str.force_encoding("GBK"))
10
+ end
11
+
12
+ def self.verify?(str, sign)
13
+ public_file = File.open(Allinpay::Client.public_path)
14
+ public_key = OpenSSL::X509::Certificate.new(public_file).public_key.export
15
+ rsa = OpenSSL::PKey::RSA.new(public_key)
16
+ rsa.verify("sha1", sign, str)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Allinpay
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: allinpay
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ye.li
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Allinpay payment client
56
+ email:
57
+ - ye.li@mdslife.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - README.md
65
+ - Rakefile
66
+ - allinpay.gemspec
67
+ - bin/console
68
+ - bin/setup
69
+ - lib/allinpay.rb
70
+ - lib/allinpay/account.rb
71
+ - lib/allinpay/client.rb
72
+ - lib/allinpay/payment.rb
73
+ - lib/allinpay/query.rb
74
+ - lib/allinpay/service.rb
75
+ - lib/allinpay/signature.rb
76
+ - lib/allinpay/version.rb
77
+ homepage: https://github.com/yeeli/allinpay
78
+ licenses: []
79
+ metadata:
80
+ allowed_push_host: https://rubygems.org
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.6.12
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Allinpay payment client
101
+ test_files: []