shake_the_counter 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fe41e0c19cf289a649602db970923a37029ced29
4
+ data.tar.gz: 912e1746cc0658f55857c34fbf0fbb1312bddf3a
5
+ SHA512:
6
+ metadata.gz: 98ca515e9ef967e09028b2dba61b355d0c23f1ab79255c619796f623b0a4b1cf7792b270ef03aedb3a38ca2c0ce21b576e5a1f4170c7d357302e5665f3fb3dd3
7
+ data.tar.gz: cc1a4ac5286fa00e6d679274bbfaa4c07ca37ca85384db9c0bb868a1d4cbd12cd311f70fb84bb2ceb3261aac32bc67cdb90829a228d53427fe05ae0c22b3ce64
@@ -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
@@ -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
@@ -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
@@ -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.
@@ -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/henkm/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.
@@ -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
@@ -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__)
@@ -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.shake_the_counter.environment = "test"
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.2"
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.2
5
+ platform: ruby
6
+ authors:
7
+ - Henk Meijer
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-04-09 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: []