lipstick 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.document +5 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +67 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +24 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/lib/lipstick.rb +10 -0
- data/lib/lipstick/api/campaign_find_active_response.rb +12 -0
- data/lib/lipstick/api/campaign_view_response.rb +10 -0
- data/lib/lipstick/api/customer_find_active_product_response.rb +7 -0
- data/lib/lipstick/api/new_order_response.rb +17 -0
- data/lib/lipstick/api/order_find_response.rb +7 -0
- data/lib/lipstick/api/order_find_updated_response.rb +7 -0
- data/lib/lipstick/api/order_view_response.rb +65 -0
- data/lib/lipstick/api/response.rb +155 -0
- data/lib/lipstick/api/session.rb +193 -0
- data/lipstick.gemspec +76 -0
- data/test/helper.rb +81 -0
- data/test/test_lipstick.rb +186 -0
- data/test/test_order_view_response.rb +127 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ODY3NmJjZmI3ODJkODBmMzVmNmMzYjZiYzUxODg2YTg0YjAyYTA2Nw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MDYzZTM4ZWY1ODBkZmI4YjFiODQ2MmMyZmUzYTVjNTAyYzcwYTRjOA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZWY5ZmU4ODM5NGYyMjlhMWQzNDU4ZTg2MTYwZWFhZGI2M2NmZjljMTBkNzZj
|
10
|
+
YmUzNmY2ZDkwODQwY2I3YWMzNmQ5Zjc3OWM4OTE1Y2U0MDM4MmE1N2YyOGVi
|
11
|
+
ZDY5MzA3MmJlMWYyY2VhZjk2ZWZjZTA2ZGQ3NzFjNzY1MDIwMGQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NDNjMTlhYWJhOGYzYmE5NDkxOWY3MWZiYjkyNjZlNjAzMDZiZTIzMmRjOGE2
|
14
|
+
ODg3MmRmMTcxZWY2ODA5ODEyYTQ5Y2U5M2Q5NjQyNTMwMWQwYmUxNTdlNGJi
|
15
|
+
M2E4MGZiZDc5YjQzYjIzZTIxYWQ5NTY1MDk0ZGExNzZjYzdkNTU=
|
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "minitest", ">= 0"
|
10
|
+
gem "yard", "~> 0.7"
|
11
|
+
gem "rdoc", "~> 3.12"
|
12
|
+
gem "bundler", "~> 1.0"
|
13
|
+
gem "jeweler", "~> 2.0.1"
|
14
|
+
gem "simplecov", ">= 0"
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.3.6)
|
5
|
+
builder (3.2.2)
|
6
|
+
descendants_tracker (0.0.4)
|
7
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
8
|
+
docile (1.1.5)
|
9
|
+
faraday (0.9.0)
|
10
|
+
multipart-post (>= 1.2, < 3)
|
11
|
+
git (1.2.8)
|
12
|
+
github_api (0.12.2)
|
13
|
+
addressable (~> 2.3)
|
14
|
+
descendants_tracker (~> 0.0.4)
|
15
|
+
faraday (~> 0.8, < 0.10)
|
16
|
+
hashie (>= 3.3)
|
17
|
+
multi_json (>= 1.7.5, < 2.0)
|
18
|
+
nokogiri (~> 1.6.3)
|
19
|
+
oauth2
|
20
|
+
hashie (3.3.1)
|
21
|
+
highline (1.6.21)
|
22
|
+
jeweler (2.0.1)
|
23
|
+
builder
|
24
|
+
bundler (>= 1.0)
|
25
|
+
git (>= 1.2.5)
|
26
|
+
github_api
|
27
|
+
highline (>= 1.6.15)
|
28
|
+
nokogiri (>= 1.5.10)
|
29
|
+
rake
|
30
|
+
rdoc
|
31
|
+
json (1.8.1)
|
32
|
+
jwt (1.0.0)
|
33
|
+
mini_portile (0.6.1)
|
34
|
+
minitest (5.4.2)
|
35
|
+
multi_json (1.10.1)
|
36
|
+
multi_xml (0.5.5)
|
37
|
+
multipart-post (2.0.0)
|
38
|
+
nokogiri (1.6.4.1)
|
39
|
+
mini_portile (~> 0.6.0)
|
40
|
+
oauth2 (1.0.0)
|
41
|
+
faraday (>= 0.8, < 0.10)
|
42
|
+
jwt (~> 1.0)
|
43
|
+
multi_json (~> 1.3)
|
44
|
+
multi_xml (~> 0.5)
|
45
|
+
rack (~> 1.2)
|
46
|
+
rack (1.5.2)
|
47
|
+
rake (10.3.2)
|
48
|
+
rdoc (3.12.2)
|
49
|
+
json (~> 1.4)
|
50
|
+
simplecov (0.9.1)
|
51
|
+
docile (~> 1.1.0)
|
52
|
+
multi_json (~> 1.0)
|
53
|
+
simplecov-html (~> 0.8.0)
|
54
|
+
simplecov-html (0.8.0)
|
55
|
+
thread_safe (0.3.4)
|
56
|
+
yard (0.8.7.6)
|
57
|
+
|
58
|
+
PLATFORMS
|
59
|
+
ruby
|
60
|
+
|
61
|
+
DEPENDENCIES
|
62
|
+
bundler (~> 1.0)
|
63
|
+
jeweler (~> 2.0.1)
|
64
|
+
minitest
|
65
|
+
rdoc (~> 3.12)
|
66
|
+
simplecov
|
67
|
+
yard (~> 0.7)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2014 Piers Chambers and South Beach Skin Care, LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
= Lipstick
|
2
|
+
|
3
|
+
Unofficial ruby wrapper for the following Lime Light CRM APIs:
|
4
|
+
|
5
|
+
* {Membership API}[http://help.limelightcrm.com/entries/317874-Membership-API-Documentation]
|
6
|
+
* {Transaction API}[http://help.limelightcrm.com/entries/22934241-Transaction-API-Documentation]
|
7
|
+
|
8
|
+
Note this wrapper attempts to fix some of the inconsistencies in the underlying APIs.
|
9
|
+
|
10
|
+
To run the tests you will need your own Lime Light CRM account with a valid campaign and test payment method.
|
11
|
+
|
12
|
+
== Contributing to lipstick
|
13
|
+
|
14
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
15
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
16
|
+
* Fork the project.
|
17
|
+
* Start a feature/bugfix branch.
|
18
|
+
* Commit and push until you are happy with your contribution.
|
19
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
20
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
21
|
+
|
22
|
+
Copyright (c) 2014 Piers Chambers and South Beach Skin Care, LLC. See LICENSE.txt for
|
23
|
+
further details.
|
24
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
17
|
+
gem.name = "lipstick"
|
18
|
+
gem.homepage = "http://github.com/varyonic/lipstick"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Unofficial ruby wrapper for the Lime Light CRM APIs.}
|
21
|
+
gem.description = %Q{Unofficial ruby wrapper for the Lime Light CRM membership and transaction APIs}
|
22
|
+
gem.email = "piers@varyonic.com"
|
23
|
+
gem.authors = ["Piers Chambers"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Code coverage detail"
|
36
|
+
task :simplecov do
|
37
|
+
ENV['COVERAGE'] = "true"
|
38
|
+
Rake::Task['test'].execute
|
39
|
+
end
|
40
|
+
|
41
|
+
task :default => :test
|
42
|
+
|
43
|
+
require 'yard'
|
44
|
+
YARD::Rake::YardocTask.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0.pre
|
data/lib/lipstick.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'lipstick/api/session.rb'
|
3
|
+
require 'lipstick/api/response.rb'
|
4
|
+
require 'lipstick/api/campaign_view_response.rb'
|
5
|
+
require 'lipstick/api/campaign_find_active_response.rb'
|
6
|
+
require 'lipstick/api/customer_find_active_product_response.rb'
|
7
|
+
require 'lipstick/api/new_order_response.rb'
|
8
|
+
require 'lipstick/api/order_find_response.rb'
|
9
|
+
require 'lipstick/api/order_find_updated_response.rb'
|
10
|
+
require 'lipstick/api/order_view_response.rb'
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Lipstick
|
2
|
+
module Api
|
3
|
+
class CampaignViewResponse < Response
|
4
|
+
csv_field :product_id, :product_name, :is_upsell
|
5
|
+
csv_field :shipping_id, :shipping_name, :shipping_description
|
6
|
+
csv_field :shipping_recurring_price, :shipping_initial_price
|
7
|
+
csv_field :countries, :payment_name
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Lipstick
|
2
|
+
module Api
|
3
|
+
class NewOrderResponse < Response
|
4
|
+
def initialize(fields)
|
5
|
+
fields.keys.each do |key|
|
6
|
+
fields[underscore(key.to_s).to_sym] = fields.delete(key)
|
7
|
+
end
|
8
|
+
if fields[:response_code] == '100'
|
9
|
+
fields[:test] = (fields[:test] == '1')
|
10
|
+
fields[:customer_id] = fields.delete(:customer_id).to_i
|
11
|
+
fields[:order_id] = fields.delete(:order_id).to_i
|
12
|
+
end
|
13
|
+
super(fields)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module Lipstick
|
6
|
+
module Api
|
7
|
+
class OrderViewResponse < Response
|
8
|
+
def initialize(fields)
|
9
|
+
fields.keys.each do |key|
|
10
|
+
fields[underscore(key.to_s).to_sym] = fields.delete(key)
|
11
|
+
end
|
12
|
+
fields[:customer] = OpenStruct.new(
|
13
|
+
id: fields.delete(:customer_id).to_i,
|
14
|
+
first_name: fields.delete(:first_name),
|
15
|
+
last_name: fields.delete(:last_name),
|
16
|
+
telephone: fields.delete(:customers_telephone),
|
17
|
+
email_address: fields.delete(:email_address)
|
18
|
+
)
|
19
|
+
fields[:shipping] = OpenStruct.new(
|
20
|
+
first_name: fields.delete(:shipping_first_name),
|
21
|
+
last_name: fields.delete(:shipping_last_name),
|
22
|
+
street_address: fields.delete(:shipping_street_address),
|
23
|
+
street_address2: fields.delete(:shipping_street_address2),
|
24
|
+
city: fields.delete(:shipping_city),
|
25
|
+
state: fields.delete(:shipping_state),
|
26
|
+
state_id: fields.delete(:shipping_state_id),
|
27
|
+
postcode: fields.delete(:shipping_postcode),
|
28
|
+
country: fields.delete(:shipping_country),
|
29
|
+
)
|
30
|
+
fields[:billing] = OpenStruct.new(
|
31
|
+
first_name: fields.delete(:billing_first_name),
|
32
|
+
last_name: fields.delete(:billing_last_name),
|
33
|
+
street_address: fields.delete(:billing_street_address),
|
34
|
+
street_address2: fields.delete(:billing_street_address2),
|
35
|
+
city: fields.delete(:billing_city),
|
36
|
+
state: fields.delete(:billing_state),
|
37
|
+
state_id: fields.delete(:billing_state_id),
|
38
|
+
postcode: fields.delete(:billing_postcode),
|
39
|
+
country: fields.delete(:billing_country),
|
40
|
+
)
|
41
|
+
fields[:order] = OpenStruct.new(
|
42
|
+
customer: fields[:customer],
|
43
|
+
ancestor_id: fields.delete(:ancestor_id).to_i,
|
44
|
+
child_id: fields.delete(:child_id).to_i,
|
45
|
+
status: fields.delete(:order_status).to_i,
|
46
|
+
is_recurring: fields.delete(:is_recurring)=='1',
|
47
|
+
shipping: fields[:shipping],
|
48
|
+
shipping_method_name: fields.delete(:shipping_method_name),
|
49
|
+
billing: fields[:billing],
|
50
|
+
created_at: DateTime.strptime(fields.delete(:time_stamp),'%Y-%m-%d %H:%M:%S'),
|
51
|
+
cc_number: fields.delete(:cc_number),
|
52
|
+
cc_expires: fields.delete(:cc_expires),
|
53
|
+
campaign_id: fields.delete(:campaign_id).to_i,
|
54
|
+
|
55
|
+
order_total: BigDecimal.new(fields.delete(:order_total)),
|
56
|
+
parent_id: fields.delete(:parent_id).to_i,
|
57
|
+
transaction_id: fields.delete(:transaction_id),
|
58
|
+
auth_id: fields.delete(:auth_id),
|
59
|
+
)
|
60
|
+
# PP.pp fields # TODO: parse remaining fields
|
61
|
+
super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module Lipstick
|
2
|
+
module Api
|
3
|
+
class Response
|
4
|
+
CODES = {
|
5
|
+
100 => 'Success',
|
6
|
+
200 => 'Invalid login credentials',
|
7
|
+
320 => 'Invalid Product Id',
|
8
|
+
321 => 'Existing Product Category Id Not Found',
|
9
|
+
322 => 'Invalid Category Id',
|
10
|
+
323 => 'Digital Delivery and Digital URL must be paired together and digital URL must be a valid URL',
|
11
|
+
324 => 'Invalid rebill_product or rebill_days value',
|
12
|
+
325 => 'Length Does Not Meet Minimum',
|
13
|
+
326 => 'URL is invalid',
|
14
|
+
327 => 'Payment Type Invalid',
|
15
|
+
328 => 'Expiration Date Invalid (Must be in the format of MMYY with no special characters)',
|
16
|
+
329 => 'Credit card must be either 15 or 16 digits numeric only',
|
17
|
+
330 => 'No Status Passed',
|
18
|
+
331 => 'Invalid Criteria',
|
19
|
+
332 => 'Start and end date are required',
|
20
|
+
333 => 'No Orders Found',
|
21
|
+
334 => 'Invalid Start Date format',
|
22
|
+
335 => 'Invalid End Date format',
|
23
|
+
336 => 'Wild Card Unsupported for this search criteria',
|
24
|
+
337 => 'Last 4 or First 4 must be 4 characters exactly',
|
25
|
+
338 => 'Timestamp invalid',
|
26
|
+
339 => 'Total Amount must be numeric and non-negative',
|
27
|
+
340 => 'Invalid country code',
|
28
|
+
341 => 'Invalid state code',
|
29
|
+
342 => 'Invalid Email Address',
|
30
|
+
343 => 'Data Element Has Same Value As Value Passed No Update done (Information ONLY, but still a success)',
|
31
|
+
344 => 'Invalid Number Format',
|
32
|
+
345 => 'Must be a 1 or 0. "1" being "On" or true. "0" being "Off" or false.',
|
33
|
+
346 => 'Invalid date format. Use mm/dd/yyyy',
|
34
|
+
347 => 'Invalid RMA reason',
|
35
|
+
348 => 'Order is already flagged as RMA',
|
36
|
+
349 => 'Order is not flagged as RMA',
|
37
|
+
350 => 'Invalid order Id supplied',
|
38
|
+
351 => 'Invalid status or action supplied',
|
39
|
+
352 => 'Uneven Order/Status/Action Pairing',
|
40
|
+
353 => 'Cannot stop recurring',
|
41
|
+
354 => 'Cannot reset recurring',
|
42
|
+
355 => 'Cannot start recurring',
|
43
|
+
356 => 'Credit card has expired',
|
44
|
+
360 => 'Cannot stop upsell recurring',
|
45
|
+
370 => 'Invalid amount supplied',
|
46
|
+
371 => 'Invalid keep recurring flag supplied',
|
47
|
+
372 => 'Refund amount exceeds current order total',
|
48
|
+
373 => 'Cannot void a fully refunded order',
|
49
|
+
374 => 'Cannot reprocess non-declined orders',
|
50
|
+
375 => 'Cannot blacklist test payment method',
|
51
|
+
376 => 'Invalid tracking number',
|
52
|
+
377 => 'Cannot ship pending orders',
|
53
|
+
378 => 'Order already shipped',
|
54
|
+
379 => 'Order is fully refunded/voided',
|
55
|
+
380 => 'Order is not valid for force bill',
|
56
|
+
381 => 'Customer is blacklisted',
|
57
|
+
382 => 'Invalid US state',
|
58
|
+
383 => 'All military states must have a city of either "APO", "FPO". or "DPO"',
|
59
|
+
384 => 'Invalid date mode',
|
60
|
+
385 => 'Invalid billing cycle filter',
|
61
|
+
386 => 'Order has already been returned',
|
62
|
+
387 => 'Invalid return reason',
|
63
|
+
388 => 'Rebill discount exceeds maximum for product',
|
64
|
+
389 => 'Refund amount must be greater than 0',
|
65
|
+
390 => 'Invalid number of days supplied',
|
66
|
+
400 => 'Invalid campaign Id supplied',
|
67
|
+
401 => 'Invalid subscription type',
|
68
|
+
402 => 'Subscription type 3 requires subscription week and subscription day values',
|
69
|
+
403 => 'Invalid subscription week value',
|
70
|
+
404 => 'Invalid subscription day value',
|
71
|
+
405 => 'Subscription type 3 required for subscription week and subscription day values',
|
72
|
+
406 => 'Rebill days must be a value between 1 and 31 for subscription type 2',
|
73
|
+
407 => 'Rebill days must be greater than 0 if subscription type is 1 or 2',
|
74
|
+
408 => 'Rebill days is invalid unless type is 1 or 2',
|
75
|
+
409 => 'Subscription type 0, other subscription fields invalid',
|
76
|
+
410 => 'API user: (api_username) has reached the limit of requests per minute: (limit) for method: (method_name)',
|
77
|
+
411 => 'Invalid subscription field',
|
78
|
+
412 => 'Missing subscription field',
|
79
|
+
413 => 'Product is not subscription based',
|
80
|
+
415 => 'Invalid subscription value',
|
81
|
+
420 => 'Campaign does not have fulfillment provider attached',
|
82
|
+
421 => 'This order was placed on hold',
|
83
|
+
422 => 'This order has not been sent to fulfillment yet',
|
84
|
+
423 => 'Invalid SKU',
|
85
|
+
424 => 'Fulfillment Error, provider did not specify',
|
86
|
+
425 => 'This order has been sent to fulfillment but has not been shipped',
|
87
|
+
500 => 'Invalid customer Id supplied',
|
88
|
+
600 => 'Invalid product Id supplied',
|
89
|
+
601 => 'Invalid prospect Id supplied',
|
90
|
+
602 => 'No prospects found',
|
91
|
+
603 => 'Invalid customer Id supplied',
|
92
|
+
604 => 'No customers found',
|
93
|
+
700 => 'Invalid method supplied',
|
94
|
+
701 => 'Action not permitted by gateway',
|
95
|
+
702 => 'Invalid gateway Id',
|
96
|
+
800 => 'Transaction was declined',
|
97
|
+
901 => 'Invalid return URL',
|
98
|
+
902 => 'Invalid cancel URL',
|
99
|
+
903 => 'Error retrieving alternative provider data',
|
100
|
+
904 => 'Campaign does not support an alternative payment provider',
|
101
|
+
905 => 'Product quantity/dynamic price does not match',
|
102
|
+
906 => 'Invalid quantity',
|
103
|
+
907 => 'Invalid shipping Id',
|
104
|
+
908 => 'Payment was already approved',
|
105
|
+
1000 => 'SSL is required'
|
106
|
+
}
|
107
|
+
attr_reader :code, :message
|
108
|
+
|
109
|
+
class << self
|
110
|
+
def csv_field(*args)
|
111
|
+
@csv_fields ||= []
|
112
|
+
@csv_fields = @csv_fields + args
|
113
|
+
end
|
114
|
+
def int_csv_field(*args)
|
115
|
+
@int_csv_fields ||= []
|
116
|
+
@int_csv_fields = @int_csv_fields + args
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def initialize(resp)
|
121
|
+
@code = resp.delete(:response_code).to_i
|
122
|
+
@message = CODES[@code]
|
123
|
+
|
124
|
+
if @code == 100
|
125
|
+
self.class.csv_field.each do |key|
|
126
|
+
resp[key] = CSV.parse_line(resp[key])
|
127
|
+
end
|
128
|
+
self.class.int_csv_field.each do |key|
|
129
|
+
resp[key] = CSV.parse_line(resp[key]).map(&:to_i)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
if !resp.empty?
|
134
|
+
resp.each do |att, val|
|
135
|
+
self.class.__send__(:attr_accessor, att)
|
136
|
+
self.__send__("#{att}=", val)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# partly copied from activesupport/inflector
|
142
|
+
def underscore(camel_cased_word)
|
143
|
+
word = camel_cased_word.to_s.dup
|
144
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
145
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
146
|
+
word.tr!("-", "_")
|
147
|
+
word.tr!("[", "_")
|
148
|
+
word.tr!("]", "")
|
149
|
+
word.downcase!
|
150
|
+
word
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module Lipstick
|
4
|
+
module Api
|
5
|
+
class Session
|
6
|
+
# API endpoint, eg. {https://example.com/admin}[https://example.com/admin]
|
7
|
+
attr_reader :base_url
|
8
|
+
|
9
|
+
# Hash containing :username, :password
|
10
|
+
attr_reader :credentials
|
11
|
+
|
12
|
+
# Used for logging request and response info.
|
13
|
+
attr_reader :logger
|
14
|
+
|
15
|
+
# Public: Initialize session.
|
16
|
+
#
|
17
|
+
# params - Hash
|
18
|
+
# * +:url+ - API endpoint, eg. {https://example.com/admin}[https://example.com/admin]
|
19
|
+
# * +:username+
|
20
|
+
# * +:password+
|
21
|
+
# * +:logger+ - Used for logging request and response info.
|
22
|
+
def initialize(params)
|
23
|
+
@base_url = params[:url] || raise("url not defined.")
|
24
|
+
raise("username missing") unless params[:username]
|
25
|
+
raise("password missing") unless params[:password]
|
26
|
+
@credentials = { username: params[:username], password: params[:password] }
|
27
|
+
@logger = params[:logger] || Logger.new('/dev/null')
|
28
|
+
end
|
29
|
+
|
30
|
+
# Find all active campaigns.
|
31
|
+
def campaign_find_active
|
32
|
+
call_api(:campaign_find_active)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Fetch details for a given campaign.
|
36
|
+
def campaign_view(campaign_id)
|
37
|
+
call_api(:campaign_view, campaign_id: campaign_id)
|
38
|
+
end
|
39
|
+
|
40
|
+
def customer_find_active_product(customer_id, campaign_id = nil)
|
41
|
+
params = { customer_id: customer_id }
|
42
|
+
params.merge!(campaign_id: campaign_id) if campaign_id
|
43
|
+
call_api(:customer_find_active_product, params)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Create order for new customer
|
47
|
+
def new_order(params)
|
48
|
+
camelcase_params!(params)
|
49
|
+
call_api('NewOrder', params)
|
50
|
+
end
|
51
|
+
|
52
|
+
def order_find(start_time, end_time, params = {})
|
53
|
+
params.merge!(
|
54
|
+
start_date: start_time.strftime('%m/%d/%Y'),
|
55
|
+
start_time: start_time.strftime('%H:%M:%S'),
|
56
|
+
end_date: end_time.strftime('%m/%d/%Y'),
|
57
|
+
end_time: end_time.strftime('%H:%M:%S'))
|
58
|
+
params[:campaign_id] ||= 'all'
|
59
|
+
params[:product_id] ||= 'all'
|
60
|
+
params[:criteria] ||= 'all'
|
61
|
+
call_api(:order_find, params)
|
62
|
+
end
|
63
|
+
|
64
|
+
def order_find_updated(start_time, end_time, params = {})
|
65
|
+
params.merge!(
|
66
|
+
start_date: start_time.strftime('%m/%d/%Y'),
|
67
|
+
start_time: start_time.strftime('%H:%M:%S'),
|
68
|
+
end_date: end_time.strftime('%m/%d/%Y'),
|
69
|
+
end_time: end_time.strftime('%H:%M:%S'))
|
70
|
+
params[:campaign_id] ||= 'all'
|
71
|
+
call_api(:order_find_updated, params)
|
72
|
+
end
|
73
|
+
|
74
|
+
def order_refund(order_id, amount, keep_recurring = true)
|
75
|
+
call_api(:order_refund,
|
76
|
+
order_id: order_id,
|
77
|
+
amount: amount.to_s,
|
78
|
+
keep_recurring: keep_recurring ? '1' : '0')
|
79
|
+
end
|
80
|
+
|
81
|
+
def order_update(order_id, action, value)
|
82
|
+
call_api(:order_update, order_ids: order_id, actions: action, values: value)
|
83
|
+
end
|
84
|
+
|
85
|
+
def order_update_recurring(order_id, status)
|
86
|
+
call_api(:order_update_recurring, order_id: order_id, status: status)
|
87
|
+
end
|
88
|
+
|
89
|
+
def order_view(order_id)
|
90
|
+
call_api(:order_view, order_id: order_id)
|
91
|
+
end
|
92
|
+
|
93
|
+
def order_void(order_id)
|
94
|
+
call_api(:order_void, order_id: order_id)
|
95
|
+
end
|
96
|
+
|
97
|
+
def shipping_method_find(campaign_id = 'all')
|
98
|
+
call_api(:shipping_method_find, campaign_id: campaign_id) do |fields|
|
99
|
+
if fields[:response_code] == '100'
|
100
|
+
[:shipping_ids].each do |key|
|
101
|
+
fields[key] = CSV.parse_line(fields[key]).map(&:to_i)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def validate_credentials
|
108
|
+
call_api(:validate_credentials)
|
109
|
+
end
|
110
|
+
|
111
|
+
# partly copied from activesupport/inflector
|
112
|
+
def underscore(camel_cased_word)
|
113
|
+
word = camel_cased_word.to_s.dup
|
114
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
115
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
116
|
+
word.tr!("-", "_")
|
117
|
+
word.tr!("[", "_")
|
118
|
+
word.tr!("]", "")
|
119
|
+
word.downcase!
|
120
|
+
word
|
121
|
+
end
|
122
|
+
|
123
|
+
def camelize(str)
|
124
|
+
return str.to_s unless str.to_s.include?(?_)
|
125
|
+
str.to_s.split("_").each {|s| s.capitalize! }.join
|
126
|
+
end
|
127
|
+
|
128
|
+
protected
|
129
|
+
# Munge params into style accepted by transaction API.
|
130
|
+
def camelcase_params!(params)
|
131
|
+
params.keys.select {|key| key.is_a?(Symbol) && key.to_s.include?(?_) }.each do |key|
|
132
|
+
camelcase_key = camelize(key)
|
133
|
+
camelcase_key[0] = camelcase_key[0].chr.downcase
|
134
|
+
params[camelcase_key] = params.delete(key)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def call_api(method, params = {}, &block)
|
139
|
+
params = params.merge(method: method)
|
140
|
+
logger.info "request = #{params.inspect}"
|
141
|
+
response = post_form(uri_for(method), params.merge(credentials))
|
142
|
+
logger.info "response = #{response.inspect}"
|
143
|
+
logger.debug "response.body = #{response.body}"
|
144
|
+
if block_given?
|
145
|
+
api_response = parse_response(response, &block)
|
146
|
+
else
|
147
|
+
fields = response_fields(response)
|
148
|
+
klassname = "#{camelize(method)}Response".to_sym
|
149
|
+
klass = Lipstick::Api.constants.include?(klassname) ? Lipstick::Api.const_get(klassname) : Lipstick::Api::Response
|
150
|
+
api_response = klass.new(fields)
|
151
|
+
end
|
152
|
+
logger.info "API response = #{api_response.inspect}"
|
153
|
+
api_response
|
154
|
+
end
|
155
|
+
|
156
|
+
def uri_for(method)
|
157
|
+
api = ['NewOrder'].include?(method) ? 'transact' : 'membership'
|
158
|
+
URI.parse("#{base_url}/#{api}.php")
|
159
|
+
end
|
160
|
+
|
161
|
+
def post_form(uri, params)
|
162
|
+
post = Net::HTTP::Post.new(uri.request_uri)
|
163
|
+
post.set_form_data(params)
|
164
|
+
request(uri, post)
|
165
|
+
end
|
166
|
+
|
167
|
+
def request(uri, request)
|
168
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
169
|
+
http.use_ssl = true
|
170
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
171
|
+
http.request(request)
|
172
|
+
end
|
173
|
+
|
174
|
+
def response_fields(response)
|
175
|
+
if response.body.include?(?=)
|
176
|
+
CGI::unescape(response.body).split('&').inject({}) do |h,kv|
|
177
|
+
k,v = kv.split('=')
|
178
|
+
k = k.to_sym if k.match(/\w/)
|
179
|
+
h.merge( k => v )
|
180
|
+
end
|
181
|
+
else
|
182
|
+
{ response_code: response.body }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def parse_response(response, &block)
|
187
|
+
fields = response_fields(response)
|
188
|
+
yield fields if block_given?
|
189
|
+
Lipstick::Api::Response.new(fields)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
data/lipstick.gemspec
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: lipstick 1.0.0.pre ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "lipstick"
|
9
|
+
s.version = "1.0.0.pre"
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.authors = ["Piers Chambers"]
|
14
|
+
s.date = "2014-11-28"
|
15
|
+
s.description = "Unofficial ruby wrapper for the Lime Light CRM membership and transaction APIs"
|
16
|
+
s.email = "piers@varyonic.com"
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE.txt",
|
19
|
+
"README.rdoc"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"lib/lipstick.rb",
|
30
|
+
"lib/lipstick/api/campaign_find_active_response.rb",
|
31
|
+
"lib/lipstick/api/campaign_view_response.rb",
|
32
|
+
"lib/lipstick/api/customer_find_active_product_response.rb",
|
33
|
+
"lib/lipstick/api/new_order_response.rb",
|
34
|
+
"lib/lipstick/api/order_find_response.rb",
|
35
|
+
"lib/lipstick/api/order_find_updated_response.rb",
|
36
|
+
"lib/lipstick/api/order_view_response.rb",
|
37
|
+
"lib/lipstick/api/response.rb",
|
38
|
+
"lib/lipstick/api/session.rb",
|
39
|
+
"lipstick.gemspec",
|
40
|
+
"test/helper.rb",
|
41
|
+
"test/test_lipstick.rb",
|
42
|
+
"test/test_order_view_response.rb"
|
43
|
+
]
|
44
|
+
s.homepage = "http://github.com/varyonic/lipstick"
|
45
|
+
s.licenses = ["MIT"]
|
46
|
+
s.rubygems_version = "2.2.2"
|
47
|
+
s.summary = "Unofficial ruby wrapper for the Lime Light CRM APIs."
|
48
|
+
|
49
|
+
if s.respond_to? :specification_version then
|
50
|
+
s.specification_version = 4
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_development_dependency(%q<minitest>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<yard>, ["~> 0.7"])
|
55
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
56
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
57
|
+
s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
|
58
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
61
|
+
s.add_dependency(%q<yard>, ["~> 0.7"])
|
62
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
63
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
64
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
65
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
69
|
+
s.add_dependency(%q<yard>, ["~> 0.7"])
|
70
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
71
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
72
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
73
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
module SimpleCov::Configuration
|
4
|
+
def clean_filters
|
5
|
+
@filters = []
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
SimpleCov.configure do
|
10
|
+
clean_filters
|
11
|
+
load_adapter 'test_frameworks'
|
12
|
+
end
|
13
|
+
|
14
|
+
ENV["COVERAGE"] && SimpleCov.start do
|
15
|
+
add_filter "/.rvm/"
|
16
|
+
end
|
17
|
+
require 'rubygems'
|
18
|
+
require 'bundler'
|
19
|
+
begin
|
20
|
+
Bundler.setup(:default, :development)
|
21
|
+
rescue Bundler::BundlerError => e
|
22
|
+
$stderr.puts e.message
|
23
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
24
|
+
exit e.status_code
|
25
|
+
end
|
26
|
+
require 'minitest/autorun'
|
27
|
+
require 'minitest/unit'
|
28
|
+
|
29
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
30
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
31
|
+
require 'lipstick'
|
32
|
+
|
33
|
+
require 'yaml'
|
34
|
+
|
35
|
+
module Lipstick
|
36
|
+
module Fixtures
|
37
|
+
HOME_DIR = RUBY_PLATFORM =~ /mswin32/ ? ENV['HOMEPATH'] : ENV['HOME'] unless defined?(HOME_DIR)
|
38
|
+
LOCAL_CREDENTIALS = File.join(HOME_DIR.to_s, '.lipstick/fixtures.yml') unless defined?(LOCAL_CREDENTIALS)
|
39
|
+
|
40
|
+
def address(prefix, options = {})
|
41
|
+
{
|
42
|
+
"#{prefix}Address1" => '1234 My Street',
|
43
|
+
"#{prefix}Address2" => 'Apt 1',
|
44
|
+
"#{prefix}City" => 'Ottawa',
|
45
|
+
"#{prefix}State" => 'ON',
|
46
|
+
"#{prefix}Zip" => 'K1C2N6',
|
47
|
+
"#{prefix}Country" => 'CA',
|
48
|
+
}.update(options)
|
49
|
+
end
|
50
|
+
|
51
|
+
def all_fixtures
|
52
|
+
@@fixtures ||= load_fixtures
|
53
|
+
end
|
54
|
+
|
55
|
+
def fixtures(key)
|
56
|
+
data = all_fixtures[key] || raise(StandardError, "No fixture data was found for '#{key}'")
|
57
|
+
data.dup
|
58
|
+
end
|
59
|
+
|
60
|
+
def load_fixtures
|
61
|
+
[LOCAL_CREDENTIALS].inject({}) do |credentials, file_name|
|
62
|
+
if File.exist?(file_name)
|
63
|
+
yaml_data = YAML.load(File.read(file_name))
|
64
|
+
credentials.merge!(symbolize_keys(yaml_data))
|
65
|
+
end
|
66
|
+
credentials
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def symbolize_keys(hash)
|
71
|
+
return hash unless hash.is_a?(Hash)
|
72
|
+
hash.each_with_object({}){|(k,v), h| h[k.to_sym] = symbolize_keys(v)}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def context(*args, &block)
|
78
|
+
describe(*args, &block)
|
79
|
+
end
|
80
|
+
|
81
|
+
Minitest.autorun
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
include Lipstick::Fixtures
|
4
|
+
|
5
|
+
describe 'Lipstick::Api::Session' do
|
6
|
+
before(:each) do
|
7
|
+
params = fixtures(:credentials)
|
8
|
+
params[:logger] = Logger.new(STDOUT) if ENV['DEBUG_LIPSTICK'] == 'true'
|
9
|
+
@session = Lipstick::Api::Session.new(params)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#campaign_find_active' do
|
13
|
+
it "finds all active campaigns" do
|
14
|
+
api_response = @session.campaign_find_active
|
15
|
+
assert api_response.code == 100, "unexpected response: #{api_response.inspect}"
|
16
|
+
assert api_response.campaign_id.is_a?(Array)
|
17
|
+
assert api_response.campaign_id[0].is_a?(Integer)
|
18
|
+
assert api_response.campaign_name.is_a?(Array)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#campaign_view' do
|
23
|
+
it "fetches attributes of a campaign" do
|
24
|
+
api_response = @session.campaign_find_active
|
25
|
+
campaign_id = api_response.campaign_id.sample
|
26
|
+
api_response = @session.campaign_view(campaign_id)
|
27
|
+
assert api_response.code == 100
|
28
|
+
assert api_response.product_id.is_a?(Array)
|
29
|
+
assert api_response.shipping_id.is_a?(Array)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "sample campaign" do
|
34
|
+
let (:order_params) {
|
35
|
+
{
|
36
|
+
campaign_id: @campaign_id,
|
37
|
+
product_id: @product_id,
|
38
|
+
first_name: 'Jim',
|
39
|
+
last_name: 'Smith',
|
40
|
+
phone: '(555)555-5555',
|
41
|
+
email: 'test@test.com', # jim.smith@example.com'
|
42
|
+
credit_card_type: @credit_card_type,
|
43
|
+
credit_card_number: fixtures(:test_card_number),
|
44
|
+
expiration_date: '1219',
|
45
|
+
"CVV" => '123',
|
46
|
+
tran_type: 'NewOrder',
|
47
|
+
shipping_id: @shipping_method_id,
|
48
|
+
ip_address: '127.0.0.1',
|
49
|
+
upsell_count: 0,
|
50
|
+
}.update(address('shipping')).update(address('billing'))
|
51
|
+
}
|
52
|
+
before (:all) do
|
53
|
+
api_response = @session.campaign_find_active
|
54
|
+
@campaign_id = api_response.campaign_id.sample
|
55
|
+
@campaign = @session.campaign_view(@campaign_id)
|
56
|
+
@product_id = @campaign.product_id.sample
|
57
|
+
@credit_card_type = @campaign.payment_name.sample
|
58
|
+
@shipping_method_id = @campaign.shipping_id.sample
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#new_order' do
|
62
|
+
it "creates order" do
|
63
|
+
api_response = @session.new_order(order_params)
|
64
|
+
assert api_response.code == 100
|
65
|
+
assert api_response.test, "Expected #{api_response.test.inspect} to be true"
|
66
|
+
assert api_response.customer_id.is_a?(Integer), "Expected #{api_response.customer_id.inspect} to be an integer"
|
67
|
+
assert api_response.order_id.is_a?(Integer)
|
68
|
+
assert api_response.transaction_id == 'Not Available'
|
69
|
+
assert api_response.auth_id == 'Not Available'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "existing order" do
|
74
|
+
before (:all) do
|
75
|
+
api_response = @session.new_order(order_params)
|
76
|
+
@order_id = api_response.order_id
|
77
|
+
@customer_id = api_response.customer_id
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#customer_find_active_product' do
|
81
|
+
it "fetches product ids" do
|
82
|
+
api_response = @session.customer_find_active_product(@customer_id)
|
83
|
+
assert api_response.code == 100
|
84
|
+
assert api_response.product_ids.is_a?(Array)
|
85
|
+
assert api_response.product_ids[0].is_a?(Integer)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#order_find' do
|
90
|
+
it "returns orders matching criteria" do
|
91
|
+
api_response = @session.order_find(Time.now - 120, Time.now)
|
92
|
+
assert api_response.code == 100, "unexpected response: #{api_response.inspect}"
|
93
|
+
assert api_response.order_ids.is_a?(Array)
|
94
|
+
assert api_response.order_ids[0].is_a?(Integer)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#order_refund' do
|
99
|
+
it "refunds the customer" do
|
100
|
+
api_response = @session.order_refund(@order_id, 0.01)
|
101
|
+
assert api_response.code == 100
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#order_view' do
|
106
|
+
it "returns details of an order" do
|
107
|
+
api_response = @session.order_view(@order_id)
|
108
|
+
assert api_response.code == 100, "unexpected response: #{api_response.inspect}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#order_update1' do
|
113
|
+
it 'posts chages to an order' do
|
114
|
+
api_response = @session.order_update(@order_id, :tracking_number, 'LC123456789012345678US')
|
115
|
+
assert api_response.code == 100
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "updated order" do
|
120
|
+
before (:each) do
|
121
|
+
api_response = @session.order_update(@order_id, :tracking_number, 'LC123456789012345678US')
|
122
|
+
end
|
123
|
+
|
124
|
+
describe '#order_find_updated' do
|
125
|
+
it "finds updated orders" do
|
126
|
+
api_response = @session.order_find_updated(Time.now - 128, Time.now)
|
127
|
+
assert api_response.code == 100, "unexpected response: #{api_response.inspect}"
|
128
|
+
assert api_response.order_ids.is_a?(Array)
|
129
|
+
assert api_response.order_ids[0].is_a?(Integer)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end # existing order
|
134
|
+
|
135
|
+
context "new order" do
|
136
|
+
before (:each) do
|
137
|
+
api_response = @session.new_order(order_params)
|
138
|
+
@new_order_id = api_response.order_id
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#order_update_recurring' do
|
142
|
+
it "cancels a new order" do
|
143
|
+
api_response = @session.order_update_recurring(@new_order_id,'stop')
|
144
|
+
assert api_response.code == 100, "unexpected response: #{api_response.inspect}"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe '#order_void' do
|
149
|
+
it "cancels a new order" do
|
150
|
+
api_response = @session.order_void(@new_order_id)
|
151
|
+
assert api_response.code == 100, "unexpected response: #{api_response.inspect}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end # sample campaign
|
156
|
+
|
157
|
+
describe '#shipping_method_find' do
|
158
|
+
it "finds shipping methods" do
|
159
|
+
api_response = @session.shipping_method_find
|
160
|
+
assert api_response.code == 100
|
161
|
+
assert api_response.shipping_ids.is_a?(Array)
|
162
|
+
assert api_response.shipping_ids[0].is_a?(Integer)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "validate_credentials" do
|
167
|
+
it "returns true if credentials valid" do
|
168
|
+
api_response = @session.validate_credentials
|
169
|
+
assert api_response.code == 100, "Credentials not valid."
|
170
|
+
end
|
171
|
+
|
172
|
+
it "returns false if credentials invalid" do
|
173
|
+
invalid_credentials = fixtures(:credentials).merge!(password: 'invalid')
|
174
|
+
@invalid_session = Lipstick::Api::Session.new(invalid_credentials)
|
175
|
+
api_response = @invalid_session.validate_credentials
|
176
|
+
assert api_response.code == 200, "Invalid credentials not detected."
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe '#underscore' do
|
181
|
+
it 'munges whatsit' do
|
182
|
+
foobar = @session.underscore('FooBar')
|
183
|
+
assert foobar == 'foo_bar', ">> #{foobar} <<"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe 'Lipstick::Api::OrderViewResponse' do
|
4
|
+
describe 'initialize' do
|
5
|
+
it 'parses the fields' do
|
6
|
+
fields = {
|
7
|
+
:response_code=>"100",
|
8
|
+
:ancestor_id=>"581006",
|
9
|
+
:customer_id=>"30346",
|
10
|
+
:parent_id=>"2081410",
|
11
|
+
:child_id=>nil,
|
12
|
+
:order_status=>"11",
|
13
|
+
:is_recurring=>"0",
|
14
|
+
:first_name=>"Jim",
|
15
|
+
:last_name=>"Smith",
|
16
|
+
:shipping_first_name=>"Jim",
|
17
|
+
:shipping_last_name=>"Smith",
|
18
|
+
:shipping_street_address=>"1234 My Street",
|
19
|
+
:shipping_street_address2=>"Apt 1",
|
20
|
+
:shipping_city=>"Ottawa",
|
21
|
+
:shipping_state=>"ON",
|
22
|
+
:shipping_state_id=>"ON",
|
23
|
+
:shipping_postcode=>"K1C2N6",
|
24
|
+
:shipping_country=>"CA",
|
25
|
+
:billing_first_name=>"Jim",
|
26
|
+
:billing_last_name=>"Smith",
|
27
|
+
:billing_street_address=>"1234 My Street",
|
28
|
+
:billing_street_address2=>"Apt 1",
|
29
|
+
:billing_city=>"Ottawa",
|
30
|
+
:billing_state=>"ON",
|
31
|
+
:billing_state_id=>"ON",
|
32
|
+
:billing_postcode=>"K1C2N6",
|
33
|
+
:billing_country=>"CA",
|
34
|
+
:customers_telephone=>"(555)555-5555",
|
35
|
+
:time_stamp=>"2014-11-26 16:34:33",
|
36
|
+
:recurring_date=>"0000-00-00",
|
37
|
+
:retry_date=>"N/A",
|
38
|
+
:cc_type=>"offline",
|
39
|
+
:cc_number=>"2822", # "N/A",
|
40
|
+
:check_account_last_4=>"N/A",
|
41
|
+
:check_routing_last_4=>"N/A",
|
42
|
+
:check_ssn_last_4=>"N/A",
|
43
|
+
:cc_expires=>"1219",
|
44
|
+
:prepaid_match=>"N/A",
|
45
|
+
:main_product_id=>"17",
|
46
|
+
:main_product_quantity=>"1",
|
47
|
+
:upsell_product_quantity=>nil,
|
48
|
+
:upsell_product_id=>nil,
|
49
|
+
:shipping_id=>"1",
|
50
|
+
:shipping_method_name=>"USPS",
|
51
|
+
:order_total=>"4.25",
|
52
|
+
:transaction_id=>"5804215901", # "Not Available",
|
53
|
+
:auth_id=>"02553Z", # "Not Available",
|
54
|
+
:tracking_number=>nil,
|
55
|
+
:on_hold=>"0",
|
56
|
+
:on_hold_by=>nil,
|
57
|
+
:hold_date=>nil,
|
58
|
+
:shipping_date=>"Not Shipped",
|
59
|
+
:email_address=>"test@test.com",
|
60
|
+
:gateway_id=>"1",
|
61
|
+
:preserve_gateway=>"0",
|
62
|
+
:amount_refunded_to_date=>"0.00",
|
63
|
+
:order_confirmed=>"NO_STATUS",
|
64
|
+
:order_confirmed_date=>nil,
|
65
|
+
:is_chargeback=>"0",
|
66
|
+
:is_fraud=>"0",
|
67
|
+
:is_rma=>"0",
|
68
|
+
:rma_number=>nil,
|
69
|
+
:rma_reason=>nil,
|
70
|
+
:ip_address=>"127.0.0.1",
|
71
|
+
:affiliate=>nil,
|
72
|
+
:sub_affiliate=>nil,
|
73
|
+
:decline_reason=>"N/A",
|
74
|
+
:campaign_id=>"23",
|
75
|
+
:order_sales_tax=>"0.00",
|
76
|
+
:order_sales_tax_amount=>"0.00",
|
77
|
+
:processor_id=>nil,
|
78
|
+
:created_by_user_name=>nil,
|
79
|
+
:created_by_employee_name=>nil,
|
80
|
+
:billing_cycle=>"0",
|
81
|
+
:click_id=>nil,
|
82
|
+
:product_qty_17=>"1",
|
83
|
+
:"products[0][product_id]"=>"1",
|
84
|
+
:"products[0][sku]"=>"094922807700",
|
85
|
+
:"products[0][price]"=>"0.00",
|
86
|
+
:"products[0][name]"=>"Lipstick",
|
87
|
+
:"products[0][on_hold]"=>"0",
|
88
|
+
:"products[0][is_recurring]"=>"1",
|
89
|
+
:"products[0][recurring_date]"=>"2014-12-26",
|
90
|
+
:"products[0][product_qty]"=>"1",
|
91
|
+
:"products[0][subscription_id]"=>"653cfc05e89438543a943731bbe6dbce",
|
92
|
+
:"products[0][subscription_type]"=>"Bill by cycle",
|
93
|
+
:"products[0][subscription_desc]"=>"Bills every 30 days"
|
94
|
+
}
|
95
|
+
response = Lipstick::Api::OrderViewResponse.new(fields)
|
96
|
+
customer = response.customer
|
97
|
+
assert_equal customer.id, 30346
|
98
|
+
assert_equal customer.first_name, "Jim"
|
99
|
+
assert_equal customer.last_name, "Smith"
|
100
|
+
assert_equal customer.telephone, "(555)555-5555"
|
101
|
+
assert_equal customer.email_address, "test@test.com"
|
102
|
+
|
103
|
+
order = response.order
|
104
|
+
assert_equal order.ancestor_id, 581006
|
105
|
+
# assert_equal order.customer.id, 30346
|
106
|
+
assert_equal order.parent_id, 2081410
|
107
|
+
assert_equal order.status, 11
|
108
|
+
|
109
|
+
assert_equal order.shipping.first_name, "Jim"
|
110
|
+
assert_equal order.shipping.last_name, "Smith"
|
111
|
+
assert_equal order.shipping.street_address, "1234 My Street"
|
112
|
+
assert_equal order.shipping.street_address2, "Apt 1"
|
113
|
+
assert_equal order.shipping.postcode, "K1C2N6"
|
114
|
+
assert_equal order.shipping.country, "CA"
|
115
|
+
assert_equal order.billing.marshal_dump, order.shipping.marshal_dump
|
116
|
+
assert_equal order.created_at, DateTime.new(2014,11,26,16,34,33)
|
117
|
+
assert_equal order.cc_number, "2822"
|
118
|
+
|
119
|
+
assert_equal order.cc_expires, "1219"
|
120
|
+
assert_equal order.shipping_method_name, "USPS"
|
121
|
+
assert_equal order.order_total, BigDecimal.new('4.25')
|
122
|
+
assert_equal order.transaction_id, '5804215901'
|
123
|
+
assert_equal order.auth_id, '02553Z'
|
124
|
+
assert_equal order.campaign_id, 23
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lipstick
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.pre
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Piers Chambers
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: yard
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rdoc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.12'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.12'
|
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.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jeweler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.0.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.0.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Unofficial ruby wrapper for the Lime Light CRM membership and transaction
|
98
|
+
APIs
|
99
|
+
email: piers@varyonic.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files:
|
103
|
+
- LICENSE.txt
|
104
|
+
- README.rdoc
|
105
|
+
files:
|
106
|
+
- .document
|
107
|
+
- Gemfile
|
108
|
+
- Gemfile.lock
|
109
|
+
- LICENSE.txt
|
110
|
+
- README.rdoc
|
111
|
+
- Rakefile
|
112
|
+
- VERSION
|
113
|
+
- lib/lipstick.rb
|
114
|
+
- lib/lipstick/api/campaign_find_active_response.rb
|
115
|
+
- lib/lipstick/api/campaign_view_response.rb
|
116
|
+
- lib/lipstick/api/customer_find_active_product_response.rb
|
117
|
+
- lib/lipstick/api/new_order_response.rb
|
118
|
+
- lib/lipstick/api/order_find_response.rb
|
119
|
+
- lib/lipstick/api/order_find_updated_response.rb
|
120
|
+
- lib/lipstick/api/order_view_response.rb
|
121
|
+
- lib/lipstick/api/response.rb
|
122
|
+
- lib/lipstick/api/session.rb
|
123
|
+
- lipstick.gemspec
|
124
|
+
- test/helper.rb
|
125
|
+
- test/test_lipstick.rb
|
126
|
+
- test/test_order_view_response.rb
|
127
|
+
homepage: http://github.com/varyonic/lipstick
|
128
|
+
licenses:
|
129
|
+
- MIT
|
130
|
+
metadata: {}
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ! '>='
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ! '>'
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: 1.3.1
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 2.2.2
|
148
|
+
signing_key:
|
149
|
+
specification_version: 4
|
150
|
+
summary: Unofficial ruby wrapper for the Lime Light CRM APIs.
|
151
|
+
test_files: []
|