diff --git a/Tests/prepaymentwebhook_test.json b/Tests/prepaymentwebhook_test.json new file mode 100644 index 0000000..3e81ef8 --- /dev/null +++ b/Tests/prepaymentwebhook_test.json @@ -0,0 +1,242 @@ +{ + "_links": { + }, + "_embedded": { + "fx:items": [ + { + "_links": { + }, + "_embedded": { + "fx:item_options": [ + { + "_links": { + }, + "name": "size", + "value": "medium", + "price_mod": 0, + "weight_mod": 0, + "date_created": null, + "date_modified": null + }, + { + "_links": { + }, + "name": "color", + "value": "red", + "price_mod": 0, + "weight_mod": 0, + "date_created": null, + "date_modified": null + } + ], + "fx:item_category": { + "_links": { + }, + "admin_email_template_uri": "", + "customer_email_template_uri": "", + "code": "DEFAULT", + "name": "Default for all products", + "item_delivery_type": "flat_rate", + "max_downloads_per_customer": 3, + "max_downloads_time_period": 24, + "default_weight": 0, + "default_weight_unit": "LBS", + "default_length_unit": "IN", + "shipping_flat_rate_type": "per_item", + "shipping_flat_rate": 5, + "handling_fee_type": "none", + "handling_fee": 0, + "handling_fee_minimum": 0, + "handling_fee_percentage": 0, + "customs_value": 0, + "discount_type": "", + "discount_name": "", + "discount_details": "", + "send_customer_email": false, + "send_admin_email": false, + "admin_email": "", + "date_created": null, + "date_modified": null + } + }, + "item_category_uri": "https://api.foxycart.com/item_categories/100", + "name": "Example Product", + "price": 15.99, + "quantity": 1, + "quantity_min": 0, + "quantity_max": 0, + "weight": 0, + "code": "1234", + "parent_code": "", + "discount_name": "", + "discount_type": "", + "discount_details": "", + "subscription_frequency": "", + "subscription_start_date": null, + "subscription_next_transaction_date": null, + "subscription_end_date": null, + "is_future_line_item": false, + "shipto": "Me", + "url": "", + "image": "", + "length": 0, + "width": 0, + "height": 0, + "expires": 0, + "date_created": null, + "date_modified": "2017-07-20T04:13:08-0700" + }, + { + "_links": { + }, + "_embedded": { + "fx:item_category": { + "_links": { + }, + "admin_email_template_uri": "", + "customer_email_template_uri": "", + "code": "live", + "name": "Live Rates", + "item_delivery_type": "shipped", + "max_downloads_per_customer": 3, + "max_downloads_time_period": 24, + "default_weight": 5, + "default_weight_unit": "LBS", + "default_length_unit": "IN", + "shipping_flat_rate_type": "per_order", + "shipping_flat_rate": 1, + "handling_fee_type": "none", + "handling_fee": 0, + "handling_fee_minimum": 0, + "handling_fee_percentage": 0, + "customs_value": 0, + "discount_type": "", + "discount_name": "", + "discount_details": "", + "send_customer_email": false, + "send_admin_email": false, + "admin_email": "", + "date_created": null, + "date_modified": null + } + }, + "item_category_uri": "https://api.foxycart.com/item_categories/101", + "name": "Another Product", + "price": 20, + "quantity": 1, + "quantity_min": 0, + "quantity_max": 0, + "weight": 5, + "code": "foo321", + "parent_code": "", + "discount_name": "", + "discount_type": "", + "discount_details": "", + "subscription_frequency": "", + "subscription_start_date": null, + "subscription_next_transaction_date": null, + "subscription_end_date": null, + "is_future_line_item": false, + "shipto": "Me", + "url": "", + "image": "", + "length": 0, + "width": 0, + "height": 0, + "expires": 0, + "date_created": null, + "date_modified": "2017-07-20T04:14:03-0700" + } + ], + "fx:discounts": [ + { + "code": "coupon", + "amount": -3.6, + "name": "Default Discount", + "display": "-$3.60", + "is_taxable": false, + "is_future_discount": false + } + ], + "fx:custom_fields": [ + { + "name": "custom_note", + "value": "Happy Birthday!", + "is_hidden": 0 + }], + "fx:shipment": { + "address_name": "", + "first_name": "John", + "last_name": "Smith", + "company": "", + "address1": "Main Street", + "address2": "", + "city": "Saint Paul", + "region": "MN", + "postal_code": "55116", + "country": "US", + "origin_region": "TX", + "origin_postal_code": "77018", + "origin_country": "US", + "shipping_service_id": 0, + "shipping_service_description": "", + "is_residential": false, + "item_count": 2, + "total_weight": 5, + "total_customs_value": 0, + "total_handling_fee": 0, + "total_flat_rate_shipping": 5, + "total_item_price": 35.99, + "total_tax": 3.24, + "total_shipping": 0, + "total_price": 39.23 + }, + "fx:customer": { + "id": "1512345", + "first_name": "John", + "last_name": "Smith", + "email": "john@example.com", + "tax_id": "", + "is_anonymous": "0", + "_embedded": { + "fx:payments": [ + { + "cc_type": "plastic", + "cc_number_masked": "xxxx xxxx xxxx 4242", + "cc_exp_month": "10", + "cc_exp_year": "2020", + "purchase_order": null + } + ], + "fx:default_billing_address": { + "country": "US", + "region": "MN", + "city": "Saint Paul", + "postal_code": "55116", + "address1": "Main Street", + "address2": "", + "company": "", + "full_name": "John Smith", + "first_name": "John", + "last_name": "Smith", + "phone": "" + } + } + } + }, + "customer_uri": "", + "template_set_uri": "", + "language": "", + "locale_code": "en_US", + "customer_ip": "192.168.0.1", + "ip_country": "United States", + "session_name": "fcsid", + "session_id": "hvcv28l8md0qc8qt5rrjh4qo85", + "total_item_price": 35.99, + "total_tax": 3.24, + "total_shipping": 14.23, + "total_future_shipping": 0, + "total_order": 49.86, + "date_created": null, + "date_modified": "2017-07-20T04:12:25-0700" +} \ No newline at end of file diff --git a/prepaymentwebhookfunctions.php b/prepaymentwebhookfunctions.php new file mode 100644 index 0000000..64427bc --- /dev/null +++ b/prepaymentwebhookfunctions.php @@ -0,0 +1,74 @@ + true, + 'details' => '' + ); + + $log_file = './log.txt'; + $date = new DateTime(); + $date_string = $date->format('Y-m-d H:i:s'); + + $log_line = $date_string . ': ' . $cart_details['customer_ip'] . ' - '. $cart_details['_embedded']['fx:customer']['email'] . ' -- '; + + $no_stock_products = array(); + $limited_stock_products = array(); + + foreach($cart_details['_embedded']['fx:items'] as $item) { + $product_id = -1; + $code = $item['code']; + + $inv_code = "%" . $wpdb->esc_like($code) . "%"; + $sql = $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value LIKE %s", '_inventory_levels', $inv_code ); + $meta_list = $wpdb->get_results( $sql ); + + foreach ($meta_list as $meta) { + $product_id = $meta->post_id; + $val = unserialize($meta->meta_value); + if (!is_array($val)) $val = array(); + foreach ($val as $ivcode => $iv) { + if ($ivcode == $code) { + $inventory = $iv['count']; + if ($inventory === 0) { + array_push($no_stock_products, $item['name']); + } + else if ($item['quantity'] > $inventory) { + array_push($limited_stock_products, $item['name']); + } + break; + } + } + } + } + + $response_text = ""; + + if (count($no_stock_products) > 0) { + $response_text = "Sorry, we are currently out of stock of the following " . ((count($no_stock_products) > 1) ? "items" : "item") . ": " . join(", ", $no_stock_products) . ". Please remove " . ((count($no_stock_products) > 1) ? "them" : "it") . " from your cart and try again."; + } + + if (count($limited_stock_products) > 0) { + if ($response_text) { + $response_text .= "/n"; + } + $response_text .= "Sorry, we currently have only limited stock of the following " . ((count($limited_stock_products) > 1) ? "items" : "item") . ": " . join(", ", $limited_stock_products) . ". Please reduce the quantity of " . ((count($limited_stock_products) > 1) ? "them" : "it") . " in your cart and try again."; + } + + if ($response_text) { + $response['ok'] = false; + $response['details'] = $response_text; + } + + $log_line .= (string) $response['ok'] . "\n"; + $fp = fopen($log_file, 'a'); + fwrite($fp, $log_line); + + if ($local_test === false) { + header('Content-Type: application/json'); + } + return $response; +} +?> diff --git a/settings-page.php b/settings-page.php index e1ef89c..52e7992 100755 --- a/settings-page.php +++ b/settings-page.php @@ -247,6 +247,12 @@ function foxyshop_settings_page() { FoxyCart can be configured to send order information to a url on your website. If you want to use FoxyShop's datafeed and take advantage of inventory, user management and more, copy this url and enable the datafeed in your FoxyCart admin panel. +
+ + + + FoxyCart can be configured to send order information to a url on your website for a final check before completing the order. If you want to use FoxyShop's prepayment webhook and do a final check of inventory or for a custom prepayment check, copy this url and enable the prepayment webhook in your FoxyCart admin panel. +
diff --git a/templateredirect.php b/templateredirect.php index 47ad1a9..9f468ee 100755 --- a/templateredirect.php +++ b/templateredirect.php @@ -28,7 +28,7 @@ function foxyshop_theme_redirect() { $request_arr = explode("/",$wp->request); $request_start = $request_arr[0]; $request_end = end($request_arr); - $foxyshop_indicators = array(FOXYSHOP_PRODUCTS_SLUG, FOXYSHOP_PRODUCT_CATEGORY_SLUG, 'product-search', 'foxycart-datafeed-'.$foxyshop_settings['datafeed_url_key'], 'foxycart-sso-'.$foxyshop_settings['datafeed_url_key'], 'upload-'.$foxyshop_settings['datafeed_url_key']); + $foxyshop_indicators = array(FOXYSHOP_PRODUCTS_SLUG, FOXYSHOP_PRODUCT_CATEGORY_SLUG, 'product-search', 'foxycart-datafeed-'.$foxyshop_settings['datafeed_url_key'], 'foxycart-prepayment-webhook-'.$foxyshop_settings['datafeed_url_key'], 'foxycart-sso-'.$foxyshop_settings['datafeed_url_key'], 'upload-'.$foxyshop_settings['datafeed_url_key']); if (array_intersect($request_arr, $foxyshop_indicators)) { if (in_array(FOXYSHOP_PRODUCTS_SLUG, $request_arr) && $request_end != FOXYSHOP_PRODUCTS_SLUG) { $currentProduct = $request_end; @@ -57,6 +57,8 @@ function foxyshop_theme_redirect() { $currentPageName = 'product-search'; } elseif ($request_start == 'foxycart-datafeed-'.$foxyshop_settings['datafeed_url_key']) { $currentPageName = 'foxycart-datafeed-'.$foxyshop_settings['datafeed_url_key']; + } elseif ($request_start == 'foxycart-prepayment-webhook-'.$foxyshop_settings['datafeed_url_key']) { + $currentPageName = 'foxycart-prepayment-webhook-'.$foxyshop_settings['datafeed_url_key']; } elseif ($request_start == 'foxycart-sso-'.$foxyshop_settings['datafeed_url_key']) { $currentPageName = 'foxycart-sso-'.$foxyshop_settings['datafeed_url_key']; } elseif ($request_start == 'upload-'.$foxyshop_settings['datafeed_url_key']) { @@ -141,6 +143,15 @@ function foxyshop_theme_redirect() { include foxyshop_get_template_file('foxyshop-datafeed-endpoint.php'); die; + //FoxyCart Prepayment Webhook Endpoint + } elseif ($currentPageName == 'foxycart-prepayment-webhook-'.$foxyshop_settings['datafeed_url_key'] || $currentName == 'foxycart-prepayment-webhook-'.$foxyshop_settings['datafeed_url_key']) { + add_filter('body_class', 'foxyshop_body_class', 10, 2 ); + status_header(200); + if (!defined("IS_FOXYSHOP")) define("IS_FOXYSHOP", 1); + $wp_query->is_404 = false; + include foxyshop_get_template_file('foxyshop-prepayment-webhook-endpoint.php'); + die; + //FoxyCart SSO Endpoint } elseif ($currentPageName == 'foxycart-sso-'.$foxyshop_settings['datafeed_url_key'] || $currentName == 'foxycart-sso-'.$foxyshop_settings['datafeed_url_key']) { status_header(200); diff --git a/themefiles/foxyshop-prepayment-webhook-endpoint.php b/themefiles/foxyshop-prepayment-webhook-endpoint.php new file mode 100644 index 0000000..cc4dffd --- /dev/null +++ b/themefiles/foxyshop-prepayment-webhook-endpoint.php @@ -0,0 +1,59 @@ +