Initial commit
This commit is contained in:
282
pirateship-live-rates/pirateship-live-rates.php
Normal file
282
pirateship-live-rates/pirateship-live-rates.php
Normal file
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
/*
|
||||
Plugin Name: Pirateship Live Rates
|
||||
Plugin URI:
|
||||
Description: Query Pirateship for the rates of any given package
|
||||
Version: 0.1
|
||||
Author: Cavemanon
|
||||
Author URI:
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Copyright (C) 2024 Cavemanon
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if ( ! defined( 'WPINC' ) ){
|
||||
die('security by preventing any direct access to your plugin file');
|
||||
}
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
|
||||
function pirateship_shipping_method() {
|
||||
if (!class_exists('WC_Pirateship_Shipping_Method')) {
|
||||
class WC_Pirateship_Shipping_Method extends WC_Shipping_Method {
|
||||
public function __construct()
|
||||
{
|
||||
$this->id = 'pirateship-live-rates';
|
||||
$this->method_title = __('Pirateship Shipping', 'pirateship-live-rates');
|
||||
$this->method_description = __('Live rates from the Pirateship API', 'pirateship-live-rates');
|
||||
// Contreis availability
|
||||
$this->init();
|
||||
$this->enabled = isset($this->settings['enabled']) ? $this->settings['enabled'] : 'yes';
|
||||
$this->originCity = $this->settings['originCity'];
|
||||
$this->originRegionCode = $this->settings['originRegionCode'];
|
||||
$this->originZip = $this->settings['originZip'];
|
||||
$this->fallbackPrice = $this->settings['fallbackPrice'];
|
||||
}
|
||||
|
||||
/**
|
||||
Load the settings API
|
||||
*/
|
||||
function init()
|
||||
{
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options'));
|
||||
}
|
||||
|
||||
function init_form_fields()
|
||||
{
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __('Enable', 'pirateship-live-rates'),
|
||||
'type' => 'checkbox',
|
||||
'default' => 'yes'
|
||||
),
|
||||
'originCity' => array(
|
||||
'title' => __('Senders City', 'pirateship-live-rates'),
|
||||
'type' => 'text',
|
||||
'default' => 'Denver'
|
||||
),
|
||||
'originRegionCode' => array(
|
||||
'title' => __('Origin Region Code (State Abreviation)', 'pirateship-live-rates'),
|
||||
'type' => 'text',
|
||||
'default' => 'SC'
|
||||
),
|
||||
'originZip' => array(
|
||||
'title' => __('Origin ZIP Code', 'pirateship-live-rates'),
|
||||
'type' => 'text',
|
||||
'default' => '72014'
|
||||
),
|
||||
'fallbackPrice' => array(
|
||||
'title' => __('API Failure Fallback Price', 'pirateship-live-rates'),
|
||||
'type' => 'int',
|
||||
'default' => '15'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function calc($package): array {
|
||||
|
||||
#Only calculate shipping when checking out
|
||||
#if( is_checkout() == False) {
|
||||
# return [];
|
||||
#}
|
||||
|
||||
//No reason to ask if we don't even have a zip code.
|
||||
if ($package["destination"]["postcode"] === '') {
|
||||
#print("none found");
|
||||
return [];
|
||||
}
|
||||
|
||||
//Before we do any work, see if we got this request before.
|
||||
$cacheKey = hash('sha256', serialize($package));
|
||||
$cachedRate = get_transient($cacheKey);
|
||||
//If we've had it before, just get it from cache.
|
||||
if ($cachedRate != false) {
|
||||
#print("cached");
|
||||
return $cachedRate;
|
||||
}
|
||||
|
||||
$weight = 0;
|
||||
$cost = 0;
|
||||
foreach ($package['contents'] as $item_id => $values) {
|
||||
|
||||
|
||||
$_product = $values['data'];
|
||||
$weight = $weight + $_product->get_weight() * $values['quantity'];
|
||||
//TODO: Fix this so that shipping is per-item type rather than bulking everything together.
|
||||
$width = $_product->get_width();
|
||||
$length = $_product->get_length();
|
||||
$height = $_product->get_height();
|
||||
}
|
||||
//API only accepts ounces
|
||||
$weight = wc_get_weight($weight, 'lb') * 16;
|
||||
|
||||
//PHP reeks like shit from hell itself
|
||||
//but somehow, wordpress extensions made it worse by making you need to
|
||||
//VENDOR FUCKING DEPENDENCIES to get other people's code in
|
||||
//
|
||||
//So that's why this fucking garbage implementation of GraphQL is here
|
||||
//GOD, what fucking happened to software engineering!?
|
||||
|
||||
//GraphQL API url for pirateship
|
||||
$apiURL = 'https://ship.pirateship.com/api/graphql?opname=GetRates' ;
|
||||
|
||||
//GraphQL statement codified in JSON for the incoming query
|
||||
|
||||
$JSONQuery = json_encode(
|
||||
array(
|
||||
"operationName" => "GetRates",
|
||||
"query" => 'query GetRates($originZip: String!, $originCity: String, $originRegionCode: String, $destinationZip: String, $isResidential: Boolean, $destinationCountryCode: String, $weight: Float, $dimensionX: Float, $dimensionY: Float, $dimensionZ: Float, $mailClassKeys: [String!]!, $packageTypeKeys: [String!]!, $pricingTypes: [String!], $showUpsRatesWhen2x7Selected: Boolean) { rates( originZip: $originZip originCity: $originCity originRegionCode: $originRegionCode destinationZip: $destinationZip isResidential: $isResidential destinationCountryCode: $destinationCountryCode weight: $weight dimensionX: $dimensionX dimensionY: $dimensionY dimensionZ: $dimensionZ mailClassKeys: $mailClassKeys packageTypeKeys: $packageTypeKeys pricingTypes: $pricingTypes showUpsRatesWhen2x7Selected: $showUpsRatesWhen2x7Selected ) { title deliveryDescription trackingDescription serviceDescription pricingDescription cubicTier mailClassKey mailClass { accuracy international __typename } packageTypeKey zone surcharges { title price __typename } carrier { carrierKey title __typename } totalPrice priceBaseTypeKey basePrice crossedTotalPrice pricingType pricingSubType ratePeriodId learnMoreUrl cheapest fastest __typename }}',
|
||||
"variables" => array(
|
||||
"originZip" => (string)$this->originZip,
|
||||
"originCity" => (string)$this->originCity,
|
||||
"originRegionCode" => (string)$this->originRegionCode,
|
||||
"isResidential" => (bool)"true",
|
||||
"destinationZip" => (string)$package["destination"]["postcode"],
|
||||
"destinationCountryCode" => (string)$package["destination"]["country"],
|
||||
"mailClassKeys" => array("PriorityExpress","First","ParcelSelect","Priority","PriorityMailExpressInternational","FirstClassPackageInternationalService","PriorityMailInternational","Priority_Cubic","Priority_Regional_Rate_Box_A","Priority_Regional_Rate_Box_B","Priority_Flat_Rate_Envelope","Priority_Legal_Flat_Rate_Envelope","Priority_Padded_Flat_Rate_Envelope","Priority_Small_Flat_Rate_Box","Priority_Medium_Flat_Rate_Box","Priority_Large_Flat_Rate_Box","Priority_APO_FPO_DPO_Large_Flat_Rate_Box","PriorityExpress_Flat_Rate_Envelope","PriorityExpress_Legal_Flat_Rate_Envelope","PriorityExpress_Padded_Flat_Rate_Envelope","PriorityMailInternational_Flat_Rate_Envelope","PriorityMailInternational_Small_Flat_Rate_Box","PriorityMailInternational_Medium_Flat_Rate_Box","PriorityMailInternational_Large_Flat_Rate_Box","PriorityMailExpressInternational_Flat_Rate_Envelope","ParcelSelect_Cubic","GroundAdvantage","GroundAdvantage_Cubic","01","02","03","07","08","11","12","13","14","59","65","03_cubic","93"),
|
||||
"packageTypeKeys" => array("Parcel"),
|
||||
"weight" => (int)$weight,
|
||||
"dimensionX" => (int)$length,
|
||||
"dimensionY" => (int)$width,
|
||||
"dimensionZ" => (int)$height,
|
||||
"showUpsRatesWhen2x7Selected" => (bool)"true"
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$success = function() use (&$resp): bool {
|
||||
return is_array($resp) && (int)$resp['response']['code'] === 200;
|
||||
};
|
||||
|
||||
$tries = 1;
|
||||
while ($tries--) {
|
||||
$resp = wp_remote_post($apiURL, [
|
||||
'timeout' => 15,
|
||||
'sslverify' => true,
|
||||
//We're expecting JSON, tell the server this or it will shit itself.
|
||||
'headers' => array(
|
||||
'content-type' => 'application/json'
|
||||
),
|
||||
'body' => $JSONQuery,
|
||||
]);
|
||||
if ($success()) {
|
||||
break;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (!is_array($resp)) {
|
||||
throw new Error("API request transport error");
|
||||
}
|
||||
if (!$success()) {
|
||||
throw new Error("API request HTTP error");
|
||||
}
|
||||
|
||||
$resp = (string)$resp["body"];
|
||||
if ($resp === '') {
|
||||
throw new Error("API response is empty");
|
||||
}
|
||||
|
||||
#print($JSONQuery);
|
||||
#print($resp);
|
||||
#print(implode(',', array_keys($resp["body"])));
|
||||
|
||||
$prices = json_decode($resp, True);
|
||||
|
||||
|
||||
if (array_key_exists("errors", $prices)){
|
||||
$option = array(
|
||||
'id' => "Fallback Price",
|
||||
'label' => "Fallback Price - Failed to get shipping rate. Refresh page and report problem to Site Administrator if problem persists.",
|
||||
'cost' => (int)$this->fallbackPrice,
|
||||
);
|
||||
|
||||
$options = [];
|
||||
array_push($options, $option);
|
||||
return $options;
|
||||
}
|
||||
|
||||
$options = [];
|
||||
|
||||
foreach($prices["data"] as $rateContainer) {
|
||||
foreach($rateContainer as $rate) {
|
||||
$title = $rate["title"];
|
||||
$duration = $rate["deliveryDescription"];
|
||||
$totalPrice = $rate["totalPrice"];
|
||||
|
||||
$option = array(
|
||||
'id' => "$title",
|
||||
'label' => "$title - $duration",
|
||||
'cost' => $totalPrice
|
||||
);
|
||||
array_push($options, $option);
|
||||
}
|
||||
}
|
||||
|
||||
set_transient($cacheKey, $options, DAY_IN_SECONDS);
|
||||
|
||||
return $options;
|
||||
|
||||
}
|
||||
|
||||
public function calculate_shipping($package = []): void {
|
||||
try {
|
||||
$stampageRates = $this->calc($package);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$msg = $e->getMessage();
|
||||
$debug->recordError($msg);
|
||||
self::logger()->error($msg);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($stampageRates as $stampage) {
|
||||
$this->add_rate($stampage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_action('woocommerce_shipping_init', 'pirateship_shipping_method');
|
||||
function add_pirateship_shipping_method($methods)
|
||||
{
|
||||
$methods['pirateship_shipping_method'] = 'WC_Pirateship_Shipping_Method';
|
||||
return $methods;
|
||||
}
|
||||
|
||||
add_filter('woocommerce_shipping_methods', 'add_pirateship_shipping_method');
|
||||
|
||||
add_action('woocommerce_checkout_update_order_review', 'action_woocommerce_checkout_update_order_review', 10, 1);
|
||||
function action_woocommerce_checkout_update_order_review( $posted_data )
|
||||
{
|
||||
global $woocommerce;
|
||||
$packages = $woocommerce->cart->get_shipping_packages();
|
||||
foreach( $packages as $package_key => $package ) {
|
||||
$session_key = 'shipping_for_package_'.$package_key;
|
||||
$stored_rates = WC()->session->__unset( $session_key );
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user