xpost 0.1.1
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/.DS_Store +0 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +64 -0
- data/lib/xpost.rb +23 -0
- data/lib/xpost/authentication.rb +33 -0
- data/lib/xpost/configuration.rb +12 -0
- data/lib/xpost/models.rb +5 -0
- data/lib/xpost/models/address.rb +38 -0
- data/lib/xpost/models/item.rb +31 -0
- data/lib/xpost/models/order.rb +54 -0
- data/lib/xpost/orders.rb +96 -0
- data/lib/xpost/version.rb +3 -0
- data/spec/address_spec.rb +41 -0
- data/spec/factories/addresses.rb +39 -0
- data/spec/factories/items.rb +17 -0
- data/spec/factories/orders.rb +36 -0
- data/spec/helpers.rb +12 -0
- data/spec/item_spec.rb +47 -0
- data/spec/line_item_spec.rb +16 -0
- data/spec/orders/order_create_spec.rb +46 -0
- data/spec/orders/order_for_pickup_spec.rb +17 -0
- data/spec/orders/orders_find_spec.rb +27 -0
- data/spec/orders/orders_track_spec.rb +27 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/xpost_spec.rb +37 -0
- data/xpost.gemspec +28 -0
- metadata +156 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1528ac526307947878501064a5b31c5c128883cf
|
4
|
+
data.tar.gz: a3a71ecaa5c1e6d786ae24e84cef98793b0ffb2a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 380cd7435dd8e02ef74e2a3de907b6260d3a8c3731903fe9524c6b1909f5f40a0f04225ee55e11769460c224d4c1b1722a5bb5c94ac0b04f42cf849d18326e76
|
7
|
+
data.tar.gz: 49323931c9acd75d1f258dfa6f6f54f46b512991316b0c7c2fc88754e916ba5875c1fcec8b99efe6cedae5e6aade8dd1793e7156f850491ab58ac822d8cc4e37
|
data/.DS_Store
ADDED
Binary file
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 xpanse-ph
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
# xpost
|
4
|
+
|
5
|
+
A ruby gem for accessing the xpost API created by xpanse.
|
6
|
+
|
7
|
+
# Configuration
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# config/initializers/xpost.rb
|
11
|
+
|
12
|
+
Xpost.configure do |config|
|
13
|
+
config.api_key = 'your_api_key'
|
14
|
+
config.secret_key = 'your_secret_key'
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
# Authentication
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
api_key = "1234"
|
22
|
+
secret_key = "ABCD"
|
23
|
+
|
24
|
+
Xpost::Authentication.authenticate(api_key, secret_key)
|
25
|
+
|
26
|
+
# "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0IiwiaWF0IjoxNTI2MzgzMzE0LCJqdGkiOjE1MjYzODMzMTR9.iXbnbn7XRmrq2msAMEGyv8cTl2PWkpfP7EbztKNo00A"
|
27
|
+
```
|
28
|
+
|
29
|
+
# Order
|
30
|
+
|
31
|
+
|
32
|
+
### Order.find
|
33
|
+
|
34
|
+
Returns all order data.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
auth_token = "..."
|
38
|
+
tracking_number = "0076-1174-PSAT"
|
39
|
+
|
40
|
+
Xpost::Order.find(auth_token, tracking_number)
|
41
|
+
```
|
42
|
+
|
43
|
+
### Order.track
|
44
|
+
|
45
|
+
Returns the order events of a specific order.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
auth_token = "..."
|
49
|
+
tracking_number = "0076-1174-PSAT"
|
50
|
+
|
51
|
+
Xpost::Order.find(auth_token, tracking_number)
|
52
|
+
```
|
53
|
+
|
54
|
+
### Order Flow
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
Order.create(auth_token, options: order_options)
|
58
|
+
Order.confirm(auth_token, options/payment_reference_id)
|
59
|
+
Order.for_pickup(auth_token, pickup_address)
|
60
|
+
```
|
61
|
+
|
62
|
+
# Testing
|
63
|
+
|
64
|
+
Disclaimer: Most of the API calls still try to connect to an external HTTP connection.
|
data/lib/xpost.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Xpost
|
2
|
+
autoload :Configuration, 'xpost/configuration'
|
3
|
+
autoload :Authentication, 'xpost/authentication'
|
4
|
+
autoload :Orders, 'xpost/orders'
|
5
|
+
|
6
|
+
module Models
|
7
|
+
autoload :Address, 'xpost/models/address'
|
8
|
+
autoload :Item, 'xpost/models/item'
|
9
|
+
autoload :Order, 'xpost/models/order'
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configuration
|
17
|
+
@configuration ||= Configuration.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configure
|
21
|
+
yield configuration
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Xpost
|
6
|
+
module Authentication
|
7
|
+
def self.authenticate(api_key, secret_key)
|
8
|
+
payload = payload(api_key)
|
9
|
+
signature = signature(header, payload, secret_key)
|
10
|
+
token = "#{header}.#{payload}.#{signature}"
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def self.header
|
16
|
+
url_safe({ "alg" => "HS256", "typ" => "JWT"}.to_json)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.payload(api_key)
|
20
|
+
iat = jti = Time.now.to_i
|
21
|
+
url_safe({"sub": api_key, "iat": iat, "jti": jti }.to_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.signature(header, payload, secret_key, alg = 'HS256')
|
25
|
+
data = "#{header}.#{payload}"
|
26
|
+
url_safe(OpenSSL::HMAC.digest('SHA256', secret_key, data))
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.url_safe(data)
|
30
|
+
Base64.urlsafe_encode64(data).delete('=')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/xpost/models.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Xpost
|
5
|
+
module Models
|
6
|
+
class Address
|
7
|
+
include ActiveModel::Model
|
8
|
+
|
9
|
+
REQUIRED_ADDRESS_PARAMETERS = Set[:name, :shipment, :line_1, :city, :state, :postal_code, :country]
|
10
|
+
OPTIONAL_ADDRESS_PARAMETERS = Set[:company, :title, :email, :phone_number, :mobile_number, :fax_number,
|
11
|
+
:district, :line_2, :remarks]
|
12
|
+
|
13
|
+
attr_accessor :name, :shipment, :line_1, :city, :state, :postal_code, :country
|
14
|
+
attr_accessor :company, :title, :email, :phone_number, :mobile_number, :fax_number, :district, :line_2, :remarks
|
15
|
+
|
16
|
+
validates_presence_of :name, :shipment, :line_1, :city, :state, :postal_code, :country
|
17
|
+
|
18
|
+
def initialize(options = {})
|
19
|
+
@shipment = options[:shipment]
|
20
|
+
@name = options[:name]
|
21
|
+
@email = options[:email]
|
22
|
+
@phone_number = options[:phone_number]
|
23
|
+
@mobile_number = options[:mobile_number]
|
24
|
+
@fax_number = options[:fax_number]
|
25
|
+
@company = options[:company]
|
26
|
+
@title = options[:title]
|
27
|
+
@line_1 = options[:line_1]
|
28
|
+
@line_2 = options[:line_2]
|
29
|
+
@city = options[:city]
|
30
|
+
@district = options[:district]
|
31
|
+
@state = options[:state]
|
32
|
+
@postal_code = options[:postal_code]
|
33
|
+
@country = options[:country]
|
34
|
+
@remarks = options[:remarks]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Xpost
|
5
|
+
module Models
|
6
|
+
class Item
|
7
|
+
include ActiveModel::Model
|
8
|
+
|
9
|
+
ITEM_TYPES = Set[:product, :shipping, :tax, :fee, :insurance, :discount]
|
10
|
+
|
11
|
+
attr_accessor :type, :description, :amount, :quantity, :metadata
|
12
|
+
|
13
|
+
validates_presence_of :type, :description, :amount
|
14
|
+
validate :check_item_type
|
15
|
+
|
16
|
+
def initialize(options = {})
|
17
|
+
@type = options[:type]
|
18
|
+
@description = options[:description]
|
19
|
+
@amount = options[:amount]
|
20
|
+
@quantity = options[:quantity]
|
21
|
+
@metadata = options[:metadata]
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_item_type
|
25
|
+
if self.type.present? && !ITEM_TYPES.include?(self.type.to_sym)
|
26
|
+
errors.add(:type, "wrong item type")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Xpost
|
5
|
+
module Models
|
6
|
+
class Order
|
7
|
+
include ActiveModel::Model
|
8
|
+
|
9
|
+
CONFIRMABLE_PARAMETERS = Set[:status, :email, :buyer_name, :contact_number, :delivery_address, :items,
|
10
|
+
:shipment, :total, :currency, :payment_method, :payment_provider]
|
11
|
+
FOR_PICKUP_PARAMETERS = Set[:pickup_address, :pickup_at]
|
12
|
+
|
13
|
+
attr_accessor :email, :buyer_name, :contact_number
|
14
|
+
attr_accessor :total, :currency, :payment_method, :payment_provider
|
15
|
+
attr_accessor :delivery_address, :pickup_address
|
16
|
+
attr_accessor :status, :items, :shipment
|
17
|
+
|
18
|
+
validates_presence_of :email, :buyer_name, :contact_number
|
19
|
+
validates_presence_of :delivery_address
|
20
|
+
|
21
|
+
def initialize(options = {})
|
22
|
+
@status = options[:status]
|
23
|
+
@email = options[:email]
|
24
|
+
@buyer_name = options[:buyer_name]
|
25
|
+
@contact_number = options[:contact_number]
|
26
|
+
@delivery_address = options[:delivery_address]
|
27
|
+
@items = options[:items]
|
28
|
+
@shipment = options[:shipment]
|
29
|
+
@total = options[:total]
|
30
|
+
@currency = options[:currency]
|
31
|
+
@payment_method = options[:payment_method]
|
32
|
+
@payment_provider = options[:payment_provider]
|
33
|
+
@pickup_address = options[:pickup_address]
|
34
|
+
@pickup_at = options[:pickup_at]
|
35
|
+
end
|
36
|
+
|
37
|
+
def confirmable?
|
38
|
+
self.valid? && self.delivery_address.present?
|
39
|
+
end
|
40
|
+
|
41
|
+
# https://docs.quadx.xyz/#5f38afd0-66bb-468f-ab4e-993d4745a257
|
42
|
+
# Sets the order status to canceled. An order can be canceled provided they have not passed the cutoff date and time as specified in the contract.
|
43
|
+
def cancellable?
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
# https://docs.quadx.xyz/#c831dc25-2de4-36c5-c321-8e9db0fc2105
|
48
|
+
# The following fields can be updated provided they have not passed the cutoff date and time as specified in the contract.
|
49
|
+
def updatable?
|
50
|
+
true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/xpost/orders.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'set'
|
3
|
+
require 'typhoeus'
|
4
|
+
|
5
|
+
# Ideal Order.create flow
|
6
|
+
# order = Order.create({...})
|
7
|
+
# order.confirm / order.cancel
|
8
|
+
# order.for_pickup(pickup_address, pickup_date)
|
9
|
+
# order.update({...})
|
10
|
+
|
11
|
+
module Xpost
|
12
|
+
class Orders
|
13
|
+
# cant actually get all orders since its paginated
|
14
|
+
def self.all(auth_token)
|
15
|
+
all_orders_url = "orders"
|
16
|
+
|
17
|
+
get_url(all_orders_url, headers: auth_header(auth_token))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find(auth_token, tracking_number)
|
21
|
+
find_order_url = "orders/#{tracking_number}"
|
22
|
+
|
23
|
+
res = get_url(find_order_url, headers: auth_header(auth_token))
|
24
|
+
res = res[:message] == "Not Found" ? "Not Found" : res
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.track(auth_token, tracking_number)
|
28
|
+
track_order_url = "orders/#{tracking_number}"
|
29
|
+
|
30
|
+
res = get_url(track_order_url, headers: auth_header(auth_token))
|
31
|
+
res = res[:message] == "Not Found" ? "Not Found" : { timeline: res[:tat], events: res[:events] }
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.create(auth_token, options = {})
|
35
|
+
raise "Missing order data" if options[:order_data].empty?
|
36
|
+
|
37
|
+
create_order_url = "orders"
|
38
|
+
order_data = options[:order_data]
|
39
|
+
|
40
|
+
res = post_url(create_order_url, data: order_data, headers: auth_header(auth_token))
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.confirm(auth_token, tracking_number, payment_reference_id)
|
44
|
+
confirm_order_url = "orders/#{tracking_number}/confirm"
|
45
|
+
|
46
|
+
res = put_url(confirm_order_url, data: payment_reference_id, headers: auth_header(auth_token))
|
47
|
+
res = res[:message] == "Not Found" ? "Not Found" : res
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.for_pickup(auth_token, tracking_number, pickup_address)
|
51
|
+
pickup_address = Xpost::Models::Address.new(pickup_address)
|
52
|
+
for_pickup_url = "orders/#{tracking_number}/for-pickup"
|
53
|
+
|
54
|
+
raise "Invalid address" unless pickup_address.valid?
|
55
|
+
|
56
|
+
res = put_url(for_pickup_url, data: pickup_address, headers: auth_header(auth_token))
|
57
|
+
res = res[:message] == "Not Found" ? "Not Found" : res
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def self.base_url
|
63
|
+
Xpost.configuration.production_url
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.auth_header(auth_token)
|
67
|
+
{"Authorization" => "Bearer #{auth_token}"}
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.get_url(url, options = {})
|
71
|
+
req_url = "#{base_url}/#{url}"
|
72
|
+
req_options = {headers: options[:headers]}
|
73
|
+
|
74
|
+
res = Typhoeus::Request.get(req_url, req_options).body
|
75
|
+
res = JSON.parse(res, symbolize_names: true)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.post_url(url, options = {})
|
79
|
+
headers = { 'Content-Type': 'application/json' }.merge options[:headers]
|
80
|
+
req_url = "#{base_url}/#{url}"
|
81
|
+
req_options = { headers: headers, body: options[:data].to_json }
|
82
|
+
|
83
|
+
res = Typhoeus::Request.post(req_url, req_options).body
|
84
|
+
res = JSON.parse(res, symbolize_names: true)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.put_url(url, options = {})
|
88
|
+
headers = { 'Content-Type': 'application/json' }.merge options[:headers]
|
89
|
+
req_url = "#{base_url}/#{url}"
|
90
|
+
req_options = { headers: headers, body: options[:data].to_json }
|
91
|
+
|
92
|
+
res = Typhoeus::Request.put(req_url, req_options).body
|
93
|
+
res = JSON.parse(res, symbolize_names: true)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'Address' do
|
4
|
+
it 'works' do
|
5
|
+
address = build(:address)
|
6
|
+
|
7
|
+
expect(address.name).to eq 'Bobby Axelrod'
|
8
|
+
expect(address.line_1).to eq 'Axe Capital'
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'with required parameters' do
|
12
|
+
it 'is valid' do
|
13
|
+
address = build(:required_address)
|
14
|
+
expect(address).to be_valid
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'is invalid with missing parameters' do
|
18
|
+
address = build(:required_address, name: nil)
|
19
|
+
expect(address).not_to be_valid
|
20
|
+
expect(address.errors.messages).to eq(name: ["can't be blank"])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'with complete parameters' do
|
25
|
+
it 'is valid' do
|
26
|
+
address = build(:complete_address)
|
27
|
+
expect(address.valid?).to be true
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'is invalid without the required parameters' do
|
31
|
+
address = build(:complete_address, name: nil)
|
32
|
+
expect(address.valid?).to be false
|
33
|
+
expect(address.errors.messages).to eq(name: ["can't be blank"])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'is valid without the optional parameters' do
|
37
|
+
address = build(:complete_address, company: nil)
|
38
|
+
expect(address.valid?).to be true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
FactoryBot.define do
|
2
|
+
factory :address, class: Xpost::Models::Address do
|
3
|
+
name "Bobby Axelrod"
|
4
|
+
line_1 "Axe Capital"
|
5
|
+
end
|
6
|
+
|
7
|
+
factory :required_address, class: Xpost::Models::Address do
|
8
|
+
name "Bobby Axelrod"
|
9
|
+
shipment "small-pouch"
|
10
|
+
line_1 "855 Sixth Avenue"
|
11
|
+
city "New York"
|
12
|
+
state "NY"
|
13
|
+
postal_code 10001
|
14
|
+
country "US"
|
15
|
+
|
16
|
+
initialize_with { new(attributes) }
|
17
|
+
end
|
18
|
+
|
19
|
+
factory :complete_address, class: Xpost::Models::Address do
|
20
|
+
name "Bobby Axelrod"
|
21
|
+
shipment "small-pouch"
|
22
|
+
line_1 "855 Sixth Avenue"
|
23
|
+
city "New York"
|
24
|
+
state "NY"
|
25
|
+
postal_code 10001
|
26
|
+
country "US"
|
27
|
+
company "Axe Capital"
|
28
|
+
title "CEO"
|
29
|
+
email "bobby@axe.com"
|
30
|
+
phone_number "12345678"
|
31
|
+
mobile_number "091712345678"
|
32
|
+
fax_number "12345678"
|
33
|
+
district "Manhattan"
|
34
|
+
line_2 "5th floor"
|
35
|
+
remarks "Send ASAP"
|
36
|
+
|
37
|
+
initialize_with { new(attributes) }
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
FactoryBot.define do
|
2
|
+
factory :product_item, class: Xpost::Models::Item do
|
3
|
+
type "product"
|
4
|
+
description "orange shirt"
|
5
|
+
amount 1200
|
6
|
+
initialize_with { new(attributes) }
|
7
|
+
end
|
8
|
+
|
9
|
+
factory :complete_product_item, class: Xpost::Models::Item do
|
10
|
+
type "product"
|
11
|
+
description "red shirt"
|
12
|
+
amount 1000
|
13
|
+
quantity 1
|
14
|
+
metadata "Small"
|
15
|
+
initialize_with { new(attributes) }
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
FactoryBot.define do
|
2
|
+
factory :order, class: Xpost::Models::Order do
|
3
|
+
email "john@me.com"
|
4
|
+
buyer_name "John Doe"
|
5
|
+
contact_number "+6391712345678"
|
6
|
+
|
7
|
+
total 1500
|
8
|
+
currency "PHP"
|
9
|
+
payment_method "cod"
|
10
|
+
payment_provider "lbcx"
|
11
|
+
|
12
|
+
items { [build(:complete_product_item)] }
|
13
|
+
delivery_address { build(:complete_address) }
|
14
|
+
end
|
15
|
+
|
16
|
+
factory :cod_order, class: Xpost::Models::Order do
|
17
|
+
email "john@me.com"
|
18
|
+
buyer_name "John Doe"
|
19
|
+
contact_number "+6391712345678"
|
20
|
+
|
21
|
+
total 1500
|
22
|
+
currency "PHP"
|
23
|
+
payment_method "cod"
|
24
|
+
payment_provider "lbcx"
|
25
|
+
|
26
|
+
items { [build(:complete_product_item)] }
|
27
|
+
delivery_address { build(:complete_address) }
|
28
|
+
end
|
29
|
+
|
30
|
+
# factory :confirmable_order, class: Xpost::Models::Order do
|
31
|
+
# end
|
32
|
+
|
33
|
+
# factory :for_pickup_order, class: Xpost::Models::Order do
|
34
|
+
# end
|
35
|
+
|
36
|
+
end
|
data/spec/helpers.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Helpers
|
2
|
+
def auth_token
|
3
|
+
Xpost.configure do |config|
|
4
|
+
config.api_key = 'api_key'
|
5
|
+
config.secret_key = 'secret_key'
|
6
|
+
config.staging_url = "https://api.staging.lbcx.ph/v1"
|
7
|
+
config.production_url = "https://api.staging.lbcx.ph/v1"
|
8
|
+
end
|
9
|
+
|
10
|
+
auth_token = Xpost::Authentication.authenticate(Xpost.configuration.api_key, Xpost.configuration.secret_key)
|
11
|
+
end
|
12
|
+
end
|
data/spec/item_spec.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'Item' do
|
4
|
+
it 'works' do
|
5
|
+
item = build(:product_item)
|
6
|
+
|
7
|
+
expect(item).to be_valid
|
8
|
+
expect(item.type).to eq "product"
|
9
|
+
expect(item.description).to eq "orange shirt"
|
10
|
+
expect(item.amount).to eq 1200
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'requires a valid item_type' do
|
14
|
+
expect(build(:product_item, type: "product")).to be_valid
|
15
|
+
expect(build(:product_item, type: "productz")).not_to be_valid
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'with required parameters' do
|
19
|
+
it 'is valid' do
|
20
|
+
item = build(:product_item)
|
21
|
+
expect(item).to be_valid
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'is invalid with missing parameters' do
|
25
|
+
item = build(:product_item, amount: nil)
|
26
|
+
expect(item.valid?).to eq false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'with complete parameters' do
|
31
|
+
it 'is valid' do
|
32
|
+
item = build(:complete_product_item)
|
33
|
+
expect(item).to be_valid
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'is invalid without the required parameters' do
|
37
|
+
item = build(:complete_product_item, type: nil)
|
38
|
+
expect(item).not_to be_valid
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'is valid without the optional parameters' do
|
42
|
+
item = build(:complete_product_item, quantity: nil)
|
43
|
+
expect(item).to be_valid
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'LineItem' do
|
4
|
+
|
5
|
+
describe 'with require parameters' do
|
6
|
+
# it 'is valid' do
|
7
|
+
# line_item = build(:line_item)
|
8
|
+
# expect(line_item).to be_valid
|
9
|
+
# end
|
10
|
+
|
11
|
+
# it 'is invalid with missing parameters' do
|
12
|
+
# line_item = build(:line_item, type: nil)
|
13
|
+
# expect(line_item).not_to be_valid
|
14
|
+
# end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe "Orders.create" do
|
5
|
+
before(:each) do
|
6
|
+
@order = build(:order)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'requires a delivery address' do
|
10
|
+
order_without_delivery_address = build(:order, delivery_address: nil)
|
11
|
+
order_with_delivery_address = build(:order)
|
12
|
+
expect(order_without_delivery_address).not_to be_valid
|
13
|
+
expect(order_with_delivery_address).to be_valid
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'requires a payment method' do
|
17
|
+
expect(@order.payment_method).to be_present
|
18
|
+
expect(@order.payment_provider).to be_present
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'requires at least one product in line items' do
|
22
|
+
expect(@order.items.count).to eq 1
|
23
|
+
expect(@order.items.first.description).to eq "red shirt"
|
24
|
+
end
|
25
|
+
|
26
|
+
# TODO: Skipping calls for now to prevent multiple
|
27
|
+
# orders from being added to the staging site.
|
28
|
+
|
29
|
+
|
30
|
+
# it 'creates an order' do
|
31
|
+
# auth_token = Xpost::Authentication.local_auth
|
32
|
+
# @res = Xpost::Orders.create(auth_token, @order)
|
33
|
+
# expect(@res[:tracking_number]).to eq 200
|
34
|
+
# end
|
35
|
+
|
36
|
+
# describe 'returning a valid order object' do
|
37
|
+
# before(:each) do
|
38
|
+
# auth_token = Xpost::Authentication.local_auth
|
39
|
+
# @res = Xpost::Orders.create(auth_token, @order)
|
40
|
+
# end
|
41
|
+
|
42
|
+
# it 'has a tracking number'
|
43
|
+
# it 'has a status of confirming'
|
44
|
+
# end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe "@order.for_pickup" do
|
4
|
+
before do
|
5
|
+
Xpost.configure do |config|
|
6
|
+
config.api_key = 'api_key'
|
7
|
+
config.secret_key = 'secret_key'
|
8
|
+
config.staging_url = "https://api.staging.lbcx.ph/v1"
|
9
|
+
config.production_url = "https://api.staging.lbcx.ph/v1"
|
10
|
+
end
|
11
|
+
@auth_token = Xpost::Authentication.authenticate(Xpost.configuration.api_key, Xpost.configuration.secret_key)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'already has a delivery address'
|
15
|
+
it 'requires a pickup address'
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe "Orders.find" do
|
4
|
+
before do
|
5
|
+
Xpost.configure do |config|
|
6
|
+
config.api_key = 'api_key'
|
7
|
+
config.secret_key = 'secret_key'
|
8
|
+
config.staging_url = "https://api.staging.lbcx.ph/v1"
|
9
|
+
config.production_url = "https://api.staging.lbcx.ph/v1"
|
10
|
+
end
|
11
|
+
@auth_token = Xpost::Authentication.authenticate(Xpost.configuration.api_key, Xpost.configuration.secret_key)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns a valid order' do
|
15
|
+
tracking_number = "0076-1174-PSAT"
|
16
|
+
order = Xpost::Orders.find(@auth_token, tracking_number)
|
17
|
+
|
18
|
+
expect(order[:id]).to eq 761174
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'fails on an invalid order' do
|
22
|
+
tracking_number = "0076-1174-PSAZ"
|
23
|
+
order = Xpost::Orders.find(@auth_token, tracking_number)
|
24
|
+
|
25
|
+
expect(order).to eq "Not Found"
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe "Orders.track" do
|
4
|
+
before do
|
5
|
+
Xpost.configure do |config|
|
6
|
+
config.api_key = 'api_key'
|
7
|
+
config.secret_key = 'secret_key'
|
8
|
+
config.staging_url = "https://api.staging.lbcx.ph/v1"
|
9
|
+
config.production_url = "https://api.staging.lbcx.ph/v1"
|
10
|
+
end
|
11
|
+
@auth_token = Xpost::Authentication.authenticate(Xpost.configuration.api_key, Xpost.configuration.secret_key)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns a valid order' do
|
15
|
+
tracking_number = "0076-1174-PSAT"
|
16
|
+
order_events = Xpost::Orders.track(@auth_token, tracking_number)
|
17
|
+
|
18
|
+
expect(order_events[:timeline].count).to eq 5
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'fails on an invalid order' do
|
22
|
+
tracking_number = "0076-1174-PSAZ"
|
23
|
+
order_events = Xpost::Orders.track(@auth_token, tracking_number)
|
24
|
+
|
25
|
+
expect(order_events).to eq "Not Found"
|
26
|
+
end
|
27
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'factory_bot'
|
3
|
+
require 'xpost'
|
4
|
+
|
5
|
+
require 'helpers'
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
# Enable flags like --only-failures and --next-failure
|
9
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
10
|
+
|
11
|
+
# Disable RSpec exposing methods globally on `Module` and `main`
|
12
|
+
config.disable_monkey_patching!
|
13
|
+
|
14
|
+
config.expect_with :rspec do |c|
|
15
|
+
c.syntax = :expect
|
16
|
+
end
|
17
|
+
|
18
|
+
config.include Helpers
|
19
|
+
|
20
|
+
# factory_bot
|
21
|
+
config.include FactoryBot::Syntax::Methods
|
22
|
+
config.before(:suite) do
|
23
|
+
FactoryBot.find_definitions
|
24
|
+
end
|
25
|
+
end
|
data/spec/xpost_spec.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Xpost do
|
4
|
+
before do
|
5
|
+
@auth_token = auth_token
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'Configuration' do
|
9
|
+
it 'has keys' do
|
10
|
+
expect(Xpost.configuration.api_key).to eq 'api_key'
|
11
|
+
expect(Xpost.configuration.secret_key).to eq 'secret_key'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'has a staging url' do
|
15
|
+
expect(Xpost.configuration.staging_url).to eq "https://api.staging.lbcx.ph/v1"
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'has a production url' do
|
19
|
+
expect(Xpost.configuration.production_url).to eq "https://api.staging.lbcx.ph/v1"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: need a better way to verify validity of the auth_token
|
24
|
+
describe 'Authentication' do
|
25
|
+
describe '.authenticate' do
|
26
|
+
it 'returns an auth_token' do
|
27
|
+
api_key = Xpost.configuration.api_key
|
28
|
+
secret_key = Xpost.configuration.secret_key
|
29
|
+
auth_token = Xpost::Authentication.authenticate(api_key, secret_key)
|
30
|
+
|
31
|
+
expect(auth_token).to_not be nil
|
32
|
+
expect(@auth_token).to_not be nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
data/xpost.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'xpost/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'xpost'
|
7
|
+
s.version = Xpost::VERSION
|
8
|
+
s.authors = ["David Marquez"]
|
9
|
+
s.email = 'david@xpanse.ph'
|
10
|
+
|
11
|
+
s.summary = "xpost Ruby API"
|
12
|
+
s.date = '2018-04-27'
|
13
|
+
s.description = "A quick wrapped of the xpost API written by xpanse."
|
14
|
+
s.homepage = 'http://rubygems.org/gems/xpost'
|
15
|
+
s.license = 'MIT'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_dependency 'activemodel', '~> 5.2'
|
21
|
+
s.add_dependency 'typhoeus', '~> 1.3'
|
22
|
+
s.add_dependency 'factory_bot', '~> 4.8'
|
23
|
+
# s.add_dependency 'vcr', '~> 4.0'
|
24
|
+
|
25
|
+
s.add_development_dependency 'bundler', "~> 1.16"
|
26
|
+
s.add_development_dependency 'rake', "~> 12.3"
|
27
|
+
s.add_development_dependency 'rspec', '~> 3.2'
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xpost
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Marquez
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-04-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: typhoeus
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: factory_bot
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.8'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.16'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.16'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '12.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '12.3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.2'
|
97
|
+
description: A quick wrapped of the xpost API written by xpanse.
|
98
|
+
email: david@xpanse.ph
|
99
|
+
executables: []
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- ".DS_Store"
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rspec"
|
106
|
+
- Gemfile
|
107
|
+
- LICENSE
|
108
|
+
- README.md
|
109
|
+
- lib/xpost.rb
|
110
|
+
- lib/xpost/authentication.rb
|
111
|
+
- lib/xpost/configuration.rb
|
112
|
+
- lib/xpost/models.rb
|
113
|
+
- lib/xpost/models/address.rb
|
114
|
+
- lib/xpost/models/item.rb
|
115
|
+
- lib/xpost/models/order.rb
|
116
|
+
- lib/xpost/orders.rb
|
117
|
+
- lib/xpost/version.rb
|
118
|
+
- spec/address_spec.rb
|
119
|
+
- spec/factories/addresses.rb
|
120
|
+
- spec/factories/items.rb
|
121
|
+
- spec/factories/orders.rb
|
122
|
+
- spec/helpers.rb
|
123
|
+
- spec/item_spec.rb
|
124
|
+
- spec/line_item_spec.rb
|
125
|
+
- spec/orders/order_create_spec.rb
|
126
|
+
- spec/orders/order_for_pickup_spec.rb
|
127
|
+
- spec/orders/orders_find_spec.rb
|
128
|
+
- spec/orders/orders_track_spec.rb
|
129
|
+
- spec/spec_helper.rb
|
130
|
+
- spec/xpost_spec.rb
|
131
|
+
- xpost.gemspec
|
132
|
+
homepage: http://rubygems.org/gems/xpost
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 2.6.14
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: xpost Ruby API
|
156
|
+
test_files: []
|