shake-the-counter 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7d4c43147c4fc10e9442d0b8e34f64ae051346a1
4
+ data.tar.gz: 6052a23736eda219a03a32310fe727406025cf81
5
+ SHA512:
6
+ metadata.gz: 0ed578dc0eb0c2cb5f8ad9543b9801b6fae299ead58be2d920118b7b1ddb73a6a3f752b66dbd28aad92b1cbd79396ca77e7e6073e97c8f3e25171c91ddeeec83
7
+ data.tar.gz: 210a8009568c88480e15f24dccc89292f8758d126a3deb38a9de68dfbfe27fe0e87c7c9039057c31d8480652e8de1eb0590c040284debc3a941db571d6bb56be
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.3
5
+ before_install: gem install bundler -v 1.16.1
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 shake_the_counter.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ shake-the-counter (0.1.0)
5
+ json
6
+ rest-client
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ diff-lcs (1.3)
12
+ domain_name (0.5.20170404)
13
+ unf (>= 0.0.5, < 1.0.0)
14
+ http-cookie (1.0.3)
15
+ domain_name (~> 0.5)
16
+ json (2.1.0)
17
+ mime-types (3.1)
18
+ mime-types-data (~> 3.2015)
19
+ mime-types-data (3.2016.0521)
20
+ netrc (0.11.0)
21
+ rake (10.5.0)
22
+ rest-client (2.0.2)
23
+ http-cookie (>= 1.0.2, < 2.0)
24
+ mime-types (>= 1.16, < 4.0)
25
+ netrc (~> 0.8)
26
+ rspec (3.7.0)
27
+ rspec-core (~> 3.7.0)
28
+ rspec-expectations (~> 3.7.0)
29
+ rspec-mocks (~> 3.7.0)
30
+ rspec-core (3.7.1)
31
+ rspec-support (~> 3.7.0)
32
+ rspec-expectations (3.7.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.7.0)
35
+ rspec-mocks (3.7.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.7.0)
38
+ rspec-support (3.7.1)
39
+ unf (0.1.4)
40
+ unf_ext
41
+ unf_ext (0.0.7.5)
42
+
43
+ PLATFORMS
44
+ ruby
45
+
46
+ DEPENDENCIES
47
+ bundler (~> 1.16)
48
+ rake (~> 10.0)
49
+ rspec (~> 3.0)
50
+ shake-the-counter!
51
+
52
+ BUNDLED WITH
53
+ 1.16.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Henk Meijer
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # ShakeTheCounter
2
+ [![Gem Version](https://badge.fury.io/rb/shake-the-counter.svg)](https://badge.fury.io/rb/shake-the-counter)
3
+ [![Dependency Status](https://gemnasium.com/henkm/shake-the-counter.svg)](https://gemnasium.com/henkm/shake-the-counter)
4
+ [![Code Climate](https://codeclimate.com/github/henkm/shake-the-counter/badges/gpa.svg)](https://codeclimate.com/github/henkm/shake-the-counter)
5
+
6
+
7
+ This gem works as a simple Ruby wrapper for the Shake The Counter API. At this point, only a limited number of options is implemented. To be more precise: only enough functionality is implemented to:
8
+ - Authenticate
9
+ - Get events and details from a `Client`
10
+ - Make a reservation which is already marked as paid
11
+ - Receive barcodes in return
12
+ - Cancel a reservation
13
+
14
+ Instead of working with JSON, you work with Ruby Classes and intuitive methods.
15
+
16
+ **This gem communicates with the STC.Tickets TicketAPI Version 1.0**
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'shake-the-counter'
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install shake-the-counter
33
+
34
+ ## Original documentation
35
+ This gem is based on V1 of the API according to the documentation found here: [https://ticketstest.ticketcounter.nl/swagger/ui/index](https://ticketstest.ticketcounter.nl/swagger/ui/index).
36
+
37
+ This gem tries to be intuitive and Object Oriented. The naming conventions between the original API and this Ruby implementation are identical. So we have these classes:
38
+
39
+ `Client` > `Event` > `Performance` > `Section` > `PriceType`
40
+
41
+ Please note that only parts of the original API are 'native' implemented. For example: `@client.events.first` will return a `<ShakeTheCounter::Event>` object with native methods like `name` and `key`, but some fields are left out. You can access all the fields by requesting the `raw_data` attribte, which has the entire original API response stored as JSON.
42
+
43
+ ## Implemented functions
44
+ - [x] Configuration via simple config
45
+ - [x] Authentication
46
+ - [x] Work with a `Client` that is automatically authenticated
47
+ - [x] Get subsequent `events > performances > sections > price_types`
48
+ - [x] Make a reservation with minimal options
49
+ - [ ] Use coupons / discount codes
50
+ - [ ] Make reservations with extra options
51
+ - [ ] Events that require date or seat selecting
52
+ - [ ] Handle capacity (at this point, we assume that each ticket is always available with no limitation.
53
+ - [x] Cancel a reservation
54
+ - [ ] Functions from the Subscriptions API
55
+ - [ ] Functions from the Statistics API
56
+ - [ ] Functions from the Reseller API
57
+
58
+ ## Configuration
59
+
60
+ First, obtain an API key from Shake The Counter. Set it up like this:
61
+
62
+ To use this gem in a Rails project:
63
+ ```ruby
64
+ # config/development.rb
65
+ config.shake_the_counter.environment = "test"
66
+ config.shake_the_counter.refresh_token = "MY-REFRESH-TOKEN"
67
+ config.shake_the_counter.client_id = "123-my-client-id-xyz"
68
+ config.shake_the_counter.language_code = "nl-NL"
69
+ config.shake_the_counter.client_secret = "client-secret-goes-here"
70
+ ```
71
+
72
+
73
+ ## Full example
74
+ The example below follows the 'Normal flow to order tickets' as described in the `Getting started with the tickets Api` section of the API Documentation.
75
+
76
+ ```ruby
77
+ # setup a client
78
+ @client = ShakeTheCounter::Client.new # when called without arguments, credentials will come from configuration
79
+
80
+ # get a list if events for client
81
+ @events = @client.events
82
+ # => [<ShakeTheCounter::Event @name="Event 1" @key="xxx">, <ShakeTheCounter::Event @name="Event 2" @key="yyy">]
83
+
84
+ # get a list of performances
85
+ @performances = @events.first.performances
86
+
87
+ # get a list of sections
88
+ @sections = @perfomances.first.sections
89
+
90
+ # The above logic can also be a one-liner:
91
+ # @sections = @client.events.first.performances.first.sections
92
+
93
+ # get the prices for a givens section
94
+ @section = @sections.first
95
+ @price_types = @section.price_types
96
+ @price_type.first # => <ShakeTheCounter::PriceType @key="xxx" @name="Ticket" @price=6.0 [...]>
97
+
98
+ # make a reservation
99
+ price_type_list = [{
100
+ PriceKey: @price_types.first.price_key,
101
+ NrOfSeats: 2
102
+ }]
103
+ @reservation = @section.make_reservation(price_type_list: price_type_list, first_name: 'Joe', last_name: 'Sixpack', email: 'jack@example.com')
104
+ # => <ShakeTheCounter::Reservation>
105
+
106
+ # send a message that we started payment
107
+ @client.start_payment(@reservation.key)
108
+ # => true
109
+
110
+ # confirm the reservation
111
+ @client.confirm_reservation(reservation_key: @reservation.key, payment_method: 'API Test', amount_paid: 12.0)
112
+ # => [<ShakeTheCounter::Ticket @ticket_code="12345566">, <ShakeTheCounter::Ticket @ticket_code="12345567">]
113
+
114
+ ```
115
+
116
+ ## Development
117
+
118
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
119
+
120
+ 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).
121
+
122
+ ## Contributing
123
+
124
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/shake-the-counter.
125
+
126
+ ## License
127
+
128
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
129
+
130
+ This gem is made with love by the smart people at [Eskes Media B.V.](https://www.eskesmedia.nl) and [DagjeWeg.NL Tickets](https://www.dagjewegtickets.nl)
131
+ Shake The Counter is not involved with this project and has no affiliation with Eskes Media B.V.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "shake_the_counter"
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
@@ -0,0 +1,45 @@
1
+ # require dependencies
2
+ require 'rest_client'
3
+ require 'json'
4
+ require 'date'
5
+
6
+ # require gem files
7
+ require "shake_the_counter/version"
8
+ require "shake_the_counter/shake_the_counter_error"
9
+ require "shake_the_counter/config"
10
+ require "shake_the_counter/engine" if defined?(Rails) && Rails::VERSION::MAJOR.to_i >= 3
11
+
12
+ # require API parts
13
+ require "shake_the_counter/api"
14
+ require "shake_the_counter/authentication"
15
+ require "shake_the_counter/client"
16
+ require "shake_the_counter/event"
17
+ require "shake_the_counter/performance"
18
+ require "shake_the_counter/section"
19
+ require "shake_the_counter/price_type"
20
+ require "shake_the_counter/reservation"
21
+ require "shake_the_counter/contact"
22
+ require "shake_the_counter/ticket"
23
+
24
+
25
+ module ShakeTheCounter
26
+
27
+ # For testing purpose only: set the username and password
28
+ # in environment variables to make the tests pass with your test
29
+ # credentials.
30
+ def self.set_credentials_from_environment
31
+ Config.environment = :test
32
+ Config.verbose = true
33
+ end
34
+
35
+ end
36
+
37
+ class String
38
+ def underscore
39
+ self.gsub(/::/, '/').
40
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
41
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
42
+ tr("-", "_").
43
+ downcase
44
+ end
45
+ end
@@ -0,0 +1,86 @@
1
+ module ShakeTheCounter
2
+
3
+ # The communication layer implements all the methods available in the ShakeTheCounter API
4
+ # https://ticketstest.ticketcounter.nl/swagger/ui/index
5
+ class API
6
+
7
+ #
8
+ # Returns the API endpoint to use
9
+ #
10
+ # @return [type] [description]
11
+ def self.endpoint
12
+ if ShakeTheCounter::Config.environment.to_s == "test"
13
+ "https://apitest.shakethecounter.com"
14
+ else
15
+ "https://api.shakethecounter.com"
16
+ end
17
+ end
18
+
19
+
20
+ #
21
+ # Returns the complete API URL
22
+ #
23
+ def self.url(path)
24
+ # Don't change the path if it already is a full url
25
+ if path.include?('http')
26
+ return path
27
+ else
28
+ "#{endpoint}/api/v#{ShakeTheCounter::Config.version}/#{path}"
29
+ end
30
+ end
31
+
32
+ #
33
+ # Makes a HTTP POST call to the endpoint en returns the response
34
+ #
35
+ # @param request_body [type] [description]
36
+ # @param request_identifier [type] [description]
37
+ #
38
+ # @return OpenStruct object with nested methods.
39
+ def self.call(path, http_method: :get, body: {}, header: {})
40
+ values = body
41
+ unless header[:content_type]
42
+ if body && body != {}
43
+ header[:content_type] = "application/json"
44
+ else
45
+ # blank body requires no JSON
46
+ header[:content_type] = "application/x-www-form-urlencoded"
47
+ end
48
+ end
49
+
50
+ begin
51
+ if ShakeTheCounter::Config.verbose
52
+ puts "Calling #{http_method.upcase} to #{url(path)}"
53
+ puts "Header: #{header.to_json}"
54
+ puts "Body:"
55
+ puts values.to_json
56
+ end
57
+ if http_method == :post
58
+ response = RestClient.post url(path), values, header
59
+ else
60
+ response = RestClient.get url(path), header
61
+ end
62
+ rescue RestClient::ExceptionWithResponse => e
63
+ raise ShakeTheCounterError.new "#{e} #{e.response}"
64
+ end
65
+ if ShakeTheCounter::Config.verbose
66
+ puts "Result:\n#{response.inspect}"
67
+ end
68
+ if response.body != ''
69
+ object = JSON.parse(response.body)
70
+ else
71
+ object = response
72
+ end
73
+ return object
74
+ end
75
+
76
+ #
77
+ # Checks the connection
78
+ # GET /api/v1/ping
79
+ #
80
+ def self.ping
81
+ call("ping", http_method: :get)
82
+ end
83
+
84
+
85
+ end
86
+ end
@@ -0,0 +1,64 @@
1
+ module ShakeTheCounter
2
+
3
+ # This class handles the login logic.
4
+ # Shake The Counter uses OAuth
5
+ #
6
+ # A HTTP POST request must be done to https://apitest.shakethecounter.com/token
7
+ # (the authorization server) with the following information:
8
+ # Header Content-Type must be set to application/form-url-encoded
9
+ class Authentication
10
+
11
+ #
12
+ # Renews the access token from the refresh token.
13
+ # https://auth0.com/learn/refresh-tokens/
14
+ #
15
+ # body:
16
+ # grant_type=refresh_token&client_id=clientid&client_secret=clientsecret&refresh_token=refreshToken
17
+ #
18
+ # @return String access_token
19
+ def self.renew_access_token(client_id: '', client_secret: '', refresh_token: '')
20
+ body = {
21
+ grant_type: "refresh_token",
22
+ client_id: client_id,
23
+ client_secret: client_secret,
24
+ refresh_token: refresh_token
25
+ }
26
+ result = ShakeTheCounter::API.call(
27
+ "#{ShakeTheCounter::API.endpoint}/token",
28
+ http_method: :post,
29
+ body: body,
30
+ header: {content_type: "application/x-www-form-urlencoded"}
31
+ )
32
+ end
33
+
34
+
35
+
36
+ #
37
+ # Gets the authentication_token and refresh_token
38
+ # from a username and password.
39
+ #
40
+ # body:
41
+ # grant_type=password&client_id=clientid&client_secret=clientsecret&username=username&password=password
42
+ #
43
+ # @return OpenStruct containing authentication_token and refresh_token
44
+ def self.get_access_token(client_id: '', client_secret: '', username: '', password: '')
45
+ body = {
46
+ grant_type: "password",
47
+ client_id: client_id,
48
+ client_secret: client_secret,
49
+ username: username,
50
+ password: password
51
+ }
52
+ header = { content_type: "application/x-www-form-urlencoded" }
53
+ result = ShakeTheCounter::API.call(
54
+ "#{ShakeTheCounter::API.endpoint}/token",
55
+ http_method: :post,
56
+ header: header,
57
+ body: body
58
+ )
59
+ end
60
+
61
+ end
62
+
63
+
64
+ end
@@ -0,0 +1,136 @@
1
+ module ShakeTheCounter
2
+
3
+ # Sets up a client to work with
4
+ class Client
5
+ attr_accessor :refresh_token
6
+ attr_accessor :id
7
+ attr_accessor :secret
8
+ attr_accessor :language_code
9
+
10
+
11
+ #
12
+ # There are two ways to setup a new client:
13
+ # 1. Initialize with options `(Client.new(client_id: x)`)
14
+ # 2. Initilize without options, get options from config
15
+ #
16
+ def initialize(args=nil)
17
+ if args.nil?
18
+ init!
19
+ reset!
20
+ else
21
+ args.each do |key,value|
22
+ instance_variable_set("@#{key}", value)
23
+ end
24
+ end
25
+ end
26
+
27
+ # Set's the default value's
28
+ # @return [Hash] configuration options
29
+ def init!
30
+ @defaults = {
31
+ :@refresh_token => ShakeTheCounter::Config.refresh_token,
32
+ :@id => ShakeTheCounter::Config.client_id,
33
+ :@secret => ShakeTheCounter::Config.client_secret,
34
+ :@language_code => ShakeTheCounter::Config.language_code,
35
+ }
36
+ end
37
+
38
+ # Resets the value's to there previous value (instance_variable)
39
+ # @return [Hash] configuration options
40
+ def reset!
41
+ @defaults.each { |key, value| instance_variable_set(key, value) }
42
+ end
43
+
44
+ #
45
+ # Retrieves a new authentication token to use for this client
46
+ # or reuse the same one from memory.
47
+ #
48
+ def access_token
49
+ @access_token ||= ShakeTheCounter::Authentication.renew_access_token(client_id: id, client_secret: secret, refresh_token: refresh_token)["access_token"]
50
+ end
51
+
52
+
53
+ #
54
+ # Make an API with access_token
55
+ #
56
+ def call(path, http_method: :get, body: {}, header: {})
57
+ # add bearer token to header
58
+ header[:authorization] = "Bearer #{access_token}"
59
+ return ShakeTheCounter::API.call(path, http_method: http_method, body: body, header: header)
60
+ end
61
+
62
+ #
63
+ # Fetches a list of events for this client
64
+ # /api/v1/events/available/{languageCode}
65
+ #
66
+ # @return Array
67
+ def events
68
+ return @events if @events
69
+ @events = []
70
+ path = "events/available/#{language_code}"
71
+ result = call(path, http_method: :get)
72
+ for event in result
73
+ @events << ShakeTheCounter::Event.new(event, client: self)
74
+ end
75
+ return @events
76
+ end
77
+
78
+ #
79
+ # Find a reservation
80
+ # GET /api/v1/reservation/{reservationKey}
81
+ #
82
+ # @return Reservation
83
+ def find_reservation(key)
84
+ path = "reservation/#{key}"
85
+ result = call(path, http_method: :get)
86
+ reservation = ShakeTheCounter::Reservation.new(result)
87
+ return reservation
88
+ end
89
+ alias_method :reservation, :find_reservation
90
+
91
+ #
92
+ # Send a message to STC that a payment
93
+ # has started.
94
+ #
95
+ # @return String status
96
+ def start_payment(reservation_key)
97
+ path = "reservation/#{reservation_key}/payment"
98
+ result = call(path, http_method: :post)
99
+ if result.code.to_i == 200
100
+ return true
101
+ else
102
+ raise ShakeTheCounterError.new "Payment failed"
103
+ end
104
+ end
105
+
106
+
107
+ # Confirm the reservation and receive tickets
108
+ # /api/v1/reservation/{reservationKey}/confirm
109
+ #
110
+ # @return True (or error)
111
+ def confirm_reservation(reservation_key: '', payment_method: '', amount_paid: nil)
112
+
113
+ # step 1: confirm
114
+ path = "reservation/#{reservation_key}/confirm"
115
+ body = {
116
+ PaymentMethod: payment_method,
117
+ AmountPaid: amount_paid
118
+ }
119
+ call(path, http_method: :post, body: body.to_json)
120
+
121
+ # step 2: get tickets
122
+ # GET /api/v1/reservation/{reservationKey}/tickets
123
+ path = "reservation/#{reservation_key}/tickets"
124
+ result = call(path, http_method: :get)
125
+
126
+ # define new list
127
+ list = []
128
+
129
+ for ticket in result
130
+ list << ShakeTheCounter::Ticket.new(ticket)
131
+ end
132
+ return list
133
+ end
134
+
135
+ end
136
+ end
@@ -0,0 +1,44 @@
1
+ #
2
+ # Configuration object for storing some parameters required for making transactions
3
+ #
4
+ module ShakeTheCounter::Config
5
+ class << self
6
+ attr_accessor :client_id
7
+ attr_accessor :client_secret
8
+ attr_accessor :refresh_token
9
+ attr_accessor :environment
10
+ attr_accessor :language_code
11
+ attr_accessor :version
12
+ attr_accessor :verbose # if set, give more output in the log/console
13
+
14
+ # Set's the default value's to nil and false
15
+ # @return [Hash] configuration options
16
+ def init!
17
+ @defaults = {
18
+ :@refresh_token => ENV["STC_REFRESH_TOKEN"],
19
+ :@client_id => ENV["STC_CLIENT_ID"],
20
+ :@client_secret => ENV["STC_CLIENT_SECRET"],
21
+ :@language_code => "nl-NL",
22
+ :@environment => 'test',
23
+ :@version => 1,
24
+ :@verbose => false,
25
+ }
26
+ end
27
+
28
+ # Resets the value's to there previous value (instance_variable)
29
+ # @return [Hash] configuration options
30
+ def reset!
31
+ @defaults.each { |key, value| instance_variable_set(key, value) }
32
+ end
33
+
34
+ # Set's the new value's as instance variables
35
+ # @return [Hash] configuration options
36
+ def update!
37
+ @defaults.each do |key, value|
38
+ instance_variable_set(key, value) unless instance_variable_defined?(key)
39
+ end
40
+ end
41
+ end
42
+ init!
43
+ reset!
44
+ end
@@ -0,0 +1,15 @@
1
+ module ShakeTheCounter
2
+
3
+ # Sets up a contact object
4
+ class Contact
5
+
6
+ attr_accessor :key
7
+ attr_accessor :raw_data
8
+
9
+ def initialize(args={}, performance: nil)
10
+ self.key = args["ContactKey"]
11
+ self.raw_data = args
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module ShakeTheCounter
2
+ #
3
+ # Simpel extend on the +Rails::Engine+ to add support for a new config section within
4
+ # the environment configs
5
+ #
6
+ # @example default
7
+ # # /config/environments/development.rb
8
+ # config.prioticket.api_key = "12343465sdfgsadr324"
9
+ #
10
+ class Engine < Rails::Engine
11
+ config.shake_the_counter = ShakeTheCounter::Config
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ module ShakeTheCounter
2
+
3
+ # Sets up an event object
4
+ class Event
5
+ attr_accessor :key
6
+ attr_accessor :name
7
+ attr_accessor :performer
8
+ attr_accessor :tagline
9
+ attr_accessor :blocked_countries_for_sales
10
+ attr_accessor :rating
11
+ attr_accessor :review_count
12
+ attr_accessor :currency
13
+ attr_accessor :lowest_price
14
+ attr_accessor :performances
15
+ attr_accessor :raw_data
16
+ attr_accessor :client
17
+
18
+
19
+ # Sets up a new event
20
+ #
21
+ def initialize(args={}, client: nil)
22
+ self.client = client
23
+ self.key = args["EventKey"]
24
+ self.name = args["EventName"]
25
+ self.performer = args["Performer"]
26
+ self.tagline = args["Tagline"]
27
+ self.blocked_countries_for_sales = args["BlockedCountriesForSales"]
28
+ self.rating = args["Rating"]
29
+ self.review_count = args["ReviewCount"]
30
+ self.currency = args["Currency"]
31
+ self.lowest_price = args["LowestPrice"]
32
+ self.performances = []
33
+ for perf in args["Performances"]
34
+ self.performances << ShakeTheCounter::Performance.new(perf, event: self)
35
+ end
36
+ self.raw_data = args
37
+
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module ShakeTheCounter
2
+
3
+ # Sets up a performance object
4
+ class Performance
5
+
6
+ attr_accessor :key
7
+ attr_accessor :name
8
+ attr_accessor :description
9
+ attr_accessor :external_performance_id
10
+ attr_accessor :raw_data
11
+ attr_accessor :event
12
+
13
+ # Sets up a new event
14
+ #
15
+ def initialize(args={}, event: nil)
16
+ self.key = args["PerformanceKey"]
17
+ self.name = args["PerformanceName"]
18
+ self.description = args["PerformanceDescription"]
19
+ self.external_performance_id = args["ExternalPerformanceID"]
20
+ self.raw_data = args
21
+ self.event = event
22
+ end
23
+
24
+ #
25
+ # GET /api/v1/event/{eventKey}/performance/{performanceKey}/sections/{languageCode}
26
+ # Get available sections, pricetypes and prices of the selected performance
27
+ #
28
+ # @return Array of sections
29
+ def sections
30
+ return @sections if @sections
31
+ @sections = []
32
+ path = "event/#{event.key}/performance/#{key}/sections/#{event.client.language_code}"
33
+ result = event.client.call(path, http_method: :get)
34
+ for section in result
35
+ @sections << ShakeTheCounter::Section.new(section, performance: self)
36
+ end
37
+ return @sections
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,37 @@
1
+ module ShakeTheCounter
2
+
3
+ # Sets up a PriceType
4
+ class PriceType
5
+
6
+ attr_accessor :key
7
+ attr_accessor :price_key
8
+ attr_accessor :product_code
9
+ attr_accessor :name
10
+ attr_accessor :ticket_valid_from
11
+ attr_accessor :ticket_valid_to
12
+ attr_accessor :phone_number_required
13
+ attr_accessor :full_address_required
14
+ attr_accessor :price
15
+ attr_accessor :requires_capacity_slot
16
+
17
+ attr_accessor :section
18
+ attr_accessor :raw_data
19
+
20
+ # Sets up a new price type
21
+ #
22
+ def initialize(args={}, section: nil)
23
+ self.section = section
24
+ self.key = args["PriceTypeKey"]
25
+ self.price_key = args["PriceKey"]
26
+ self.name = args["PriceTypeName"]
27
+ self.ticket_valid_from = DateTime.parse(args["TicketValidFrom"])
28
+ self.ticket_valid_to = DateTime.parse(args["TicketValidTo"])
29
+ self.phone_number_required = args["PhoneNumberRequired"]
30
+ self.full_address_required = args["FullAddressRequired"]
31
+ self.price = args["Price"].to_f
32
+ self.requires_capacity_slot = args["RequiresCapacitySlot"]
33
+ self.raw_data = args
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,50 @@
1
+ module ShakeTheCounter
2
+
3
+ # Describes a reservation
4
+ class Reservation
5
+ attr_accessor :reservation_key
6
+ attr_accessor :nr_of_tickets
7
+ attr_accessor :contact_key
8
+ attr_accessor :affiliate
9
+ attr_accessor :reservation_number
10
+ attr_accessor :currency
11
+ attr_accessor :external_reservation_number
12
+ attr_accessor :currency_code
13
+ attr_accessor :basket_key
14
+ attr_accessor :total_amount
15
+ attr_accessor :status
16
+ attr_accessor :ticket_amount
17
+ attr_accessor :reservation_date
18
+ attr_accessor :original_ticket_amount
19
+ attr_accessor :confirmed_date
20
+ attr_accessor :reservation_costs_per_ticket
21
+ attr_accessor :tickets_url
22
+ attr_accessor :reservation_costs_per_transaction
23
+ attr_accessor :payment_method
24
+ attr_accessor :payment_costs
25
+ attr_accessor :is_paid
26
+ attr_accessor :discount
27
+ attr_accessor :is_confirmed
28
+ attr_accessor :discount_title
29
+ attr_accessor :is_blocked
30
+
31
+ attr_accessor :raw_data
32
+
33
+ # Sets up a new reservation
34
+ #
35
+ def initialize(args={})
36
+ args.each do |key, value|
37
+ instance_variable_set("@#{key.underscore}", value)
38
+ end
39
+ self.raw_data = args
40
+ end
41
+
42
+ def key
43
+ reservation_key
44
+ end
45
+
46
+
47
+
48
+
49
+ end
50
+ end
@@ -0,0 +1,67 @@
1
+ module ShakeTheCounter
2
+
3
+ # Sets up a section object
4
+ class Section
5
+
6
+ attr_accessor :key
7
+ attr_accessor :performance_section_key
8
+ attr_accessor :name
9
+ attr_accessor :available_seats
10
+ attr_accessor :price_types
11
+ attr_accessor :performance
12
+ attr_accessor :raw_data
13
+ attr_accessor :price_types
14
+
15
+ # Sets up a new section
16
+ #
17
+ def initialize(args={}, performance: nil)
18
+ self.key = args["SectionKey"]
19
+ self.name = args["SectionName"]
20
+ self.performance_section_key = args["PerformanceSectionKey"]
21
+ self.available_seats = args["AvailableSeats"]
22
+ self.performance = performance
23
+ self.price_types = []
24
+ for price_type in args["PriceTypes"]
25
+ self.price_types << ShakeTheCounter::PriceType.new(price_type, section: self)
26
+ end
27
+ self.raw_data = args
28
+ end
29
+
30
+ #
31
+ # Makes a reservation for this section
32
+ # POST /api/v1/event/{eventKey}/performance/{performanceKey}/section/{performanceSectionKey}/reservation/{languageCode}
33
+ # @param email: '' [type] [description]
34
+ #
35
+ # @return Reservation
36
+ def make_reservation(price_type_list: {}, affiliate: '', first_name: '', last_name: '', email: '')
37
+ # step 1: make the reservation
38
+ path = "event/#{performance.event.key}/performance/#{performance.key}/section/#{performance_section_key}/reservation/#{performance.event.client.language_code}"
39
+ body = {
40
+ PriceTypeList: price_type_list
41
+ }
42
+ result = performance.event.client.call(path, http_method: :post, body: body.to_json)
43
+ reservation = ShakeTheCounter::Reservation.new(result)
44
+
45
+ # step 2: create a contact
46
+ path = "contact/#{performance.event.client.language_code}"
47
+ body = {
48
+ FirstName: first_name,
49
+ LastName: last_name,
50
+ MailAddress: email,
51
+ LanguageCode: performance.event.client.language_code
52
+ }
53
+ result = performance.event.client.call(path, http_method: :post, body: body.to_json)
54
+ contact = ShakeTheCounter::Contact.new(result)
55
+
56
+ # step 3: link contact to the reservation
57
+ path = "reservation/#{reservation.key}/contact"
58
+ body = {
59
+ ContactKey: contact.key
60
+ }
61
+ result = performance.event.client.call(path, http_method: :post, body: body.to_json)
62
+
63
+ return reservation
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,4 @@
1
+ class ShakeTheCounterError < StandardError
2
+ attr_accessor :error_message
3
+ attr_accessor :error_code
4
+ end
@@ -0,0 +1,24 @@
1
+ module ShakeTheCounter
2
+
3
+ # Describes a ticket
4
+ class Ticket
5
+
6
+ # Sets up a new reservation
7
+ #
8
+ def initialize(args={})
9
+ args.each do |key, value|
10
+ # {"TicketKey"=>"1539335d-865d-40eb-ac31-0ac4b687ef2e", "Currency"=>"EUR", "Price"=>6.0, "PriceTypeKey"=>"0e9e2088-f74a-4ef4-9fe4-e668f2a01241", "PriceTypeName"=>"55 Plus", "ExternalPriceTypeID"=>"", "BranchePriceID"=>nil, "SectionName"=>"Toegangskaart", "TicketCode"=>"9787821683696", "BarcodeType"=>nil, "TicketValidFrom"=>"2018-03-31T00:00:00+02:00", "TicketValidTo"=>"2018-10-28T23:59:00+01:00", "LastClaimDate"=>nil, "SubscriptionProductKey"=>"00000000-0000-0000-0000-000000000000", "ScanningDisplayMessage"=>"", "TicketText"=>nil, "SalesChannelName"=>nil, "ExternalPriceID"=>nil}
11
+ singleton_class.class_eval { attr_accessor key.underscore }
12
+ instance_variable_set("@#{key.underscore}", value)
13
+ end
14
+ end
15
+
16
+ def key
17
+ reservation_key
18
+ end
19
+
20
+
21
+
22
+
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module ShakeTheCounter
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,40 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "shake_the_counter/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "shake-the-counter"
8
+ spec.version = ShakeTheCounter::VERSION
9
+ spec.authors = ["Henk Meijer"]
10
+ spec.email = ["meijerhenk@gmail.com"]
11
+
12
+ spec.summary = %q{Ruby implementation of the ShakeTheCounter API}
13
+ spec.description = %q{Ruby implementation of the ShakeTheCounter API}
14
+ spec.homepage = "https://github.com/henkm/shake-the-counter"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+
20
+ # if spec.respond_to?(:metadata)
21
+ # spec.metadata["allowed_push_host"] = 'https://rubygems.org'
22
+ # else
23
+ # raise "RubyGems 2.0 or newer is required to protect against " \
24
+ # "public gem pushes."
25
+ # end
26
+
27
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
28
+ f.match(%r{^(test|spec|features)/})
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_dependency "rest-client"
35
+ spec.add_dependency "json"
36
+
37
+ spec.add_development_dependency "bundler", "~> 1.16"
38
+ spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "rspec", "~> 3.0"
40
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shake-the-counter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Henk Meijer
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-04-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
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: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ description: Ruby implementation of the ShakeTheCounter API
84
+ email:
85
+ - meijerhenk@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - Gemfile.lock
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - bin/console
99
+ - bin/setup
100
+ - lib/shake_the_counter.rb
101
+ - lib/shake_the_counter/api.rb
102
+ - lib/shake_the_counter/authentication.rb
103
+ - lib/shake_the_counter/client.rb
104
+ - lib/shake_the_counter/config.rb
105
+ - lib/shake_the_counter/contact.rb
106
+ - lib/shake_the_counter/engine.rb
107
+ - lib/shake_the_counter/event.rb
108
+ - lib/shake_the_counter/performance.rb
109
+ - lib/shake_the_counter/price_type.rb
110
+ - lib/shake_the_counter/reservation.rb
111
+ - lib/shake_the_counter/section.rb
112
+ - lib/shake_the_counter/shake_the_counter_error.rb
113
+ - lib/shake_the_counter/ticket.rb
114
+ - lib/shake_the_counter/version.rb
115
+ - shake-the-counter.gemspec
116
+ homepage: https://github.com/henkm/shake-the-counter
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.6.14
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Ruby implementation of the ShakeTheCounter API
140
+ test_files: []