wheretocard 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9525b0d8a16b19b0ca6a24e94c14c0695fbad479
4
+ data.tar.gz: e023fb76f40ed4ed084f710b0f8845e4364904c1
5
+ SHA512:
6
+ metadata.gz: 74b996595133f49ea3a67b3fcd64f7d0039676995d16ff6670d86554143250568a3ea586dcb561cd48feb45ceff6e585d1776ce8a0072623040ccf888cbd0b8e
7
+ data.tar.gz: b65fb0053e6d10167f7ac99832f79e10d0a9ea31d40015a32b15883de515943b7a7a7998ac8ec9a38534b8772fdbc051e8819cdf4cfac36eb44625d836154472
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /fixtures/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wheretocard.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 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,102 @@
1
+
2
+ # Wheretocard
3
+
4
+ The Wheretocard gem is a straight forward ruby binder for the Wheretocard API.
5
+
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'wheretocard'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install wheretocard
22
+
23
+ ## Usage
24
+
25
+ To request two barcodes from two different ticket kinds (4 barcodes in total), you can do the following:
26
+
27
+
28
+ ```ruby
29
+ # Setup the WtC client with credentials
30
+ @wtc_client = Wheretocard::Client.new(
31
+ username: yourusername,
32
+ password: yourpassword,
33
+ client_code: yourclientcode,
34
+ case_code: yourcasecode
35
+ )
36
+
37
+ # Check the credentials first, without making test orders
38
+ @order.check_credentials("TICKET_KIND_1_CODE") #returns true or false
39
+
40
+ # Initialize a new OrderRequest
41
+ @order_request = @wtc_client.order_request
42
+ @order_request.first_name = "Foo"
43
+ @order_request.last_name = "Bar"
44
+ @order_request.email = "foobar@example.org"
45
+ @order_request.delivery_type = "BARCODE" # ["TEXTCODE","BARCODE"]
46
+
47
+ # Add line itmes to the request
48
+ # Please note: the price is in cents (currency is EUR)
49
+ @order_request.add_line_item(
50
+ product_code: TICKET_KIND_1_CODE,
51
+ quantity: 2,
52
+ price: 1250,
53
+ description: Action Description,
54
+ valid_from: Time.now,
55
+ valid_until: Time.now + 3.months
56
+ )
57
+
58
+ # It is also possible to not let WtC pick a barcode,
59
+ # but to submit your own barcode by adding the 'barcode' param
60
+ @order_request.add_line_item(
61
+ product_code: TICKET_KIND_3_CODE,
62
+ quantity: 2,
63
+ price: 1750,
64
+ description: Action Description,
65
+ barcode: "ABC12345"
66
+ valid_from: Time.now,
67
+ valid_until: Time.now + 3.months
68
+ )
69
+
70
+
71
+ # Submit the request and receive a response object
72
+ @response = @order_request.submit
73
+
74
+ # redirect the consumer to the PDF download page:
75
+ if @response.success?
76
+ redirect_to @response.url
77
+ # => https://ticketing.wheretocard.nl/ticketService/print/printTicket?refId=xxx&ui=yyy
78
+ else
79
+ # TODO: handle exception
80
+ end
81
+
82
+ ```
83
+
84
+ ## Development
85
+
86
+ 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.
87
+
88
+ 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).
89
+
90
+ ## Contributing
91
+
92
+ Bug reports and pull requests are welcome on GitHub at https://github.com/henkm/wheretocard.
93
+
94
+
95
+ ## License
96
+
97
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
98
+
99
+ ## Credits and disclaimer
100
+
101
+ This gem is made with love by the smart people at [Eskes Media B.V.](http://www.eskesmedia.nl) and [dagjewegtickets.nl](https://www.dagjewegtickets.nl)
102
+ Wheretocard 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 "wheretocard"
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
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,243 @@
1
+ <?php
2
+
3
+ // test_wtc_api.php
4
+ // 20160410/PPM Created
5
+
6
+ // Warning: This scripts doesn't work without valid credentials in wtc_parameters
7
+
8
+
9
+ test_wtc_api();
10
+
11
+
12
+ // test_wtc_api()
13
+ // Description: Send request, show result
14
+
15
+
16
+
17
+ function xml_entities($string) {
18
+ return strtr(
19
+ $string,
20
+ array(
21
+ "<" => "&lt;",
22
+ ">" => "&gt;",
23
+ '"' => "&quot;",
24
+ "'" => "&apos;",
25
+ "&" => "&amp;",
26
+ )
27
+ );
28
+ }
29
+
30
+ function convertdate_last2to($date_last){
31
+ $date_to = date('Y-m-d', strtotime($date_last.' + 1 day'));
32
+
33
+ return $date_to;
34
+ }
35
+
36
+
37
+ function test_wtc_api(){
38
+
39
+ // Initialize
40
+ $fname = __FUNCTION__;
41
+ $dbg = 1;
42
+
43
+ if($dbg>0){ echo "$fname()<br>\n"; }
44
+
45
+ // WtC parameters
46
+ $wtc_client_code = 'CLIENT_TICKETCOUNTER_API';
47
+ $wtc_case_code = 'TCAPI_CLIENT_NAME';
48
+ $wtc_client_username = 'username_api';
49
+ $wtc_client_password = 'rand0mpa55w0rd';
50
+ $wtc_request_url = 'https://ticketing.wheretocard.nl/ticketService/submitOrder';
51
+
52
+ /*
53
+ CLIENT_TICKETCOUNTER_API
54
+ Case:
55
+ TCAPI_CLIENT_NAME
56
+ Apicodes:
57
+ TICKET_KIND_1_API_CODE
58
+ TICKET_KIND_2_API_CODE
59
+ */
60
+
61
+ // Construct name
62
+ $order_code = '1234';
63
+ $name = 'My Name';
64
+ $email = 'myemail@myemail.com';
65
+ $street = 'My Street';
66
+ $house_number = 123;
67
+ $postal_code = '1234AB';
68
+ $city = 'My City';
69
+
70
+ // To xml
71
+ $xml_order_code = xml_entities($order_code);
72
+ $xml_name = xml_entities($name);
73
+ $xml_email = xml_entities($email);
74
+ $xml_street = xml_entities($street);
75
+ $xml_house_number = xml_entities($house_number);
76
+ $xml_postal_code = xml_entities($postal_code);
77
+ $xml_city = xml_entities($city);
78
+
79
+ $properties_first_name = '';
80
+ $properties_infix = '';
81
+ $properties_last_name = $xml_name;
82
+ $properties_email = $xml_email;
83
+ $properties_street = $xml_street;
84
+ $properties_house_number = $xml_house_number;
85
+ $properties_postal_code = $xml_postal_code;
86
+ $properties_city = $xml_city;
87
+
88
+ if($dbg>0){ echo "$fname: prepare xml request ...<br>\n"; }
89
+
90
+ // Construct orderlines by constructing orderline items
91
+ // <orderline code="{{ reservation.producttypeperiodtime.producttypeperiod.producttype.code }}" ticket-ref="{{ reservation.number }}"><quantity>1</quantity><price>{{ reservation.price|makeCents }}</price><action>{{ reservation.producttypeperiodtime.producttypeperiod.producttype.name }}</action><validPeriod from="{{ reservation.reservationdate|date:"Y-m-d" }}T00:00:00" to="{{ reservation.reservationdate|addDays:1|date:"Y-m-d" }}T00:00:00"/></orderline>
92
+
93
+ $orderitems = array();
94
+ // Product#1
95
+ $orderitems[] = array(
96
+ 'product_code' => 'TICKET_KIND_1_API_CODE',
97
+ 'product_name' => 'My Ticket',
98
+ 'quantity' => 1,
99
+ 'unitprice' => 1150,
100
+ 'dated_from' => '2016-04-10',
101
+ 'dated_last' => '2016-06-30',
102
+ );
103
+ // Product#2
104
+ $orderitems[] = array(
105
+ 'product_code' => 'TICKET_KIND_2_API_CODE',
106
+ 'product_name' => 'My Ticket 2',
107
+ 'quantity' => 2,
108
+ 'unitprice' => 2250,
109
+ 'dated_from' => '2016-04-10',
110
+ 'dated_last' => '2016-06-30',
111
+
112
+ );
113
+
114
+ $orderlines = array();
115
+ foreach($orderitems as $orderitem){
116
+
117
+ $xml_orderline_ticketref = 23;
118
+
119
+ $xml_orderline_code = $orderitem['product_code'];
120
+
121
+ $xml_quantity = $orderitem['quantity'];
122
+ $orderline_quantity =<<<EOT
123
+ <quantity>$xml_quantity</quantity>
124
+ EOT;
125
+
126
+ $xml_price = $orderitem['unitprice'];
127
+ $orderline_price =<<<EOT
128
+ <price>$xml_price</price>
129
+ EOT;
130
+
131
+ $validPeriod_from = $orderitem['dated_from'].'T00:00:00';
132
+ $validPeriod_to = convertdate_last2to($orderitem['dated_from']).'T00:00:00';
133
+ $orderline_validPeriod =<<<EOT
134
+ <validPeriod from="$validPeriod_from" to="$validPeriod_to"/>
135
+ EOT;
136
+
137
+ $xml_product_name = xml_entities($orderitem['product_name']);
138
+ $orderline_action =<<<EOT
139
+ <action>$xml_product_name</action>
140
+ EOT;
141
+
142
+ // Construct orderline
143
+ $orderline = '<orderline code="'.$xml_orderline_code.'" ticket-ref="'.$xml_orderline_ticketref.'">'.$orderline_quantity.$orderline_price.$orderline_action.$orderline_validPeriod.'</orderline>';
144
+
145
+ // Add to list
146
+ $orderlines[] = $orderline;
147
+ }
148
+
149
+ // Join orderlines
150
+ $orderlines_list = join("\n", $orderlines);
151
+
152
+ $xml_request_data = <<<EOT
153
+ <orderRequest version="1.0">
154
+ <client code="$wtc_client_code">
155
+ <username>$wtc_client_username</username>
156
+ <password>$wtc_client_password</password>
157
+ </client>
158
+ <order referenceId="$xml_order_code">
159
+ <properties>
160
+ <property name="FIRST_NAME" value="$properties_first_name"/>
161
+ <property name="INFIX" value="$properties_infix"/>
162
+ <property name="LAST_NAME" value="$properties_last_name"/>
163
+ <property name="EMAIL" value="$properties_email"/>
164
+ <property name="STREET" value="$properties_street"/>
165
+ <property name="HOUSE_NUMBER" value="$properties_house_number"/>
166
+ <property name="POSTAL_CODE" value="$properties_postal_code"/>
167
+ <property name="CITY" value="$properties_city"/>
168
+ </properties>
169
+ <cases>
170
+ <case code="$wtc_case_code">
171
+ <orderlines>
172
+ $orderlines_list
173
+ </orderlines>
174
+ </case>
175
+ </cases>
176
+ </order>
177
+ <tickets>
178
+ <ticket ref="23" delivery-channel="WEB" delivery-format="BARCODE">
179
+ </ticket>
180
+ </tickets>
181
+ </orderRequest>
182
+ EOT;
183
+
184
+ if($dbg>0){ echo "$fname: wtc_request_url = ".$wtc_request_url."<br>\n"; }
185
+ if($dbg>0){ echo "$fname: xml_request_data = ".$xml_request_data; }
186
+
187
+
188
+ $ch = curl_init();
189
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:', 'Content-Type: text/xml'));
190
+ curl_setopt($ch, CURLOPT_URL, $wtc_request_url);
191
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
192
+ curl_setopt($ch, CURLOPT_POST, 1);
193
+ curl_setopt($ch, CURLOPT_TIMEOUT, 30);
194
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
195
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_request_data);
196
+
197
+ $time_start = time();
198
+ $result = curl_exec($ch);
199
+ $time_end = time();
200
+
201
+ if($dbg>0){ echo "$fname: result = ".$result; }
202
+
203
+ $time_diff = $time_end - $time_start;
204
+ if($dbg>0){ echo "$fname: curl request executed in $time_diff second(s)<br>\n"; }
205
+
206
+ $curl_errors = 0;
207
+ $curl_errors_msg = '';
208
+ if(curl_errno($ch)){
209
+ // print curl_error($ch);
210
+ $curl_errors++;
211
+ $curl_errors_msg = curl_error($ch);
212
+ if($dbg>0){ echo "$fname: curl_error = ".$curl_errors_msg."<br>\n"; }
213
+ $result = '';
214
+ }else{
215
+ if($dbg>0){ echo "$fname: NO curl error(s)<br>\n"; }
216
+ }
217
+ curl_close($ch);
218
+
219
+ $got_ok = 0;
220
+ $got_url = 0;
221
+ $url = '';
222
+ if($curl_errors == 0){
223
+ // Try to locate OK (= <orderResponse status="OK"> ) in result
224
+ if(preg_match("/\<\s*orderResponse\s+status\s*\=\s*\"OK\"\\s*[\/]*\s*>/", $result)){
225
+ $got_ok = 1;
226
+
227
+ // Now try to get the URL
228
+ if(preg_match("/\<\s*comment\s+type\s*\=\s*\"url\"\\s*[\/]*\s*>/", $result)){
229
+ if(preg_match("/\[CDATA\[http(.*?)\]\]/", $result, $matches)){
230
+ $got_url = 1;
231
+ $url = 'http'.$matches[1];
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ if($dbg>0){ echo "$fname: curl_errors = $curl_errors, got_ok = $got_ok, got_url = $got_url, url = ".$url."<br>\n"; }
238
+
239
+ }
240
+
241
+
242
+
243
+ ?>
@@ -0,0 +1,39 @@
1
+ # Libraries
2
+ require 'ostruct'
3
+ require 'httparty'
4
+ # require 'uri'
5
+ # require 'rails'
6
+ # require 'active_support/dependencies'
7
+ # require 'active_support'
8
+ require 'open-uri'
9
+ require 'nokogiri'
10
+ # require 'veto'
11
+
12
+
13
+ # Files
14
+ require "wheretocard/version"
15
+ require "wheretocard/config"
16
+ require "wheretocard/engine" if defined?(Rails) && Rails::VERSION::MAJOR.to_i >= 3
17
+ require "wheretocard/wheretocard_error"
18
+ require "wheretocard/client"
19
+ require "wheretocard/order"
20
+ require "wheretocard/line_item"
21
+ require "wheretocard/response"
22
+
23
+
24
+ #
25
+ # Wheretocard Module
26
+ #
27
+ module Wheretocard
28
+ API_VERSION = 1
29
+
30
+ # returns the version number
31
+ def self.version
32
+ VERSION
33
+ end
34
+
35
+ def self.url
36
+ "https://ticketing.wheretocard.nl/ticketService/submitOrder"
37
+ end
38
+
39
+ end
@@ -0,0 +1,66 @@
1
+ module Wheretocard
2
+
3
+ class Client
4
+ # @note The is a required parameter.
5
+ attr_accessor :username
6
+ # @return [String] Your Wheretocard password
7
+ attr_accessor :password
8
+ # @return [String] Your Wheretocard client code
9
+ attr_accessor :client_code
10
+ # @return [String] Your Wheretocard case code
11
+ attr_accessor :case_code
12
+
13
+
14
+ #
15
+ # Initializer to transform a +Hash+ into an Client object
16
+ #
17
+ # @param [Hash] args
18
+ def initialize(args=nil)
19
+ required_args = [:username, :password, :client_code, :case_code]
20
+ for arg in required_args
21
+ if args.nil? || args[arg].nil?
22
+ raise WheretocardError.new(self), "Insufficient login credentials. Please provide @username, @password, @client_code and @case_code"
23
+ end
24
+ end
25
+
26
+ return if args.nil?
27
+ args.each do |k,v|
28
+ instance_variable_set("@#{k}", v) unless v.nil?
29
+ end
30
+ end
31
+
32
+ def check_credentials(product_code="")
33
+ o = order
34
+ o.add_line_item(
35
+ price: 0,
36
+ description: 'Checking credentials [TEST]',
37
+ ticket_ref: 1234,
38
+ valid_from: Time.now,
39
+ valid_until: Time.now + 24*31*3600,
40
+ product_code: product_code,
41
+ quantity: 0
42
+ )
43
+ begin
44
+ o.submit
45
+ rescue WheretocardError => e
46
+ # return true if the error raised is only about the
47
+ # number of tickets (cannot be zero)
48
+ e.to_s.include?("OI_0210")
49
+ end
50
+
51
+ end
52
+
53
+ # def order_requests
54
+ # Wheretocard::Order
55
+ # end
56
+ # alias :order_request :order_requests
57
+
58
+ def order(args={})
59
+ Wheretocard::Order.new({client: self}.merge(args))
60
+ end
61
+ alias :orders :order
62
+ alias :new_order :order
63
+ alias :add_order :order
64
+
65
+ end
66
+ end
@@ -0,0 +1,8 @@
1
+ #
2
+ # Configuration object for storing some parameters required for making transactions
3
+ #
4
+ module Wheretocard::Config
5
+ class << self
6
+ # config code here... (if needed)
7
+ end
8
+ end
@@ -0,0 +1,47 @@
1
+ module Wheretocard
2
+ #
3
+ # Object representing a line item with attributes provided by WTC
4
+ # required args:
5
+ # - product_code (string)
6
+ # - price (integer - cents)
7
+ # - valid_from (DateTime / Date)
8
+ # - valid_until (DateTime / Date)
9
+ # - barcode (string) OR quantity (integer)
10
+ #
11
+ # @return [Array] Errors
12
+ class LineItem
13
+ attr_accessor :errors
14
+ attr_accessor :product_code
15
+ # If a barcode is given, it'll be used. There is no check for
16
+ # uniqueness. If no barcode is given, WtC will generate a unique one.
17
+ attr_accessor :barcode
18
+ attr_accessor :quantity
19
+ attr_accessor :ticket_ref
20
+ attr_accessor :price
21
+ attr_accessor :description
22
+ attr_accessor :valid_from
23
+ attr_accessor :valid_until
24
+
25
+ #
26
+ # Initializer to transform a +Hash+ into an Payment object
27
+ #
28
+ # @param [Hash] args
29
+ def initialize(args=nil)
30
+ @quantity = 1
31
+ return if args.nil?
32
+ args.each do |k,v|
33
+ instance_variable_set("@#{k}", v) unless v.nil?
34
+ end
35
+
36
+ validate
37
+ end
38
+
39
+ def validate
40
+ if barcode && quantity && quantity > 1
41
+ raise WheretocardError.new(self), "Quantity cannot be greater than 1 if a barcode is specified."
42
+ end
43
+ end
44
+
45
+
46
+ end
47
+ end
@@ -0,0 +1,113 @@
1
+ module Wheretocard
2
+
3
+ # Creates a validator
4
+ class OrderValidator
5
+ # include Veto.validator
6
+ # validates :value, presence: true, integer: true
7
+ # validates :profile, presence: true
8
+ # validates :currency, presence: true, format: /[A-Z]{3}/
9
+ # validates :email, presence: true
10
+ end
11
+
12
+
13
+
14
+ #
15
+ # Object representing a response object with attributes provided by WTC
16
+ #
17
+ # @return [Array] Errors
18
+ # @param :amount [Integer] The total price in cents
19
+ class Order
20
+ attr_accessor :errors
21
+ attr_accessor :reference_id
22
+ attr_accessor :first_name
23
+ attr_accessor :infix
24
+ attr_accessor :last_name
25
+ attr_accessor :street
26
+ attr_accessor :house_number
27
+ attr_accessor :city
28
+ attr_accessor :postal_code
29
+ attr_accessor :country
30
+ attr_accessor :email
31
+ attr_accessor :phone_number
32
+ attr_accessor :value
33
+ attr_accessor :client
34
+ attr_accessor :line_items
35
+ attr_accessor :delivery_format
36
+ attr_accessor :delivery_channel
37
+
38
+
39
+ #
40
+ # Initializer to transform a +Hash+ into an Payment object
41
+ #
42
+ # @param [Hash] args
43
+ def initialize(args=nil)
44
+ @line_items = []
45
+ @delivery_format = "BARCODE"
46
+ @delivery_channel = "WEB"
47
+ return if args.nil?
48
+ args.each do |k,v|
49
+ instance_variable_set("@#{k}", v) unless v.nil?
50
+ end
51
+ end
52
+
53
+ # @return [Boolean] true/false, depending if this instanciated object is valid
54
+ def valid?
55
+ validator = OrderValidator.new
56
+ validator.valid?(self)
57
+ end
58
+
59
+ #
60
+ # This is the most importent method. It uses all the attributes
61
+ # and performs a `order` action on Wheretocard API.
62
+ # @return [Wheretocard::Response] response object with `key`, `message` and `success?` methods
63
+ #
64
+ def create
65
+ # if there are any line items, they should all be valid.
66
+ validate_line_items
67
+
68
+ # make the API call
69
+ # response = Docdata.client.call(:create, xml: create_xml)
70
+ # response_object = Docdata::Response.parse(:create, response)
71
+ if response_object.success?
72
+ self.key = response_object.key
73
+ end
74
+
75
+ # set `self` as the value of the `payment` attribute in the response object
76
+ response_object.payment = self
77
+ response_object.url = redirect_url
78
+
79
+ return response_object
80
+ end
81
+
82
+ # adds a line item of type LineItem to the line_items atribute (array)
83
+ def add_line_item(args=nil)
84
+ line_item = Wheretocard::LineItem.new(args)
85
+ line_items << line_item
86
+ return line_item
87
+ end
88
+
89
+ # @return [String] the xml to send in the SOAP API
90
+ def to_xml
91
+ xml_file = "#{File.dirname(__FILE__)}/xml/order_request.xml.erb"
92
+ template = File.read(xml_file)
93
+ namespace = OpenStruct.new(order: self, client: client)
94
+ xml = ERB.new(template).result(namespace.instance_eval { binding })
95
+ end
96
+ alias :xml :to_xml
97
+
98
+ # submit the xml to the WtC API url
99
+ # return object is a Wheretocard::Response
100
+ def submit
101
+ # validate_line_items
102
+ Wheretocard::Response.from_order_request(self)
103
+ end
104
+
105
+ end
106
+
107
+ private
108
+
109
+ # make sure all the line items are valid
110
+ def validate_line_items
111
+
112
+ end
113
+ end
@@ -0,0 +1,114 @@
1
+ module Wheretocard
2
+
3
+
4
+ #
5
+ # Object representing a response object with attributes provided by WTC
6
+ #
7
+ # @return [Array] Errors
8
+ # @param :amount [Integer] The total price in cents
9
+ class Response
10
+ attr_accessor :errors
11
+ attr_accessor :body
12
+ attr_accessor :comment
13
+ attr_accessor :status
14
+ attr_accessor :url
15
+
16
+ #
17
+ # Initializer to transform a +Hash+ into an Payment object
18
+ #
19
+ # @param [Hash] args
20
+ def initialize(args=nil)
21
+ @line_items = []
22
+ return if args.nil?
23
+ args.each do |k,v|
24
+ instance_variable_set("@#{k}", v) unless v.nil?
25
+ end
26
+ end
27
+
28
+ # raise errors if the API returns errors
29
+ def validate
30
+ if nokogiri_document.xpath('//error').any?
31
+ code = nokogiri_document.xpath('//code').text
32
+ desc = nokogiri_document.xpath('//description').text
33
+ raise WheretocardError.new(self), "#{desc}\nError code: #{code} (#{error_codes[code]})"
34
+ end
35
+ end
36
+
37
+ # return true if status is "OK"
38
+ def success
39
+ status == "OK"
40
+ end
41
+ alias :success? :success
42
+
43
+ # return the parsed xml document
44
+ def nokogiri_document
45
+ @nokogiri_document ||= Nokogiri::XML(body)
46
+ end
47
+
48
+ def error_codes
49
+ {
50
+ "OI_0001" => "Internal server error",
51
+ "OI_0099" => "Unknown error",
52
+
53
+ "OI_0101" => "Supplied client not found",
54
+ "OI_0102" => "Interface not enabled for client",
55
+
56
+ "OI_0201" => "Submitted client not found",
57
+ "OI_0202" => "Interface not enabled for client",
58
+ "OI_0203" => "Missing (or empty) order reference id attribute.",
59
+ "OI_0204" => "Request contains invalid orderline.ticket-ref <-> ticket.ref link reference(s)",
60
+ "OI_0205" => "Unknown delivery channel",
61
+ "OI_0206" => "Unknown delivery format",
62
+ "OI_0207" => "Device manufacturerer/type is not known",
63
+ "OI_0208" => "The delivery address is not specified",
64
+ "OI_0209" => "The submitted data for order reference id (max 32 chars), or one of the
65
+ properties (max 100 chars) is too long.",
66
+ "OI_0210" => "Submitted number of persons is negative or 0",
67
+ "OI_0211" => "Submitted times valid is negative or 0",
68
+ "OI_0212" => "Supplied email address is missing or the format is not correct",
69
+ "OI_0213" => "The submitted orderline type does not belong to the client",
70
+ "OI_0214" => "Missing required orderlinetype",
71
+ "OI_0215" => "Orderline type is not owned by the submitted case",
72
+ "OI_0216" => "Could not generate ticket code for request, all ticket codes are in use (batch
73
+ full).",
74
+ }
75
+ end
76
+
77
+ def self.parse_respose_code(order, code)
78
+ if code == 200
79
+ return
80
+ elsif code == 500
81
+ raise WheretocardError.new(order), "A server error occured (500)"
82
+ else
83
+ raise WheretocardError.new(order), "The request failed (http status code #{code})"
84
+ end
85
+ end
86
+
87
+ def self.from_order_request(order)
88
+ response = HTTParty.post(Wheretocard.url, body: order.to_xml)
89
+ # puts response.body, response.code, response.message, response.headers.inspect
90
+
91
+
92
+ # raise error if code is not 200
93
+ parse_respose_code(order, response.code)
94
+
95
+ # parse the response
96
+ # <orderResponse status="NOT_OK">
97
+ # <error>
98
+ # <code>OI_0202</code>
99
+ # <description><![CDATA[Posted XML not valid, or not conform Schema definition. ]]></description>
100
+ # </error>
101
+ # </orderResponse>
102
+
103
+ r = Response.new()
104
+ r.body = response.body
105
+ r.status = r.nokogiri_document.xpath('//orderResponse/@status').text
106
+ if r.nokogiri_document.search('comment[type="url"]').any?
107
+ r.url = r.nokogiri_document.search('comment[type="url"]').first.text
108
+ end
109
+ r.validate
110
+ return r
111
+ end
112
+
113
+ end
114
+ end
@@ -0,0 +1,3 @@
1
+ module Wheretocard
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,7 @@
1
+ class WheretocardError < StandardError
2
+ attr_reader :object
3
+
4
+ def initialize(object)
5
+ @object = object
6
+ end
7
+ end
@@ -0,0 +1,44 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <orderRequest version="1.0">
3
+ <client code="<%= client.client_code %>">
4
+ <username><%= client.username%></username>
5
+ <password><%= client.password%></password>
6
+ </client>
7
+ <order referenceId="<%= order.reference_id %>">
8
+ <properties>
9
+ <property name="FIRST_NAME" value="<%= order.first_name %>"/>
10
+ <property name="INFIX" value="<%= order.infix %>"/>
11
+ <property name="LAST_NAME" value="<%= order.last_name %>"/>
12
+ <property name="EMAIL" value="<%= order.email %>"/>
13
+ <property name="STREET" value="<%= order.street %>"/>
14
+ <property name="HOUSE_NUMBER" value="<%= order.house_number %>"/>
15
+ <property name="POSTAL_CODE" value="<%= order.postal_code %>"/>
16
+ <property name="CITY" value="<%= order.city %>"/>
17
+ </properties>
18
+ <cases>
19
+ <case code="<%= client.case_code %>">
20
+ <orderlines>
21
+ <% for line_item in order.line_items %>
22
+ <orderline code="<%= line_item.product_code %>" ticket-ref="<%= line_item.ticket_ref %>">
23
+ <quantity><%= line_item.quantity %></quantity>
24
+ <price><%= line_item.price %></price>
25
+ <action><%= line_item.description %></action>
26
+ <% if line_item.valid_from && line_item.valid_until %>
27
+ <validPeriod from="<%= line_item.valid_from.strftime("%Y-%m-%dT%H:%M:%S") %>" to="<%= line_item.valid_until.strftime("%Y-%m-%dT%H:%M:%S") %>"/>
28
+ <% end %>
29
+ </orderline>
30
+ <% end %>
31
+ </orderlines>
32
+ </case>
33
+ </cases>
34
+ </order>
35
+ <tickets>
36
+ <% for line_item in order.line_items %>
37
+ <ticket ref="<%= line_item.ticket_ref %>" delivery-channel="<%= order.delivery_channel %>" delivery-format="<%= order.delivery_format %>">
38
+ <% if line_item.barcode %>
39
+ <contentCode><%= line_item.barcode %></contentCode>
40
+ <% end %>
41
+ </ticket>
42
+ <% end %>
43
+ </tickets>
44
+ </orderRequest>
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wheretocard/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wheretocard"
8
+ spec.version = Wheretocard::VERSION
9
+ spec.authors = ["Henk Meijer"]
10
+ spec.email = ["henk.meijer@eskesmedia.nl"]
11
+
12
+ spec.summary = %q{Ruby binder to the Wherto CARD API}
13
+ spec.description = %q{Ruby binder to the Wherto CARD API}
14
+ spec.homepage = "http://www.eskesmedia.nl/"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ # end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.10"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "rspec"
33
+ spec.add_development_dependency "vcr"
34
+ spec.add_development_dependency "fakeweb"
35
+ spec.add_development_dependency "coveralls"
36
+ spec.add_development_dependency "simplecov"
37
+
38
+
39
+ # spec.add_dependency 'veto'
40
+ # spec.add_dependency 'rubyntlm' #, '0.4.0'
41
+ spec.add_dependency 'httparty'
42
+ spec.add_dependency 'nokogiri'
43
+ # spec.add_dependency 'railties'
44
+
45
+ end
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wheretocard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Henk Meijer
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-04-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: vcr
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: fakeweb
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: coveralls
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
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: httparty
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: nokogiri
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Ruby binder to the Wherto CARD API
140
+ email:
141
+ - henk.meijer@eskesmedia.nl
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - .gitignore
147
+ - .rspec
148
+ - .travis.yml
149
+ - Gemfile
150
+ - LICENSE.txt
151
+ - README.md
152
+ - Rakefile
153
+ - bin/console
154
+ - bin/setup
155
+ - documentation/Ticketing order interface specification v1.60.pdf
156
+ - documentation/test_wtc_api.php
157
+ - lib/wheretocard.rb
158
+ - lib/wheretocard/client.rb
159
+ - lib/wheretocard/config.rb
160
+ - lib/wheretocard/line_item.rb
161
+ - lib/wheretocard/order.rb
162
+ - lib/wheretocard/response.rb
163
+ - lib/wheretocard/version.rb
164
+ - lib/wheretocard/wheretocard_error.rb
165
+ - lib/wheretocard/xml/order_request.xml.erb
166
+ - wheretocard.gemspec
167
+ homepage: http://www.eskesmedia.nl/
168
+ licenses:
169
+ - MIT
170
+ metadata: {}
171
+ post_install_message:
172
+ rdoc_options: []
173
+ require_paths:
174
+ - lib
175
+ required_ruby_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - '>='
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - '>='
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ requirements: []
186
+ rubyforge_project:
187
+ rubygems_version: 2.3.0
188
+ signing_key:
189
+ specification_version: 4
190
+ summary: Ruby binder to the Wherto CARD API
191
+ test_files: []
192
+ has_rdoc: