wheretocard 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: