· 6 years ago · Mar 22, 2020, 07:10 PM
1<?php
2/* Copyright 2013 Your Inspiration Themes (email : plugins@yithemes.com)
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18/**
19 * API handler class
20 *
21 * @author Your Inspiration Themes
22 * @package YITH WooCommerce Authorize.net
23 * @version 1.0.0
24 */
25
26if ( ! defined( 'YITH_WCAUTHNET' ) ) {
27 exit;
28} // Exit if accessed directly
29
30if ( ! class_exists( 'YITH_WCAUTHNET_CIM_API' ) ) {
31 /**
32 * WooCommerce Authorize.net CIM API handler class
33 *
34 * @since 1.0.0
35 */
36 class YITH_WCAUTHNET_CIM_API {
37
38 /**
39 * @const Sandbox payment url
40 */
41 const AUTHORIZE_NET_XML_SANDBOX_PAYMENT_URL = 'https://apitest.authorize.net/xml/v1/request.api';
42
43 /**
44 * @const Public payment url
45 */
46 const AUTHORIZE_NET_XML_PRODUCTION_PAYMENT_URL = 'https://api2.authorize.net/xml/v1/request.api';
47
48 /**
49 * @var string Whether or not we're using a development env
50 */
51 public $sandbox;
52
53 /**
54 * @var string Authorize.net Login ID
55 */
56 public $login_id;
57
58 /**
59 * @var string Authorize.net transaction key
60 */
61 public $transaction_key;
62
63 /**
64 * @var bool Whether or not transactions should be itemized
65 */
66 public $itemized;
67
68 /**
69 * @var bool whether or not transaction should handle payment profiles
70 */
71 public $cim_handling;
72
73 /**
74 * Single instance of the class
75 *
76 * @var \YITH_WCAUTHNET_CIM_API
77 * @since 1.0.0
78 */
79 protected static $instance;
80
81 /**
82 * Instance of the class XMLWriter, used to create xml request to server
83 *
84 * @var \XMLWriter
85 * @since 1.0.0
86 */
87 protected $xml_writer = null;
88
89 /**
90 * Returns single instance of the class
91 *
92 * @return \YITH_WCAUTHNET_CIM_API
93 * @since 1.0.0
94 */
95 public static function get_instance() {
96 if ( is_null( self::$instance ) ) {
97 self::$instance = new self;
98 }
99
100 return self::$instance;
101 }
102
103 /**
104 * Constructor method
105 *
106 * @return \YITH_WCAUTHNET_CIM_API
107 * @since 1.0.0
108 */
109 public function __construct() {
110 $this->xml_writer = new XMLWriter();
111 }
112
113 /**
114 * Process a request to Authorize.net servers
115 *
116 * @param $xml string Xml to send through request
117 *
118 * @return string Xml response from the server
119 * @throws Exception
120 * @since 1.0.0
121 */
122 public function do_request( $xml ) {
123 if ( empty( $this->login_id ) || empty( $this->transaction_key ) ) {
124 return false;
125 }
126
127 if ( $this->sandbox ) {
128 $process_url = self::AUTHORIZE_NET_XML_SANDBOX_PAYMENT_URL;
129 } else {
130 $process_url = self::AUTHORIZE_NET_XML_PRODUCTION_PAYMENT_URL;
131 }
132
133 $wp_http_args = array(
134 'timeout' => apply_filters( 'yith_wcauthnet_cim_api_timeout', 45 ),
135 'redirection' => 0,
136 'httpversion' => '1.0',
137 'sslverify' => false,
138 'blocking' => true,
139 'headers' => array(
140 'accept' => 'application/xml',
141 'content-type' => 'application/xml'
142 ),
143 'body' => $xml,
144 'cookies' => array(),
145 'user-agent' => "PHP " . PHP_VERSION
146 );
147
148 $response = wp_remote_post( $process_url, $wp_http_args );
149
150 // Check for Network timeout, etc.
151 if ( is_wp_error( $response ) ) {
152 throw new Exception( $response->get_error_message() );
153 }
154
155 // return blank XML document if response body doesn't exist
156 $response = ( isset( $response['body'] ) ) ? $response['body'] : '<?xml version="1.0" encoding="utf-8"?>';
157
158 return $response;
159 }
160
161 /**
162 * Parse xml response from the server
163 *
164 * @param $response string XML response from the server
165 *
166 * @return \SimpleXMLElement Parsed xml
167 * @since 1.0.0
168 */
169 public function parse_response( $response ) {
170 // Remove namespace as SimpleXML throws warnings with invalid namespace URI provided by Authorize.net
171 $response = preg_replace( '/[[:space:]]xmlns[^=]*="[^"]*"/i', '', $response );
172
173 // LIBXML_NOCDATA ensures that any XML fields wrapped in [CDATA] will be included as text nodes
174 $response = new SimpleXMLElement( $response, LIBXML_NOCDATA );
175
176 return $response;
177 }
178
179 /**
180 * Execute a request for payment transaction, and return parsed response
181 *
182 * @param $order \WC_Order Order to pay
183 * @param $payment_details \StdClass Payment details
184 *
185 * @return \SimpleXMLElement Parsed xml
186 * @since 1.0.0
187 */
188 public function create_payment_transaction( $order, $payment_details, $transaction_mode = 'authCaptureTransaction' ) {
189 $response = $this->do_request( $this->get_create_payment_transaction_xml( $order, $payment_details, $transaction_mode ) );
190
191 if ( ! $response ) {
192 return false;
193 }
194
195 return $this->parse_response( $response );
196 }
197
198 /**
199 * Execute a request for refund transaction, and return parsed response
200 *
201 * @param $order \WC_Order Order to refund
202 * @param $amount float Amount to refund
203 * @param $payment_details \StdClass Payment details, masked
204 *
205 * @return \SimpleXMLElement Parsed xml
206 * @since 1.0.0
207 */
208 public function crete_refund_transaction( $order, $amount, $payment_details ) {
209 $response = $this->do_request( $this->get_create_refund_transaction_xml( $order, $amount, $payment_details ) );
210
211 if ( ! $response ) {
212 return false;
213 }
214
215 return $this->parse_response( $response );
216 }
217
218 /**
219 * Execute a request for create customer profile, and return parsed response
220 *
221 * @param $user \WP_User User to map in Authorize.net servers
222 * @param $payment \StdClass|bool Payment details (false if no payment to add)
223 *
224 * @return \SimpleXMLElement Parsed xml
225 * @since 1.0.9
226 */
227 public function create_customer_profile( $user, $payment = false ) {
228 $response = $this->do_request( $this->get_create_customer_profile_xml( $user, $payment ) );
229
230 if ( ! $response ) {
231 return false;
232 }
233
234 return $this->parse_response( $response );
235 }
236
237 /**
238 * Execute a request for create customer payment profile, and return parsed response
239 *
240 * @param $order \WC_Order Order to use as a base for billTo section
241 * @param $customer_profile_id string Customer profile unique ID
242 * @param $payment \StdClass Payment details
243 *
244 * @return \SimpleXMLElement Parsed xml
245 * @since 1.0.0
246 */
247 public function create_customer_payment_profile( $order, $customer_profile_id, $payment ) {
248 $response = $this->do_request( $this->get_create_customer_payment_profile_xml( $order, $customer_profile_id, $payment ) );
249
250 if ( ! $response ) {
251 return false;
252 }
253
254 return $this->parse_response( $response );
255 }
256
257 /**
258 * Execute a request for create customer payment profile, and return parsed response
259 *
260 * @param $order \WC_Order Order to use as a base for billTo section
261 * @param $customer_profile_id string Customer profile unique ID
262 *
263 * @return \SimpleXMLElement Parsed xml
264 * @since 1.0.0
265 */
266 public function update_customer_profile( $order, $customer_profile_id ) {
267 $response = $this->do_request( $this->get_update_customer_profile_xml( $order, $customer_profile_id ) );
268
269 if ( ! $response ) {
270 return false;
271 }
272
273 return $this->parse_response( $response );
274 }
275
276 /**
277 * Execute a request for update customer payment profile, and return parsed response
278 *
279 * @param $order \WC_Order Order to use as a base for billTo section
280 * @param $customer_profile_id string Customer profile unique ID
281 * @param $customer_payment_profile_id string Customer payment profile unique ID
282 * @param $payment_details \StdClass Payment details
283 *
284 * @return \SimpleXMLElement Parsed xml
285 * @since 1.0.0
286 */
287 public function update_customer_payment_profile( $order, $customer_profile_id, $customer_payment_profile_id, $payment_details ) {
288 $response = $this->do_request( $this->get_update_customer_payment_profile_xml( $order, $customer_profile_id, $customer_payment_profile_id, $payment_details ) );
289
290 if ( ! $response ) {
291 return false;
292 }
293
294 return $this->parse_response( $response );
295 }
296
297 /**
298 * Execute a request for delete customer payment profile, and return parsed response
299 *
300 * @param $customer_profile_id string Customer profile unique ID
301 * @param $customer_payment_profile_id string Customer payment profile unique ID
302 *
303 * @return \SimpleXMLElement Parsed xml
304 * @since 1.0.0
305 */
306 public function delete_customer_payment_profile( $customer_profile_id, $customer_payment_profile_id ) {
307 $response = $this->do_request( $this->get_delete_customer_payment_profile_xml( $customer_profile_id, $customer_payment_profile_id ) );
308
309 if ( ! $response ) {
310 return false;
311 }
312
313 return $this->parse_response( $response );
314 }
315
316 /**
317 * Returns xml string to create a payment transaction on Authorize.net
318 *
319 * @param $order \WC_Order Order to pay
320 * @param $payment_details \StdClass Payment details
321 * @param $transaction_mode string Transaction mode
322 *
323 * @return string XML request
324 * @since 1.0.0
325 */
326 public function get_create_payment_transaction_xml( $order, $payment_details, $transaction_mode = 'authCaptureTransaction' ) {
327 // starts xml document
328 $this->xml_writer->openMemory();
329 $this->xml_writer->startDocument( '1.0', 'UTF-8' );
330
331 // <createTransactionRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
332 $this->xml_writer->startElementNs( null, 'createTransactionRequest', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' );
333
334 // adds authentication info
335 $this->add_auth_xml();
336
337 // <transactionRequest>
338 $this->xml_writer->startElement( 'transactionRequest' );
339
340 // <transactionType>authCaptureTransaction</transactionType>
341 $this->xml_writer->writeElement( 'transactionType', $transaction_mode );
342
343 // <amount>Order Amount</amount>
344 $this->xml_writer->writeElement( 'amount', $order->get_total() );
345
346 // <currencyCode>Order Currency Code</currencyCode>
347 $this->xml_writer->writeElement( 'currencyCode', method_exists( $order, 'get_currency' ) ? $order->get_currency() : $order->get_order_currency() );
348
349 // adds payment detail
350 $this->add_payment_xml( $payment_details );
351
352 // adds profile detail
353 $this->add_profile_xml( $payment_details );
354
355 // <order>
356 $this->xml_writer->startElement( 'order' );
357
358 // <invoiceNumber>Order ID</invoiceNumber>
359 $this->xml_writer->writeElement( 'invoiceNumber', apply_filters( 'yith_wcauthnet_invoice_number', $order->get_order_number(), $order ) );
360
361 // <description>Order description</description>
362 $this->xml_writer->writeElement( 'description', apply_filters( 'yith_wcauthnet_order_description', 'Order ' . $order->get_order_number(), $order ) );
363
364 // </order>
365 $this->xml_writer->endElement();
366
367 if ( $this->itemized ) {
368 // <lineItems>
369 $this->xml_writer->startElement( 'lineItems' );
370
371 // add line items informations for itemized transactions
372 $this->add_line_items_xml( $order );
373
374 // </lineItems>
375 $this->xml_writer->endElement();
376 }
377
378 if ( $order->get_total_tax() > 0 ) {
379 $this->add_tax_xml( $order );
380 }
381
382 if ( ( method_exists( $order, 'get_shipping_total' ) ? $order->get_shipping_total() : $order->get_total_shipping() ) > 0 ) {
383 $this->add_shipping_xml( $order );
384 }
385
386 // <customer>
387 $this->xml_writer->startElement( 'customer' );
388
389 $this->xml_writer->writeElement( 'id', method_exists( $order, 'get_customer_id' ) && $order->get_customer_id() ? $order->get_customer_id() : get_current_user_id() );
390
391 if ( $billing_email = yit_get_prop( $order, 'billing_email', true ) ) {
392 $this->xml_writer->writeElement( 'email', $billing_email );
393 }
394
395 // </customer>
396 $this->xml_writer->endElement();
397
398 // <billTo>
399 if ( $payment_details->type != 'profile' ) {
400 $this->xml_writer->startElement( 'billTo' );
401
402 // add billing informations
403 $this->add_address_xml( $order );
404
405 // </billTo>
406 $this->xml_writer->endElement();
407 }
408
409 if ( yit_get_prop( $order, 'shipping_country', true ) ) {
410 // <shipTo>
411 $this->xml_writer->startElement( 'shipTo' );
412
413 // add billing informations
414 $this->add_address_xml( $order, 'shipping' );
415
416 // </shipTo>
417 $this->xml_writer->endElement();
418 }
419
420 if ( $order->get_customer_ip_address() && filter_var( $order->get_customer_ip_address(), FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
421 // <customerIP>192.168.1.1</customerIP>
422 $this->xml_writer->writeElement( 'customerIP', $order->get_customer_ip_address() );
423 }
424
425 $this->add_user_info( $order );
426
427 // </transactionRequest>
428 $this->xml_writer->endElement();
429
430 // </createTransactionRequest>
431 $this->xml_writer->endElement();
432
433 // ends xml document and returns it
434 $this->xml_writer->endDocument();
435
436 return $this->xml_writer->outputMemory();
437 }
438
439 /**
440 * Returns xml string to create a refund transaction on Authorize.net
441 *
442 * @param $order \WC_Order Order to refund
443 * @param $amount float Amount to refund
444 * @param $payment_details \StdClass Payment details
445 *
446 * @return string XML request
447 * @since 1.0.0
448 */
449 public function get_create_refund_transaction_xml( $order, $amount, $payment_details ) {
450 if ( empty( $amount ) ) {
451 $amount = $order->get_total();
452 }
453
454 $trans_id = $order->get_transaction_id();
455 $order_total = $order->get_total();
456
457 /**
458 * When processing entire amount refund, transaction should be voided
459 *
460 * @since 1.1.14
461 */
462 $is_void = $order_total === $amount;
463
464 if ( empty( $trans_id ) ) {
465 return false;
466 }
467
468 // starts xml document
469 $this->xml_writer->openMemory();
470 $this->xml_writer->startDocument( '1.0', 'UTF-8' );
471
472 // <createTransactionRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
473 $this->xml_writer->startElementNs( null, 'createTransactionRequest', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' );
474
475 // adds authentication info
476 $this->add_auth_xml();
477
478 // <transactionRequest>
479 $this->xml_writer->startElement( 'transactionRequest' );
480
481 // <transactionType>authCaptureTransaction</transactionType>
482 $this->xml_writer->writeElement( 'transactionType', $is_void ? 'voidTransaction' : 'refundTransaction' );
483
484 // <refTransId>123456</refTransId>
485 $this->xml_writer->writeElement( 'refTransId', $trans_id );
486
487 // set refund amount only for partial refunds
488 if ( ! $is_void ) {
489 // <amount>Order Amount</amount>
490 $this->xml_writer->writeElement( 'amount', $amount );
491
492 // <currencyCode>Order Currency Code</currencyCode>
493 $this->xml_writer->writeElement( 'currencyCode', method_exists( $order, 'get_currency' ) ? $order->get_currency() : $order->get_order_currency() );
494
495 // adds payment detail
496 $this->add_payment_xml( $payment_details );
497 }
498
499 // </transactionRequest>
500 $this->xml_writer->endElement();
501
502 // </createTransactionRequest>
503 $this->xml_writer->endElement();
504
505 // ends xml document and returns it
506 $this->xml_writer->endDocument();
507
508 return $this->xml_writer->outputMemory();
509 }
510
511 /**
512 * Returns xml string to create a customer payment transaction on Authorize.net
513 *
514 * @param $user \WP_User User to map in Authorize.net servers
515 * @param $payment \StdClass|bool Payment details (false if no payment to add)
516 *
517 * @return string XML request
518 * @since 1.0.9
519 */
520 public function get_create_customer_profile_xml( $user, $payment = false ) {
521 // starts xml document
522 $this->xml_writer->openMemory();
523 $this->xml_writer->startDocument( '1.0', 'UTF-8' );
524
525 // <createCustomerPaymentProfileRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
526 $this->xml_writer->startElementNs( null, 'createCustomerProfileRequest', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' );
527
528 $this->add_auth_xml();
529
530 // <profile>
531 $this->xml_writer->startElement( 'profile' );
532
533 $this->xml_writer->writeElement( 'merchantCustomerId', $user->ID );
534 $this->xml_writer->writeElement( 'email', $user->user_email );
535
536 if ( false !== $payment ) {
537
538 // <paymentProfile>
539 $this->xml_writer->startElement( 'paymentProfiles' );
540
541 $this->add_payment_xml( $payment );
542
543 // </paymentProfiles>
544 $this->xml_writer->endElement();
545
546 }
547
548 // </profile>
549 $this->xml_writer->endElement();
550
551 $this->xml_writer->writeElement( 'validationMode', 'none' );
552
553 // </createCustomerProfileRequest>
554 $this->xml_writer->endElement();
555
556 // ends xml document and returns it
557 $this->xml_writer->endDocument();
558
559 return $this->xml_writer->outputMemory();
560 }
561
562 /**
563 * Returns xml string to create a customer payment profile transaction on Authorize.net
564 *
565 * @param $order \WC_Order Order to use as a base for billTo
566 * @param $customer_profile_id string Customer profile unique ID
567 * @param $payment \StdClass Payment details
568 *
569 * @return string XML request
570 * @since 1.0.0
571 */
572 public function get_create_customer_payment_profile_xml( $order, $customer_profile_id, $payment ) {
573 // starts xml document
574 $this->xml_writer->openMemory();
575 $this->xml_writer->startDocument( '1.0', 'UTF-8' );
576
577 // <createCustomerPaymentProfileRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
578 $this->xml_writer->startElementNs( null, 'createCustomerPaymentProfileRequest', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' );
579
580 $this->add_auth_xml();
581
582 $this->xml_writer->writeElement( 'customerProfileId', $customer_profile_id );
583
584 // <paymentProfile>
585 $this->xml_writer->startElement( 'paymentProfile' );
586
587 if ( ! is_null( $order ) ):
588
589 // <billTo>
590 $this->xml_writer->startElement( 'billTo' );
591
592 $this->add_address_xml( $order, 'billing' );
593
594 // </billTo>
595 $this->xml_writer->endElement();
596
597 endif;
598
599 $this->add_payment_xml( $payment );
600
601 // </paymentProfile>
602 $this->xml_writer->endElement();
603
604 $this->xml_writer->writeElement( 'validationMode', 'none' );
605
606 // </createCustomerPaymentProfileRequest>
607 $this->xml_writer->endElement();
608
609 // ends xml document and returns it
610 $this->xml_writer->endDocument();
611
612 return $this->xml_writer->outputMemory();
613 }
614
615 /**
616 * Returns xml string to update a customer profile transaction on Authorize.net
617 *
618 * @param $order \WC_Order Order to use as a base for billTo
619 * @param $customer_profile_id string Customer profile unique ID
620 *
621 * @return string XML request
622 * @since 1.0.0
623 */
624 public function get_update_customer_profile_xml( $order, $customer_profile_id ) {
625 $user_id = get_current_user_id();
626 $user = wp_get_current_user();
627 $user_email = ! empty( $user->billing_email ) ? $user->billing_email : $user->user_email;
628
629 // starts xml document
630 $this->xml_writer->openMemory();
631 $this->xml_writer->startDocument( '1.0', 'UTF-8' );
632
633 // <updateCustomerProfileRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
634 $this->xml_writer->startElementNs( null, 'updateCustomerProfileRequest', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' );
635
636 $this->add_auth_xml();
637
638 $this->xml_writer->startElement( 'profile' );
639
640 $this->xml_writer->writeElement( 'merchantCustomerId', $user_id );
641 $this->xml_writer->writeElement( 'email', is_null( $order ) ? $user_email : yit_get_prop( $order, 'billing_email', true ) );
642 $this->xml_writer->writeElement( 'customerProfileId', $customer_profile_id );
643
644 $this->xml_writer->endElement();
645
646 // </updateCustomerProfileRequest>
647 $this->xml_writer->endElement();
648
649 // ends xml document and returns it
650 $this->xml_writer->endDocument();
651
652 return $this->xml_writer->outputMemory();
653 }
654
655 /**
656 * Returns xml string to update a customer payment profile transaction on Authorize.net
657 *
658 * @param $order \WC_Order Order to use as a base for billTo
659 * @param $customer_profile_id string Customer profile unique ID
660 * @param $customer_payment_profile_id string Customer payment profile unique ID
661 * @param $payment_details \StdClass Payment details
662 * @param $is_default bool Wheter method should be default or not
663 *
664 * @return string XML request
665 * @since 1.0.0
666 */
667 public function get_update_customer_payment_profile_xml( $order, $customer_profile_id, $payment_profile_id, $payment_details, $is_default = false ) {
668 // starts xml document
669 $this->xml_writer->openMemory();
670 $this->xml_writer->startDocument( '1.0', 'UTF-8' );
671
672 // <updateCustomerProfileRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
673 $this->xml_writer->startElementNs( null, 'updateCustomerPaymentProfileRequest', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' );
674
675 $this->add_auth_xml();
676
677 $this->xml_writer->writeElement( 'customerProfileId', $customer_profile_id );
678
679 $this->xml_writer->startElement( 'paymentProfile' );
680
681 if ( ! is_null( $order ) ):
682
683 $this->xml_writer->startElement( 'billTo' );
684
685 $this->add_address_xml( $order );
686
687 $this->xml_writer->endElement();
688
689 endif;
690
691 $this->add_payment_xml( $payment_details );
692
693 $this->xml_writer->writeElement( 'customerPaymentProfileId', $payment_profile_id );
694
695 $this->xml_writer->writeElement( 'defaultPaymentProfile', $is_default );
696
697 $this->xml_writer->endElement();
698
699 $this->xml_writer->writeElement( 'validationMode', 'none' );
700
701 // </updateCustomerProfileRequest>
702 $this->xml_writer->endElement();
703
704 // ends xml document and returns it
705 $this->xml_writer->endDocument();
706
707 return $this->xml_writer->outputMemory();
708 }
709
710 /**
711 * Returns xml string to delete a customer profile transaction on Authorize.net
712 *
713 * @param $customer_profile_id string Customer profile unique ID
714 * @param $customer_payment_profile_id string Customer payment profile unique ID
715 *
716 * @return string XML request
717 * @since 1.0.0
718 */
719 public function get_delete_customer_payment_profile_xml( $customer_profile_id, $customer_payment_profile_id ) {
720 // starts xml document
721 $this->xml_writer->openMemory();
722 $this->xml_writer->startDocument( '1.0', 'UTF-8' );
723
724 // <deleteCustomerPaymentProfileRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
725 $this->xml_writer->startElementNs( null, 'deleteCustomerPaymentProfileRequest', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' );
726
727 $this->add_auth_xml();
728
729 $this->xml_writer->writeElement( 'customerProfileId', $customer_profile_id );
730
731 $this->xml_writer->writeElement( 'customerPaymentProfileId', $customer_payment_profile_id );
732
733 // </deleteCustomerPaymentProfileRequest>
734 $this->xml_writer->endElement();
735
736 // ends xml document and returns it
737 $this->xml_writer->endDocument();
738
739 return $this->xml_writer->outputMemory();
740 }
741
742 /**
743 * Add xml to authenticate merchant on Authorize.net servers
744 *
745 * @return void
746 * @since 1.0.0
747 */
748 protected function add_auth_xml() {
749
750 // <merchantAuthentication>
751 $this->xml_writer->startElement( 'merchantAuthentication' );
752
753 // <name>{api_login_id}</name>
754 $this->xml_writer->writeElement( 'name', $this->login_id );
755
756 // <transactionKey>{api_transaction_key}</transactionKey>
757 $this->xml_writer->writeElement( 'transactionKey', $this->transaction_key );
758
759 // </merchantAuthentication>
760 $this->xml_writer->endElement();
761 }
762
763 /**
764 * Add xml for an address (shipping or billig)
765 *
766 * @param $order \WC_Order Order from which retrieve address information
767 * @param $type string billing/shipping
768 * @param $fields array An array of field to print
769 *
770 * @return void
771 * @since 1.0.0
772 */
773 protected function add_address_xml( $order, $type = 'billing', $fields = array() ) {
774 if ( empty( $fields ) ) {
775 $fields = array(
776 'first_name',
777 'last_name',
778 'company',
779 'address',
780 'city',
781 'state',
782 'zip',
783 'country',
784 'phone'
785 );
786 }
787
788 foreach ( $fields as $field ) {
789
790 $field_name = $type . '_' . $field;
791 $xml_name = lcfirst( str_replace( ' ', '', ucwords( str_replace( '_', ' ', $field ) ) ) );
792
793 if ( 'shipping' == $type && 'phone' == $field ) {
794 continue;
795 }
796
797 if ( 'address' == $field ) {
798 $this->xml_writer->writeElement( 'address', yit_get_prop( $order, $type . '_address_1', true ) . ' ' . yit_get_prop( $order, $type . '_address_2', true ) );
799 continue;
800 }
801
802 if ( 'zip' == $field ) {
803 $this->xml_writer->writeElement( 'zip', yit_get_prop( $order, $type . '_postcode', true ) );
804 continue;
805 }
806
807 if ( 'phone' == $field ) {
808 $this->xml_writer->writeElement( 'phoneNumber', yit_get_prop( $order, 'billing_phone', true ) );
809 continue;
810 }
811
812 if ( 'country' == $field ) {
813 $this->xml_writer->writeElement( 'country', $this->convert_country_code( yit_get_prop( $order, $type . '_country', true ) ) );
814 continue;
815 }
816
817 if ( $field_value = yit_get_prop( $order, $field_name, true ) ) {
818 $this->xml_writer->writeElement( $xml_name, $field_value );
819 }
820 }
821 }
822
823 /**
824 * Add xml for payment information
825 *
826 * @param $payment \StdClass Payment details
827 *
828 * @return void
829 * @since 1.0.0
830 */
831 protected function add_payment_xml( $payment ) {
832 if ( $payment->type != 'profile' ) {
833 // <payment>
834 $this->xml_writer->startElement( 'payment' );
835
836 if ( 'echeck' === $payment->type ) {
837
838 // <bankAccount>
839 $this->xml_writer->startElement( 'bankAccount' );
840
841 if ( ! empty( $payment->routing_number ) ) {
842 $this->xml_writer->writeElement( 'routingNumber', $payment->routing_number );
843 }
844
845 if ( ! empty( $payment->account_number ) ) {
846 $this->xml_writer->writeElement( 'accountNumber', $payment->account_number );
847 }
848
849 if ( ! empty( $payment->name_on_account ) ) {
850 $this->xml_writer->writeElement( 'nameOnAccount', $payment->name_on_account );
851 }
852
853
854 // $this->xml_writer->writeElement( 'echeckType', 'WEB' );
855
856 // </bankAccount>
857 $this->xml_writer->endElement();
858
859 } elseif ( 'credit_card' === $payment->type ) {
860
861 // <creditCard>
862 $this->xml_writer->startElement( 'creditCard' );
863
864 if ( ! empty( $payment->card_number ) ) {
865 $this->xml_writer->writeElement( 'cardNumber', $payment->card_number );
866 }
867
868 if ( ! empty( $payment->expiration_date ) ) {
869 $this->xml_writer->writeElement( 'expirationDate', $payment->expiration_date );
870 }
871
872 if ( ! empty( $payment->cvv ) ) {
873 $this->xml_writer->writeElement( 'cardCode', $payment->cvv );
874 }
875
876 // </creditCard>
877 $this->xml_writer->endElement();
878 }
879
880 // </payment>
881 $this->xml_writer->endElement();
882 }
883 }
884
885 /**
886 * Add xml for profile information
887 *
888 * @param $payment \StdClass Payment details
889 *
890 * @return void
891 * @since 1.0.0
892 */
893 protected function add_profile_xml( $payment ) {
894 if ( $this->cim_handling && is_user_logged_in() ) {
895 // <profile>
896 $this->xml_writer->startElement( 'profile' );
897
898 if ( $payment->type != 'profile' && empty( $payment->customer_profile_id ) ) {
899 $this->xml_writer->writeElement( 'createProfile', true );
900 }
901
902 if ( ! empty( $payment->customer_profile_id ) ) {
903 $this->xml_writer->writeElement( 'customerProfileId', $payment->customer_profile_id );
904 }
905
906 if ( 'profile' === $payment->type ) {
907 $this->xml_writer->startElement( 'paymentProfile' );
908
909 $this->xml_writer->writeElement( 'paymentProfileId', $payment->payment_profile_id );
910
911 $this->xml_writer->endElement();
912 }
913
914 // </profile>
915 $this->xml_writer->endElement();
916 }
917 }
918
919 /**
920 * Add xml for items information
921 *
922 * @param $order \WC_Order Order to use to retrieve items
923 *
924 * @return void
925 * @since 1.0.0
926 */
927 protected function add_line_items_xml( $order ) {
928 $line_items = $order->get_items( 'line_item' );
929 $fees_item = $order->get_fees();
930
931 $order_items = array_merge( $line_items, $fees_item );
932 $counter = 0;
933
934 if ( ! empty( $order_items ) ) {
935 foreach ( $order_items as $item_id => $item ) {
936 if ( $counter >= 30 ) {
937 break;
938 }
939
940 // <lineItem>
941 $this->xml_writer->startElement( 'lineItem' );
942
943 // <itemId>Item id</itemId>
944 $this->xml_writer->writeElement( 'itemId', apply_filters( 'yith_wcauthnet_add_line_item_id', $item_id, $item, $order ) );
945 // <name>Item name</name>
946 $this->xml_writer->writeElement( 'name', htmlentities( mb_substr( $item['name'], 0, 20 ), ENT_QUOTES, 'UTF-8', false ) );
947 // <quantity>Item quantity</quantity>
948 $this->xml_writer->writeElement( 'quantity', isset( $item['qty'] ) ? $item['qty'] : 1 );
949 // <unitPrice>Item unit price</unitPrice>
950 $this->xml_writer->writeElement( 'unitPrice', $order->get_item_total( $item ) );
951 // </lineItem>
952 $this->xml_writer->endElement();
953
954 $counter ++;
955 }
956 }
957 }
958
959 /**
960 * Add xml for tax information
961 *
962 * @param $order \WC_Order Order to use to retrieve taxes
963 *
964 * @return void
965 * @since 1.0.0
966 */
967 protected function add_tax_xml( $order ) {
968
969 // <tax>
970 $this->xml_writer->startElement( 'tax' );
971
972 // <amount>
973 $this->xml_writer->writeElement( 'amount', round( $order->get_total_tax(), wc_get_price_decimals() ) );
974
975 // <name>
976 $this->xml_writer->writeElement( 'name', __( 'Taxes', 'yith-woocommerce-authorizenet-payment-gateway' ) );
977
978 $taxes = array();
979
980 foreach ( $order->get_tax_totals() as $tax_code => $tax ) {
981
982 $taxes[] = sprintf( '%s (%s) - %s', $tax->label, $tax_code, $tax->amount );
983 }
984
985 // </tax>
986 $this->xml_writer->endElement();
987 }
988
989 /**
990 * Add xml for shipping costs information
991 *
992 * @param $order \WC_Order Order to use to retrieve shipping costs
993 *
994 * @return void
995 * @since 1.0.0
996 */
997 protected function add_shipping_xml( $order ) {
998
999 // <shipping>
1000 $this->xml_writer->startElement( 'shipping' );
1001
1002 // <amount>
1003 $this->xml_writer->writeElement( 'amount', method_exists( $order, 'get_shipping_total' ) ? $order->get_shipping_total() : $order->get_total_shipping() );
1004
1005 // <name>
1006 $this->xml_writer->writeElement( 'name', __( 'Shipping', 'yith-woocommerce-authorizenet-payment-gateway' ) );
1007
1008 // </shipping>
1009 $this->xml_writer->endElement();
1010 }
1011
1012 /**
1013 * Add xml for user information
1014 *
1015 * @param $order \WC_Order Order to use to retrieve user informations
1016 *
1017 * @return void
1018 * @since 1.0.0
1019 */
1020 protected function add_user_info( $order ) {
1021 $user_info = apply_filters( 'yith_wcauthnet_user_info', array(
1022 'transaction_email' => yit_get_prop( $order, 'billing_email', true ),
1023 'transaction_amount' => $order->get_total()
1024 ), $order );
1025
1026 if ( ! empty( $user_info ) ) {
1027 $this->xml_writer->startElement( 'userFields' );
1028 foreach ( $user_info as $id => $value ) {
1029 $this->xml_writer->startElement( 'userField' );
1030
1031 $this->xml_writer->writeElement( 'name', $id );
1032 $this->xml_writer->writeElement( 'value', $value );
1033
1034 $this->xml_writer->endElement();
1035 }
1036 $this->xml_writer->endElement();
1037 }
1038 }
1039
1040 /**
1041 * Convert country code from ISO 3166-1 alpha-2 to ISO_3166-1 alpha-3
1042 *
1043 * @param $country string Original ISO 3166-1 alpha-2 code
1044 *
1045 * @return string Translated ISO 3166-1 alpha-3 code
1046 */
1047 protected function convert_country_code( $country ) {
1048 $countries = array(
1049 'AF' => 'AFG', //Afghanistan
1050 'AX' => 'ALA', //Åland Islands
1051 'AL' => 'ALB', //Albania
1052 'DZ' => 'DZA', //Algeria
1053 'AS' => 'ASM', //American Samoa
1054 'AD' => 'AND', //Andorra
1055 'AO' => 'AGO', //Angola
1056 'AI' => 'AIA', //Anguilla
1057 'AQ' => 'ATA', //Antarctica
1058 'AG' => 'ATG', //Antigua and Barbuda
1059 'AR' => 'ARG', //Argentina
1060 'AM' => 'ARM', //Armenia
1061 'AW' => 'ABW', //Aruba
1062 'AU' => 'AUS', //Australia
1063 'AT' => 'AUT', //Austria
1064 'AZ' => 'AZE', //Azerbaijan
1065 'BS' => 'BHS', //Bahamas
1066 'BH' => 'BHR', //Bahrain
1067 'BD' => 'BGD', //Bangladesh
1068 'BB' => 'BRB', //Barbados
1069 'BY' => 'BLR', //Belarus
1070 'BE' => 'BEL', //Belgium
1071 'BZ' => 'BLZ', //Belize
1072 'BJ' => 'BEN', //Benin
1073 'BM' => 'BMU', //Bermuda
1074 'BT' => 'BTN', //Bhutan
1075 'BO' => 'BOL', //Bolivia
1076 'BQ' => 'BES', //Bonaire, Saint Estatius and Saba
1077 'BA' => 'BIH', //Bosnia and Herzegovina
1078 'BW' => 'BWA', //Botswana
1079 'BV' => 'BVT', //Bouvet Islands
1080 'BR' => 'BRA', //Brazil
1081 'IO' => 'IOT', //British Indian Ocean Territory
1082 'BN' => 'BRN', //Brunei
1083 'BG' => 'BGR', //Bulgaria
1084 'BF' => 'BFA', //Burkina Faso
1085 'BI' => 'BDI', //Burundi
1086 'KH' => 'KHM', //Cambodia
1087 'CM' => 'CMR', //Cameroon
1088 'CA' => 'CAN', //Canada
1089 'CV' => 'CPV', //Cape Verde
1090 'KY' => 'CYM', //Cayman Islands
1091 'CF' => 'CAF', //Central African Republic
1092 'TD' => 'TCD', //Chad
1093 'CL' => 'CHL', //Chile
1094 'CN' => 'CHN', //China
1095 'CX' => 'CXR', //Christmas Island
1096 'CC' => 'CCK', //Cocos (Keeling) Islands
1097 'CO' => 'COL', //Colombia
1098 'KM' => 'COM', //Comoros
1099 'CG' => 'COG', //Congo
1100 'CD' => 'COD', //Congo, Democratic Republic of the
1101 'CK' => 'COK', //Cook Islands
1102 'CR' => 'CRI', //Costa Rica
1103 'CI' => 'CIV', //Côte d\'Ivoire
1104 'HR' => 'HRV', //Croatia
1105 'CU' => 'CUB', //Cuba
1106 'CW' => 'CUW', //Curaçao
1107 'CY' => 'CYP', //Cyprus
1108 'CZ' => 'CZE', //Czech Republic
1109 'DK' => 'DNK', //Denmark
1110 'DJ' => 'DJI', //Djibouti
1111 'DM' => 'DMA', //Dominica
1112 'DO' => 'DOM', //Dominican Republic
1113 'EC' => 'ECU', //Ecuador
1114 'EG' => 'EGY', //Egypt
1115 'SV' => 'SLV', //El Salvador
1116 'GQ' => 'GNQ', //Equatorial Guinea
1117 'ER' => 'ERI', //Eritrea
1118 'EE' => 'EST', //Estonia
1119 'ET' => 'ETH', //Ethiopia
1120 'FK' => 'FLK', //Falkland Islands
1121 'FO' => 'FRO', //Faroe Islands
1122 'FJ' => 'FIJ', //Fiji
1123 'FI' => 'FIN', //Finland
1124 'FR' => 'FRA', //France
1125 'GF' => 'GUF', //French Guiana
1126 'PF' => 'PYF', //French Polynesia
1127 'TF' => 'ATF', //French Southern Territories
1128 'GA' => 'GAB', //Gabon
1129 'GM' => 'GMB', //Gambia
1130 'GE' => 'GEO', //Georgia
1131 'DE' => 'DEU', //Germany
1132 'GH' => 'GHA', //Ghana
1133 'GI' => 'GIB', //Gibraltar
1134 'GR' => 'GRC', //Greece
1135 'GL' => 'GRL', //Greenland
1136 'GD' => 'GRD', //Grenada
1137 'GP' => 'GLP', //Guadeloupe
1138 'GU' => 'GUM', //Guam
1139 'GT' => 'GTM', //Guatemala
1140 'GG' => 'GGY', //Guernsey
1141 'GN' => 'GIN', //Guinea
1142 'GW' => 'GNB', //Guinea-Bissau
1143 'GY' => 'GUY', //Guyana
1144 'HT' => 'HTI', //Haiti
1145 'HM' => 'HMD', //Heard Island and McDonald Islands
1146 'VA' => 'VAT', //Holy See (Vatican City State)
1147 'HN' => 'HND', //Honduras
1148 'HK' => 'HKG', //Hong Kong
1149 'HU' => 'HUN', //Hungary
1150 'IS' => 'ISL', //Iceland
1151 'IN' => 'IND', //India
1152 'ID' => 'IDN', //Indonesia
1153 'IR' => 'IRN', //Iran
1154 'IQ' => 'IRQ', //Iraq
1155 'IE' => 'IRL', //Republic of Ireland
1156 'IM' => 'IMN', //Isle of Man
1157 'IL' => 'ISR', //Israel
1158 'IT' => 'ITA', //Italy
1159 'JM' => 'JAM', //Jamaica
1160 'JP' => 'JPN', //Japan
1161 'JE' => 'JEY', //Jersey
1162 'JO' => 'JOR', //Jordan
1163 'KZ' => 'KAZ', //Kazakhstan
1164 'KE' => 'KEN', //Kenya
1165 'KI' => 'KIR', //Kiribati
1166 'KP' => 'PRK', //Korea, Democratic People\'s Republic of
1167 'KR' => 'KOR', //Korea, Republic of (South)
1168 'KW' => 'KWT', //Kuwait
1169 'KG' => 'KGZ', //Kyrgyzstan
1170 'LA' => 'LAO', //Laos
1171 'LV' => 'LVA', //Latvia
1172 'LB' => 'LBN', //Lebanon
1173 'LS' => 'LSO', //Lesotho
1174 'LR' => 'LBR', //Liberia
1175 'LY' => 'LBY', //Libya
1176 'LI' => 'LIE', //Liechtenstein
1177 'LT' => 'LTU', //Lithuania
1178 'LU' => 'LUX', //Luxembourg
1179 'MO' => 'MAC', //Macao S.A.R., China
1180 'MK' => 'MKD', //Macedonia
1181 'MG' => 'MDG', //Madagascar
1182 'MW' => 'MWI', //Malawi
1183 'MY' => 'MYS', //Malaysia
1184 'MV' => 'MDV', //Maldives
1185 'ML' => 'MLI', //Mali
1186 'MT' => 'MLT', //Malta
1187 'MH' => 'MHL', //Marshall Islands
1188 'MQ' => 'MTQ', //Martinique
1189 'MR' => 'MRT', //Mauritania
1190 'MU' => 'MUS', //Mauritius
1191 'YT' => 'MYT', //Mayotte
1192 'MX' => 'MEX', //Mexico
1193 'FM' => 'FSM', //Micronesia
1194 'MD' => 'MDA', //Moldova
1195 'MC' => 'MCO', //Monaco
1196 'MN' => 'MNG', //Mongolia
1197 'ME' => 'MNE', //Montenegro
1198 'MS' => 'MSR', //Montserrat
1199 'MA' => 'MAR', //Morocco
1200 'MZ' => 'MOZ', //Mozambique
1201 'MM' => 'MMR', //Myanmar
1202 'NA' => 'NAM', //Namibia
1203 'NR' => 'NRU', //Nauru
1204 'NP' => 'NPL', //Nepal
1205 'NL' => 'NLD', //Netherlands
1206 'AN' => 'ANT', //Netherlands Antilles
1207 'NC' => 'NCL', //New Caledonia
1208 'NZ' => 'NZL', //New Zealand
1209 'NI' => 'NIC', //Nicaragua
1210 'NE' => 'NER', //Niger
1211 'NG' => 'NGA', //Nigeria
1212 'NU' => 'NIU', //Niue
1213 'NF' => 'NFK', //Norfolk Island
1214 'MP' => 'MNP', //Northern Mariana Islands
1215 'NO' => 'NOR', //Norway
1216 'OM' => 'OMN', //Oman
1217 'PK' => 'PAK', //Pakistan
1218 'PW' => 'PLW', //Palau
1219 'PS' => 'PSE', //Palestinian Territory
1220 'PA' => 'PAN', //Panama
1221 'PG' => 'PNG', //Papua New Guinea
1222 'PY' => 'PRY', //Paraguay
1223 'PE' => 'PER', //Peru
1224 'PH' => 'PHL', //Philippines
1225 'PN' => 'PCN', //Pitcairn
1226 'PL' => 'POL', //Poland
1227 'PT' => 'PRT', //Portugal
1228 'PR' => 'PRI', //Puerto Rico
1229 'QA' => 'QAT', //Qatar
1230 'RE' => 'REU', //Reunion
1231 'RO' => 'ROU', //Romania
1232 'RU' => 'RUS', //Russia
1233 'RW' => 'RWA', //Rwanda
1234 'BL' => 'BLM', //Saint Barthélemy
1235 'SH' => 'SHN', //Saint Helena
1236 'KN' => 'KNA', //Saint Kitts and Nevis
1237 'LC' => 'LCA', //Saint Lucia
1238 'MF' => 'MAF', //Saint Martin (French part)
1239 'SX' => 'SXM', //Sint Maarten / Saint Matin (Dutch part)
1240 'PM' => 'SPM', //Saint Pierre and Miquelon
1241 'VC' => 'VCT', //Saint Vincent and the Grenadines
1242 'WS' => 'WSM', //Samoa
1243 'SM' => 'SMR', //San Marino
1244 'ST' => 'STP', //São Tomé and Príncipe
1245 'SA' => 'SAU', //Saudi Arabia
1246 'SN' => 'SEN', //Senegal
1247 'RS' => 'SRB', //Serbia
1248 'SC' => 'SYC', //Seychelles
1249 'SL' => 'SLE', //Sierra Leone
1250 'SG' => 'SGP', //Singapore
1251 'SK' => 'SVK', //Slovakia
1252 'SI' => 'SVN', //Slovenia
1253 'SB' => 'SLB', //Solomon Islands
1254 'SO' => 'SOM', //Somalia
1255 'ZA' => 'ZAF', //South Africa
1256 'GS' => 'SGS', //South Georgia/Sandwich Islands
1257 'SS' => 'SSD', //South Sudan
1258 'ES' => 'ESP', //Spain
1259 'LK' => 'LKA', //Sri Lanka
1260 'SD' => 'SDN', //Sudan
1261 'SR' => 'SUR', //Suriname
1262 'SJ' => 'SJM', //Svalbard and Jan Mayen
1263 'SZ' => 'SWZ', //Swaziland
1264 'SE' => 'SWE', //Sweden
1265 'CH' => 'CHE', //Switzerland
1266 'SY' => 'SYR', //Syria
1267 'TW' => 'TWN', //Taiwan
1268 'TJ' => 'TJK', //Tajikistan
1269 'TZ' => 'TZA', //Tanzania
1270 'TH' => 'THA', //Thailand
1271 'TL' => 'TLS', //Timor-Leste
1272 'TG' => 'TGO', //Togo
1273 'TK' => 'TKL', //Tokelau
1274 'TO' => 'TON', //Tonga
1275 'TT' => 'TTO', //Trinidad and Tobago
1276 'TN' => 'TUN', //Tunisia
1277 'TR' => 'TUR', //Turkey
1278 'TM' => 'TKM', //Turkmenistan
1279 'TC' => 'TCA', //Turks and Caicos Islands
1280 'TV' => 'TUV', //Tuvalu
1281 'UG' => 'UGA', //Uganda
1282 'UA' => 'UKR', //Ukraine
1283 'AE' => 'ARE', //United Arab Emirates
1284 'GB' => 'GBR', //United Kingdom
1285 'US' => 'USA', //United States
1286 'UM' => 'UMI', //United States Minor Outlying Islands
1287 'UY' => 'URY', //Uruguay
1288 'UZ' => 'UZB', //Uzbekistan
1289 'VU' => 'VUT', //Vanuatu
1290 'VE' => 'VEN', //Venezuela
1291 'VN' => 'VNM', //Vietnam
1292 'VG' => 'VGB', //Virgin Islands, British
1293 'VI' => 'VIR', //Virgin Island, U.S.
1294 'WF' => 'WLF', //Wallis and Futuna
1295 'EH' => 'ESH', //Western Sahara
1296 'YE' => 'YEM', //Yemen
1297 'ZM' => 'ZMB', //Zambia
1298 'ZW' => 'ZWE', //Zimbabwe
1299 );
1300 $iso_code = isset( $countries[ $country ] ) ? $countries[ $country ] : $country;
1301
1302 return $iso_code;
1303 }
1304 }
1305}
1306
1307/**
1308 * Unique access to instance of YITH_WCAUTHNET_CIM_API class
1309 *
1310 * @return \YITH_WCAUTHNET_CIM_API
1311 * @since 1.0.0
1312 */
1313function YITH_WCAUTHNET_CIM_API() {
1314 return YITH_WCAUTHNET_CIM_API::get_instance();
1315}