· 4 years ago · Jul 04, 2021, 03:32 PM
1/**
2 * process scheduled subscription payment for Subscriptions 2.0
3 */
4 function woocommerce_process_scheduled_subscription_payment( $amount_to_charge, $order ) {
5
6 if( !is_object( $order ) ) {
7 $order = new WC_Order( $order );
8 }
9
10 // WooCommerce 3.0 compatibility
11 $order_id = is_callable( array( $order, 'get_id' ) ) ? $order->get_id() : $order->id;
12
13 // Check WC version - changes for WC 3.0.0
14 $pre_wc_30 = version_compare( WC_VERSION, '3.0', '<' );
15
16 /**
17 * Get parent order ID
18 */
19 $subscriptions = wcs_get_subscriptions_for_renewal_order( $order_id );
20 foreach( $subscriptions as $subscription ) {
21
22 $parent_order = is_callable( array( $subscription, 'get_parent' ) ) ? $subscription->get_parent() : $subscription->order;
23
24 $parent_order_id = is_callable( array( $parent_order, 'get_id' ) ) ? $parent_order->get_id() : $parent_order->id;
25 $subscription_id = is_callable( array( $subscription, 'get_id' ) ) ? $subscription->get_id() : $subscription->id;
26
27 }
28
29 // Check for token
30 $sagepaytoken = get_post_meta( $parent_order_id, '_SagePayDirectToken', true );
31
32 if( $sagepaytoken && $sagepaytoken != '' ) {
33 // Tokens
34 $VendorTxCode = 'Renewal-' . $parent_order_id . '-' . time();
35
36 // SAGE Line 50 Fix
37 $VendorTxCode = str_replace( 'order_', '', $VendorTxCode );
38
39 // make your query.
40 $data = array(
41 "Token" => $sagepaytoken,
42 "StoreToken" => "1",
43 "ApplyAVSCV2" => "2",
44 "Apply3DSecure" => "2",
45 "VPSProtocol" => $this->vpsprotocol,
46 "TxType" => "PAYMENT",
47 "Vendor" => $this->vendor,
48 "VendorTxCode" => $VendorTxCode,
49 "Amount" => urlencode( $amount_to_charge ),
50 "Currency" => WC_Sagepay_Common_Functions::get_order_currency( $order ),
51 "Description" => __( 'Order', 'woocommerce_sagepayform' ) . ' ' . str_replace( '#' , '' , $order->get_order_number() ),
52 "BillingSurname" => $pre_wc_30 ? $order->billing_last_name : $order->get_billing_last_name(),
53 "BillingFirstnames" => $pre_wc_30 ? $order->billing_first_name : $order->get_billing_first_name(),
54 "BillingAddress1" => $pre_wc_30 ? $order->billing_address_1 : $order->get_billing_address_1(),
55 "BillingAddress2" => $pre_wc_30 ? $order->billing_address_2 : $order->get_billing_address_2(),
56 "BillingCity" => $pre_wc_30 ? $order->billing_city : $order->get_billing_city(),
57 "BillingPostCode" => $this->billing_postcode( $pre_wc_30 ? $order->billing_postcode : $order->get_billing_postcode() ),
58 "BillingCountry" => $pre_wc_30 ? $order->billing_country : $order->get_billing_country(),
59 "BillingState" => WC_Sagepay_Common_Functions::sagepay_state( $pre_wc_30 ? $order->billing_country : $order->get_billing_country(), $pre_wc_30 ? $order->billing_state : $order->get_billing_state() ),
60 "BillingPhone" => $pre_wc_30 ? $order->billing_phone : $order->get_billing_phone(),
61 "DeliverySurname" => apply_filters( 'woocommerce_sagepay_direct_deliverysurname', $pre_wc_30 ? $order->shipping_last_name : $order->get_shipping_last_name(), $order ),
62 "DeliveryFirstnames"=> apply_filters( 'woocommerce_sagepay_direct_deliveryfirstname', $pre_wc_30 ? $order->shipping_first_name : $order->get_shipping_first_name(), $order ),
63 "DeliveryAddress1" => apply_filters( 'woocommerce_sagepay_direct_deliveryaddress1', $pre_wc_30 ? $order->shipping_address_1 : $order->get_shipping_address_1(), $order ),
64 "DeliveryAddress2" => apply_filters( 'woocommerce_sagepay_direct_deliveryaddress2', $pre_wc_30 ? $order->shipping_address_2 : $order->get_shipping_address_2(), $order ),
65 "DeliveryCity" => apply_filters( 'woocommerce_sagepay_direct_deliverycity', $pre_wc_30 ? $order->shipping_city : $order->get_shipping_city(), $order ),
66 "DeliveryPostCode" => apply_filters( 'woocommerce_sagepay_direct_deliverypostcode', $pre_wc_30 ? $order->shipping_postcode : $order->get_shipping_postcode(), $order ),
67 "DeliveryCountry" => apply_filters( 'woocommerce_sagepay_direct_deliverycountry', $pre_wc_30 ? $order->shipping_country : $order->get_shipping_country(), $order ),
68 "DeliveryState" => apply_filters( 'woocommerce_sagepay_direct_deliverystate', WC_Sagepay_Common_Functions::sagepay_state( $pre_wc_30 ? $order->shipping_country : $order->get_shipping_country(), $pre_wc_30 ? $order->shipping_state : $order->get_shipping_state() ), $order ),
69 "DeliveryPhone" => apply_filters( 'woocommerce_sagepay_direct_deliveryphone', $pre_wc_30 ? $order->billing_phone : $order->get_billing_phone(), $order ), "CustomerEMail" => $pre_wc_30 ? $order->billing_email : $order->get_billing_email(),
70 "AllowGiftAid" => $this->allowgiftaid,
71 "ClientIPAddress" => $this->get_ipaddress(),
72 "AccountType" => $this->accounttype,
73 "BillingAgreement" => $this->billingagreement,
74 "ReferrerID" => $this->referrerid,
75 "Website" => site_url()
76 );
77
78
79 $basket = WC_Sagepay_Common_Functions::get_basket( $this->basketoption, $order_id );
80
81 if ( $basket != NULL ) {
82
83 if ( $this->basketoption == 1 ) {
84 $data["Basket"] = $basket;
85 } elseif ( $this->basketoption == 2 ) {
86 $data["BasketXML"] = $basket;
87 }
88
89 }
90
91 /**
92 * Debugging
93 */
94 if ( $this->debug == true ) {
95 WC_Sagepay_Common_Functions::sagepay_debug( $data, $this->id, __('Sent to SagePay : ', 'woocommerce_sagepayform'), TRUE );
96 }
97
98 /**
99 * Convert the $data array for Sage
100 */
101 $data = http_build_query( $data, '', '&' );
102
103 /**
104 * Send $data to Sage
105 * @var [type]
106 */
107 $result = $this->sagepay_post( $data, $this->purchaseURL );
108
109 // Process the result
110 if ( 'OK' != $result['Status'] ) {
111
112 $content = 'There was a problem renewing this payment for order ' . $order_id . '. The Transaction ID is ' . $api_request['RelatedVPSTxId'] . '. The API Request is <pre>' .
113 print_r( $api_request, TRUE ) . '</pre>. SagePay returned the error <pre>' .
114 print_r( $result['StatusDetail'], TRUE ) . '</pre> The full returned array is <pre>' .
115 print_r( $result, TRUE ) . '</pre>. ';
116
117 wp_mail( $this->notification ,'SagePay Renewal Error ' . $result['Status'] . ' ' . time(), $content );
118
119 $ordernote = '';
120 foreach ( $result as $key => $value ) {
121 $ordernote .= $key . ' : ' . $value . "\r\n";
122 }
123
124 $order->add_order_note( __('Payment failed', 'woocommerce_sagepayform') . '<br />' . $ordernote );
125
126 WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $order, $product_id );
127
128 } else {
129
130 WC_Subscriptions_Manager::process_subscription_payments_on_order( $order );
131
132 $successful_ordernote = '';
133 foreach ( $result as $key => $value ) {
134 $successful_ordernote .= $key . ' : ' . $value . "\r\n";
135 }
136
137 $order->add_order_note( __('Payment completed', 'woocommerce_sagepayform') . '<br />' . $successful_ordernote );
138
139 update_post_meta( $order_id, '_VPSTxId' , str_replace( array('{','}'),'',$result['VPSTxId'] ) );
140 update_post_meta( $order_id, '_SecurityKey' , $result['SecurityKey'] );
141 update_post_meta( $order_id, '_TxAuthNo' , $result['TxAuthNo'] );
142
143 update_post_meta( $order_id, '_RelatedVPSTxId' , str_replace( array('{','}'),'',$result['VPSTxId'] ) );
144 update_post_meta( $order_id, '_RelatedSecurityKey' , $result['SecurityKey'] );
145 update_post_meta( $order_id, '_RelatedTxAuthNo' , $result['TxAuthNo'] );
146 update_post_meta( $order_id, '_RelatedVendorTxCode' , $VendorTxCode );
147 update_post_meta( $order_id, '_SagePayDirectToken', $sagepaytoken );
148
149
150 // WC()->cart->empty_cart();
151 $order->payment_complete( str_replace( array('{','}'),'',$result['VPSTxId'] ) );
152
153 do_action( 'woocommerce_sagepay_direct_payment_complete', $result, $order );
154
155 }
156
157 } else {
158 // Not tokens
159 global $wpdb;
160 /**
161 * Check for previous renewals for this subscription.
162 */
163 $previous_renewals = $wpdb->get_results( $wpdb->prepare( "
164 SELECT * FROM {$wpdb->postmeta} pm
165 LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
166 WHERE pm.meta_key = '%s'
167 AND pm.meta_value = '%s'
168 AND p.post_status IN ( '%s','%s' )
169 ORDER BY pm.post_id DESC
170 LIMIT 1
171 ", '_subscription_renewal', $subscription_id, 'wc-processing', 'wc-completed' )
172 );
173
174 /**
175 * $previous_renewal_id is used to get the Sage transaction information from the last successful renewal.
176 *
177 * Sage archives orders after 2 years, if we use the transaction information from the first order then
178 * orders will fail once the first order is archived.
179 */
180 if( isset( $previous_renewals[0]->post_id ) && '' != $previous_renewals[0]->post_id ) {
181 $previous_renewal_id = $previous_renewals[0]->post_id;
182 } else {
183 $previous_renewal_id = $parent_order_id;
184 }
185
186 // Set $previous_renewal_id = $parent_order_id if the last order does not have a '_RelatedVPSTxId'
187 if( !get_post_meta( $previous_renewal_id, '_RelatedVPSTxId', true ) || get_post_meta( $previous_renewal_id, '_RelatedVPSTxId', true ) == '' ) {
188 $previous_renewal_id = $parent_order_id;
189 }
190
191 $VendorTxCode = 'Renewal-' . $parent_order_id . '-' . time();
192
193 // SAGE Line 50 Fix
194 $VendorTxCode = str_replace( 'order_', '', $VendorTxCode );
195
196 // New API Request for repeat
197 $api_request = 'VPSProtocol=' . urlencode( $this->vpsprotocol );
198 $api_request .= '&TxType=REPEAT';
199 $api_request .= '&Vendor=' . urlencode( $this->vendor );
200 $api_request .= '&VendorTxCode=' . $VendorTxCode;
201 $api_request .= '&Amount=' . urlencode( $amount_to_charge );
202 $api_request .= '&Currency=' . get_post_meta( $previous_renewal_id, '_order_currency', true );
203 $api_request .= '&Description=Repeat payment for order ' . $parent_order_id;
204 $api_request .= '&RelatedVPSTxId=' . get_post_meta( $previous_renewal_id, '_RelatedVPSTxId', true );
205 $api_request .= '&RelatedVendorTxCode=' . get_post_meta( $previous_renewal_id, '_RelatedVendorTxCode', true );
206 $api_request .= '&RelatedSecurityKey=' . get_post_meta( $previous_renewal_id, '_RelatedSecurityKey', true );
207 $api_request .= '&RelatedTxAuthNo=' . get_post_meta( $previous_renewal_id, '_RelatedTxAuthNo', true );
208
209 // Send the request to sage for processing
210 $result = $this->sagepay_post( $api_request, $this->repeatURL );
211
212 // Process the result
213 if ( 'OK' != $result['Status'] ) {
214
215 $content = 'There was a problem renewing this payment for order ' . $order_id . '. The Transaction ID is ' . $api_request['RelatedVPSTxId'] . '. The API Request is <pre>' .
216 print_r( $api_request, TRUE ) . '</pre>. SagePay returned the error <pre>' .
217 print_r( $result['StatusDetail'], TRUE ) . '</pre> The full returned array is <pre>' .
218 print_r( $result, TRUE ) . '</pre>. ';
219
220 wp_mail( $this->notification ,'SagePay Renewal Error ' . $result['Status'] . ' ' . time(), $content );
221
222 $ordernote = '';
223 foreach ( $result as $key => $value ) {
224 $ordernote .= $key . ' : ' . $value . "\r\n";
225 }
226
227 $order->add_order_note( __('Payment failed', 'woocommerce_sagepayform') . '<br />' . $ordernote );
228
229 WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $order, $product_id );
230
231 } else {
232
233 WC_Subscriptions_Manager::process_subscription_payments_on_order( $order );
234
235 $successful_ordernote = '';
236 foreach ( $result as $key => $value ) {
237 $successful_ordernote .= $key . ' : ' . $value . "\r\n";
238 }
239
240 $order->add_order_note( __('Payment completed', 'woocommerce_sagepayform') . '<br />' . $successful_ordernote );
241
242 update_post_meta( $order_id, '_VPSTxId' , str_replace( array('{','}'),'',$result['VPSTxId'] ) );
243 update_post_meta( $order_id, '_SecurityKey' , $result['SecurityKey'] );
244 update_post_meta( $order_id, '_TxAuthNo' , $result['TxAuthNo'] );
245
246 update_post_meta( $order_id, '_RelatedVPSTxId' , str_replace( array('{','}'),'',$result['VPSTxId'] ) );
247 update_post_meta( $order_id, '_RelatedSecurityKey' , $result['SecurityKey'] );
248 update_post_meta( $order_id, '_RelatedTxAuthNo' , $result['TxAuthNo'] );
249 update_post_meta( $order_id, '_RelatedVendorTxCode' , $VendorTxCode );
250
251 // WC()->cart->empty_cart();
252 $order->payment_complete( str_replace( array('{','}'),'',$result['VPSTxId'] ) );
253
254 do_action( 'woocommerce_sagepay_direct_payment_complete', $result, $order );
255
256 }
257
258 }
259
260 } // process scheduled subscription payment