first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
/* order metabox */
.flexible_shipping_shipment_content span.description {
display: block;
}
.fs-saas-button-cancel-created {
float: right;
color: #a00;
margin-top: 5px;
}
.fs-saas-button-cancel-created:hover {
color: #a00;
cursor: pointer;
}
.flexible_shipping_shipment_content input[type=checkbox] {
float: left;
margin-right: 5px;
margin-top: 2px !important;
opacity: 1;
border-color: #888;
}
.flexible_shipping_shipment_content input[type=checkbox]:disabled {
opacity: 0.7;
border-color: rgba( 51, 51, 51, 0.5 );
}
.flexible_shipping_shipment_content p.fs-saas-status {
}
.flexible_shipping_shipment_content p.fs-saas-status span {
font-weight: bold;
color: #444;
}
.flexible_shipping_shipment_content p.fs-saas-status-fs-new {
color: #ffba00;
}
.flexible_shipping_shipment_content p.fs-saas-status-fs-created {
color: #d0c21f;
}
.flexible_shipping_shipment_content p.fs-saas-status-fs-confirmed {
color: #444;
}
.flexible_shipping_shipment_content p.fs-saas-status-fs-failed {
color: #a00;
}
.flexible_shipping_shipment_content p.fs-saas-status-fs-manifest {
color: #2ea2cc;
}
.flexible_shipping_shipment_content p.connection-error {
font-weight: bold;
color: #a00;
}
.flexible_shipping_shipment_content span.optional {
display: none;
}
.flexible_shipping_shipment_message {
color: green;
}
.flexible_shipping_shipment_message_error {
color: #a00 !important;
}
.flexible_shipping_shipment_message_error span {
color: #444;
font-weight: bold;
}

View File

@@ -0,0 +1,173 @@
function fs_select2() {
let elements = jQuery( '.fs_select2' );
if ( elements.length ) {
if (jQuery.fn.selectWoo) {
elements.selectWoo();
} else {
elements.select2();
}
}
}
function fs_shipment_removeParam(key, sourceURL) {
var rtn = sourceURL.split("?")[0],
param,
params_arr = [],
queryString = (sourceURL.indexOf("?") !== -1) ? sourceURL.split("?")[1] : "";
if (queryString !== "") {
params_arr = queryString.split("&");
for (var i = params_arr.length - 1; i >= 0; i -= 1) {
param = params_arr[i].split("=")[0];
if (param === key) {
params_arr.splice(i, 1);
}
}
rtn = rtn + "?" + params_arr.join("&");
}
return rtn;
}
function fs_shipment_trimChar(string, charToRemove) {
while(string.charAt(0)==charToRemove) {
string = string.substring(1);
}
while(string.charAt(string.length-1)==charToRemove) {
string = string.substring(0,string.length-1);
}
return string;
}
// Order functions
function fs_id( element ) {
return jQuery(element).closest('.flexible_shipping_shipment').attr('data-id');
}
function fs_data_set_val( data, name, val ) {
if ( typeof name == 'undefined' ) {
return data;
}
if ( name.indexOf("[") == -1 ) {
data[name] = val;
}
else {
var names = name.split("[");
var data2 = data;
var data3 = data;
var name2 = '';
jQuery.each(names,function(index,name) {
name2 = name.replace("]","");
if ( typeof data2[name2] == 'undefined' ) {
data2[name2] = {};
}
data3 = data2;
data2 = data2[name2];
});
data3[name2] = val;
}
return data;
}
function fs_ajax(button, id, fs_action) {
jQuery('.button-shipping').attr('disabled', true);
jQuery(button).parent().find('.spinner').css({visibility: 'visible'});
var data = {};
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_content input, #flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_content select, #flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_content textarea').each(function () {
if (jQuery(this).attr('type') == 'radio') {
data = fs_data_set_val( data, jQuery(this).attr('name'), jQuery('#flexible_shipping_shipment_' + id + ' input[name=' + jQuery(this).attr('name') + ']:checked').val() );
}
else if (jQuery(this).attr('type') == 'checkbox') {
if (jQuery(this).is(':checked')) {
data = fs_data_set_val( data, jQuery(this).attr('name'), jQuery(this).val() );
}
else {
data = fs_data_set_val( data, jQuery(this).attr('name'), '' );
}
}
else {
data = fs_data_set_val( data, jQuery(this).attr('name'), jQuery(this).val() );
}
});
var nonce = jQuery('#flexible_shipping_shipment_nonce_' + id).val();
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').hide();
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').removeClass("flexible_shipping_shipment_message_error");
jQuery.ajax({
url: fs_shipment_admin.ajax_url,
type: 'POST',
data: {
fs_action: fs_action,
action: 'flexible_shipping',
nonce: nonce,
shipment_id: id,
data: data,
},
dataType: 'json',
}).done(function (response) {
if (response) {
if (response == '0') {
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').show();
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').html("Invalid response: 0");
}
else if (response.status == 'success') {
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_content').html(response.content);
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').hide();
if ( typeof response.message != 'undefined' ) {
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').show();
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').html(response.message);
}
}
else {
if ( typeof response.content !== 'undefined' ) {
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_content').html(response.content);
}
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').addClass("flexible_shipping_shipment_message_error");
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').show();
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').html(response.message);
}
}
else {
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').addClass("flexible_shipping_shipment_message_error");
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').show();
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').html("Request failed: invalid method?");
}
}).always(function () {
jQuery('.button-shipping').attr('disabled', false);
jQuery('.shipping-spinner').parent().find('.spinner').css({visibility: 'hidden'});
fs_select2();
jQuery('#flexible_shipping_shipment_' + id).trigger( "flexible_shipping_ajax_fs_action_after" );
}).fail(function (jqXHR, textStatus) {
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').addClass("flexible_shipping_shipment_message_error");
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').show();
jQuery('#flexible_shipping_shipment_' + id + ' .flexible_shipping_shipment_message').html("Request failed: " + textStatus + " " + jqXHR.status);
})
}
jQuery(document).ready(function(){
if ( jQuery('#flexible_shipping_labels_url').length ) {
window.location.href = jQuery('#flexible_shipping_labels_url').attr('href');
}
if ( jQuery('a.shipping_manifest_download').length == 1 ) {
window.location.href = jQuery('a.shipping_manifest_download').attr('href');
}
if ( typeof window.history.pushState == 'function' ) {
var url = document.location.href;
var url2 = document.location.href;
url = fs_shipment_removeParam('bulk_flexible_shipping_labels', url);
url = fs_shipment_removeParam('bulk_flexible_shipping_send', url);
url = fs_shipment_removeParam('bulk_flexible_shipping_manifests', url);
url = fs_shipment_removeParam('bulk_flexible_shipping_no_labels_created', url);
url = fs_shipment_trimChar(url,'?');
if ( url != url2 ) {
window.history.pushState({}, "", url);
}
}
});

View File

@@ -0,0 +1,51 @@
{
"name": "wpdesk\/wp-wpdesk-fs-shipment",
"authors": [
{
"name": "Krzysiek",
"email": "krzysiek@wpdesk.pl"
}
],
"config": {
"platform": {
"php": "7.0.8"
},
"sort-packages": true
},
"require": {
"php": ">=7.0.8",
"wpdesk\/wp-builder": "^2.0",
"wpdesk\/wp-mutex": "^1.1",
"wpdesk\/wp-notice": "^3.2",
"wpdesk\/wp-wpdesk-fs-shipment-interfaces": "^1.0"
},
"require-dev": {
"10up\/wp_mock": "*",
"phpunit\/phpunit": "<7",
"squizlabs\/php_codesniffer": "^3.4.2",
"wp-coding-standards\/wpcs": "^0.14.1"
},
"autoload": {
"psr-4": {
"FSVendor\\": "src"
}
},
"autoload-dev": {
"classmap": [
"tests\/unit\/stubs"
]
},
"extra": {
"text-domain": "wp-wpdesk-fs-shipment",
"translations-folder": "lang",
"po-files": {
"pl_PL": "pl_PL.po"
}
},
"scripts": {
"phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
"phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
"phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
"phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage"
}
}

View File

@@ -0,0 +1,77 @@
<?php
/**
* Class ShipmentFunctionality
*
* @package WPDesk\FS\Shipment
*/
namespace FSVendor\WPDesk\FS\Shipment;
use Psr\Log\LoggerInterface;
use FSVendor\WPDesk\FS\Shipment\Label\SingleLabelFileDispatcher;
use FSVendor\WPDesk\FS\Shipment\Manifest\ManifestCustomPostType;
use FSVendor\WPDesk\FS\Shipment\Metabox\Ajax;
use FSVendor\WPDesk\FS\Shipment\Order\AddShippingMetabox;
use FSVendor\WPDesk\FS\Shipment\RestApi\OrderResponseDataAppender;
use FSVendor\WPDesk\FS\Shipment\Subscriptions\SubscriptionsIntegration;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
/**
* Can load shipment functionality.
*/
class Assets implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
const HANDLE = 'fs_shipment_admin';
/**
* @var string
*/
private $assets_url;
/**
* @var string
*/
private $scripts_version;
/**
* Assets constructor.
*
* @param string $assets_url .
* @param string $scripts_version .
*/
public function __construct($assets_url, $scripts_version)
{
$this->assets_url = $assets_url;
$this->scripts_version = $scripts_version;
}
/**
* Hooks.
*/
public function hooks()
{
\add_action('admin_enqueue_scripts', [$this, 'admin_enqueue_scripts']);
}
/**
* Admin enqueue scripts.
*/
public function admin_enqueue_scripts()
{
if ($this->should_enqueue_admin_scripts()) {
\wp_register_script(self::HANDLE, \trailingslashit($this->assets_url) . 'js/admin.js', array('jquery'), $this->scripts_version);
\wp_localize_script(self::HANDLE, self::HANDLE, array('ajax_url' => \admin_url('admin-ajax.php')));
\wp_enqueue_script(self::HANDLE);
\wp_enqueue_style(self::HANDLE, \trailingslashit($this->assets_url) . 'css/admin.css', array(), $this->scripts_version);
}
}
/**
* Should enqueue admin scripts?
*/
private function should_enqueue_admin_scripts()
{
$current_screen = \get_current_screen();
$wc_screen_id = \sanitize_title(\__('WooCommerce', 'woocommerce'));
if (!$current_screen) {
return \false;
}
if ('woocommerce_page_wc-orders' === $current_screen->id || \in_array($current_screen->post_type, array('shop_order', 'shop_subscription'), \true) || $wc_screen_id . '_page_wc-settings' === $current_screen->id) {
return \true;
}
return \false;
}
}

View File

@@ -0,0 +1,148 @@
<?php
namespace FSVendor\WPDesk\FS\Shipment\Checkout;
use FSVendor\WPDesk\Mutex\WordpressPostMutex;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
class ShipmentCreator implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
/**
* Is order processed on checkout?
*
* @var bool
*/
private $is_order_processed_on_checkout = \false;
public function hooks()
{
$last_priority = \PHP_INT_MAX;
\add_action('woocommerce_checkout_update_order_meta', array($this, 'create_shipping_for_order'), $last_priority);
\add_action('woocommerce_store_api_checkout_update_order_from_request', [$this, 'create_shipment_block_checkout'], $last_priority, 2);
}
/**
* @param \WC_Order $order .
* @param \WP_REST_Request $request .
*/
public function create_shipment_block_checkout($order, $request)
{
if ($order && !$this->is_order_processed_on_checkout) {
$shipments = fs_get_order_shipments($order->get_id());
if (0 === \count($shipments)) {
$this->is_order_processed_on_checkout = \true;
$this->create_shipping_for_order_and_cart($order, \WC()->cart);
}
}
}
/**
* Create shipping for order.
*
* @param int $order_id .
*/
public function create_shipping_for_order($order_id)
{
$order = \wc_get_order($order_id);
if ($order && !$this->is_order_processed_on_checkout) {
$mutex = $this->get_mutex($order);
$mutex->acquireLock();
$shipments = fs_get_order_shipments($order_id);
if (0 === \count($shipments)) {
$this->is_order_processed_on_checkout = \true;
$this->create_shipping_for_order_and_cart($order, \WC()->cart);
}
$mutex->releaseLock();
}
}
/**
* @param \WC_Order $order .
* @param \WC_Cart $cart .
*/
public function create_shipping_for_order_and_cart($order, $cart)
{
global $fs_package_id;
$order_shipping_methods = $order->get_shipping_methods();
$packages = $cart->get_shipping_packages();
$current_package = -1;
foreach ($order_shipping_methods as $shipping_id => $shipping_method) {
$current_package++;
$package_id = \array_keys($packages)[$current_package];
$fs_package_id = $package_id;
$fs_method = $this->get_fs_method_from_order_shipping_method($shipping_method);
if (!empty($fs_method['method_integration'])) {
$integration = $fs_method['method_integration'];
if (fs_shipment_integration_exists($integration) && $this->is_order_type_supported_by_integration($order->get_type(), $integration)) {
$shipment = $this->create_shipment_for_order_and_fs_shipping_method($order, $fs_method, $shipping_id, $shipping_method, $packages, $package_id);
/**
* Do actions when shipment is created via checkout.
*
* @param \WPDesk_Flexible_Shipping_Shipment $shipment Created shipment.
*/
\do_action('flexible_shipping_checkout_shipment_created', $shipment);
}
}
}
}
/**
* @param string $order_type .
* @param string $integration .
*
* @return bool
*/
private function is_order_type_supported_by_integration($order_type, $integration)
{
$supported = 'shop_order' === $order_type;
$supported = \apply_filters('flexible-shipping/shipment/supported-order-type/' . $integration, $supported, $order_type);
return \is_bool($supported) ? $supported : \false;
}
/**
* @param \WC_Order $order .
*
* @return WordpressPostMutex
* @codeCoverageIgnore
*/
protected function get_mutex(\WC_Order $order)
{
return \FSVendor\WPDesk\Mutex\WordpressPostMutex::fromOrder($order);
}
/**
* Create shipment for order and shipping method.
*
* @param \WC_Order $order Order.
* @param array $fs_method Flexible Shipping shipping method.
* @param string $shipping_id Shipping Id.
* @param \WC_Order_Item_Shipping $shipping_method Shipping method.
* @param array $packages Packages.
* @param int $package_id Package Id.
*
* @return \WPDesk_Flexible_Shipping_Shipment
*/
private function create_shipment_for_order_and_fs_shipping_method(\WC_Order $order, array $fs_method, $shipping_id, \WC_Order_Item_Shipping $shipping_method, array $packages, $package_id)
{
$shipment = fs_create_shipment($order, $fs_method);
try {
$shipment->set_meta('_fs_method', $fs_method);
$shipment->set_meta('_shipping_id', $shipping_id);
$shipment->set_meta('_shipping_method', $shipping_method);
$shipment->set_created_via_checkout();
$shipment->checkout($fs_method, $packages[$package_id]);
$shipment->save();
return $shipment;
} catch (\Exception $e) {
\wp_delete_post($shipment->get_id(), \true);
throw $e;
}
}
/**
* Get Flexible Shipping method from order shipping method meta data.
*
* @param \WC_Order_Item_Shipping $shipping_method .
*
* @return array
*/
private function get_fs_method_from_order_shipping_method($shipping_method)
{
$fs_method = $shipping_method->get_meta('_fs_method');
if (!\is_array($fs_method) || empty($fs_method)) {
return [];
}
return $fs_method;
}
}

View File

@@ -0,0 +1,140 @@
<?php
/**
* Class CustomPostType
*
* @package WPDesk\FS\Shipment
*/
namespace FSVendor\WPDesk\FS\Shipment;
use FSVendor\WPDesk\Mutex\WordpressPostMutex;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
/**
* Can register custom post type.
*/
class CustomPostType implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
const POST_TYPE_SHIPMENT = 'shipment';
/**
* Hooks.
*/
public function hooks()
{
\add_action('init', array($this, 'register_post_types'), 20);
\add_action('add_meta_boxes', array($this, 'add_meta_boxes'), 20, 2);
\add_action('woocommerce_order_details_after_order_table', array($this, 'woocommerce_order_details_after_order_table'));
\add_action('woocommerce_email_after_order_table', array($this, 'woocommerce_email_after_order_table'), 10, 2);
}
/**
* Register post types.
*/
public function register_post_types()
{
if (\post_type_exists(self::POST_TYPE_SHIPMENT)) {
return;
}
\register_post_type(self::POST_TYPE_SHIPMENT, array('labels' => array('name' => \__('Shipments', 'flexible-shipping'), 'singular_name' => \__('Shipment', 'flexible-shipping'), 'menu_name' => \__('Shipments', 'flexible-shipping'), 'parent_item_colon' => '', 'all_items' => \__('Shipments', 'flexible-shipping'), 'view_item' => \__('View Shipments', 'flexible-shipping'), 'add_new_item' => \__('Add new Shipment', 'flexible-shipping'), 'add_new' => \__('Add new Shipment', 'flexible-shipping'), 'edit_item' => \__('Edit Shipment', 'flexible-shipping'), 'update_item' => \__('Save Shipment', 'flexible-shipping'), 'search_items' => \__('Search Shipments', 'flexible-shipping'), 'not_found' => \__('Shipment not found', 'flexible-shipping'), 'not_found_in_trash' => \__('Shipment not found in trash', 'flexible-shipping')), 'description' => \__('Shipments.', 'flexible-shipping'), 'public' => \false, 'show_ui' => \false, 'capability_type' => 'post', 'capabilities' => array(), 'map_meta_cap' => \true, 'publicly_queryable' => \false, 'exclude_from_search' => \true, 'hierarchical' => \false, 'query_var' => \true, 'supports' => array('title'), 'has_archive' => \false, 'show_in_nav_menus' => \true, 'menu_icon' => 'dashicons-upload'));
$shipment_statuses = \apply_filters('flexible_shipping_register_shipment_statuses', array('fs-new' => array('label' => \_x('New', 'Shipment status', 'flexible-shipping'), 'public' => \false, 'exclude_from_search' => \false, 'show_in_admin_all_list' => \true, 'show_in_admin_status_list' => \true, 'label_count' => \_n_noop('New <span class="count">(%s)</span>', 'New <span class="count">(%s)</span>', 'flexible-shipping')), 'fs-created' => array('label' => \_x('Created', 'Shipment status', 'flexible-shipping'), 'public' => \false, 'exclude_from_search' => \false, 'show_in_admin_all_list' => \true, 'show_in_admin_status_list' => \true, 'label_count' => \_n_noop('Created <span class="count">(%s)</span>', 'Created <span class="count">(%s)</span>', 'flexible-shipping')), 'fs-confirmed' => array('label' => \_x('Confirmed', 'Shipment status', 'flexible-shipping'), 'public' => \false, 'exclude_from_search' => \false, 'show_in_admin_all_list' => \true, 'show_in_admin_status_list' => \true, 'label_count' => \_n_noop('Confirmed <span class="count">(%s)</span>', 'Confirmed <span class="count">(%s)</span>', 'flexible-shipping')), 'fs-manifest' => array('label' => \_x('Manifest created', 'Shipment status', 'flexible-shipping'), 'public' => \false, 'exclude_from_search' => \false, 'show_in_admin_all_list' => \true, 'show_in_admin_status_list' => \true, 'label_count' => \_n_noop('Confirmed <span class="count">(%s)</span>', 'Confirmed <span class="count">(%s)</span>', 'flexible-shipping')), 'fs-failed' => array('label' => \_x('Failed', 'Shipment status', 'flexible-shipping'), 'public' => \false, 'exclude_from_search' => \false, 'show_in_admin_all_list' => \true, 'show_in_admin_status_list' => \true, 'label_count' => \_n_noop('Failed <span class="count">(%s)</span>', 'Failed <span class="count">(%s)</span>', 'flexible-shipping'))));
foreach ($shipment_statuses as $shipment_status => $values) {
\register_post_status($shipment_status, $values);
}
}
/**
* Prepares class name for integration.
*
* @param string $integration .
*
* @return string
*/
public function prepare_integration_class_name($integration)
{
return \apply_filters('flexible_shipping_shipment_class', 'WPDesk_Flexible_Shipping_Shipment_' . $integration, $integration);
}
/**
* @param string $post_type .
* @param \WP_Post $post .
*/
public function add_meta_boxes($post_type, $post)
{
if (self::POST_TYPE_SHIPMENT === $post_type) {
\add_meta_box('shipment_meta_box', \__('Shipment data', 'flexible-shipping'), array($this, 'metabox'), 'shipment', 'normal', 'high');
}
if (\in_array($post_type, array('shop_order', 'shop_subscription', 'woocommerce_page_wc-orders'), \true)) {
$order = \wc_get_order($post);
$shipments = fs_get_order_shipments($order->get_id());
foreach ($shipments as $shipment) {
if ($this->should_add_metabox($shipment)) {
$args = array('shipment' => $shipment);
\add_meta_box('shipment_meta_box_' . $shipment->get_id(), $shipment->get_order_metabox_title(), array($this, 'order_metabox'), null, $shipment->get_order_metabox_context(), 'default', $args);
}
}
}
}
/**
* @param \WPDesk_Flexible_Shipping_Shipment $shipment .
*
* @return bool
*/
private function should_add_metabox($shipment)
{
$avaliable_integrations = \apply_filters('flexible_shipping_add_shipping_options', array());
return isset($avaliable_integrations[$shipment->get_integration()]);
}
/**
* @param \WP_Post $post .
* @param array $args .
*/
public function order_metabox($post, $args)
{
/** @var \WPDesk_Flexible_Shipping_Shipment $shipment */
$shipment = $args['args']['shipment'];
$shipment_id = $shipment->get_id();
$message = $shipment->get_error_message();
$message_heading = $shipment->get_order_metabox_title();
$message_css_style = '';
include __DIR__ . '/views/order-metabox.php';
}
/**
* .
*/
public function metabox()
{
global $post;
echo '<pre>';
\print_r($post);
echo '</pre>';
$meta_data = \get_post_meta($post->ID);
foreach ($meta_data as $key => $val) {
echo '<pre>';
echo \esc_html($key);
echo ' = ';
\print_r(\maybe_unserialize($val[0]));
echo '</pre>';
}
}
/**
* Hook woocommerce_order_details_after_order_table.
*
* @param \WC_Abstract_Order $order Order.
*/
public function woocommerce_order_details_after_order_table($order)
{
$order_id = $order->get_id();
$shipments = fs_get_order_shipments($order_id);
foreach ($shipments as $shipment) {
echo \wp_kses_post($shipment->get_after_order_table());
}
}
/**
* @param \WC_Order $order .
* @param bool $sent_to_admin .
*/
public function woocommerce_email_after_order_table($order, $sent_to_admin)
{
$order_id = $order->get_id();
$shipments = fs_get_order_shipments($order_id);
foreach ($shipments as $shipment) {
echo \wp_kses_post($shipment->get_email_after_order_table());
}
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace FSVendor\WPDesk\FS\Shipment\Exception;
/**
* .
*/
class UnableToCreateTmpFileException extends \RuntimeException
{
}

View File

@@ -0,0 +1,10 @@
<?php
namespace FSVendor\WPDesk\FS\Shipment\Exception;
/**
* .
*/
class UnableToCreateTmpZipFileException extends \RuntimeException
{
}

View File

@@ -0,0 +1,108 @@
<?php
/**
* Labels builders.
*
* @package Flexible Shipping
*/
namespace FSVendor\WPDesk\FS\Shipment\Label;
/**
* Can create labels for shipments.
*/
class LabelsBulkActionHandler
{
/**
* Builders.
*
* @var LabelsBulkActionHandler
*/
private static $labels_builder;
/**
* Labels builders collection.
*
* @var \WPDesk_Flexible_Shipping_Labels_Builder[]
*/
private $builders_collection = array();
/**
* Shipments.
*
* @var \WPDesk_Flexible_Shipping_Shipment_Interface[]
*/
private $shipments = array();
/**
* Add builder to builders collection.
*
* @param \WPDesk_Flexible_Shipping_Labels_Builder $builder .
*/
public function add_builder($builder)
{
$this->builders_collection[$builder->get_integration_id()] = $builder;
}
/**
* Bulk process orders.
*
* @param array $orders_ids .
*/
public function bulk_process_orders(array $orders_ids)
{
foreach ($orders_ids as $order_id) {
$shipments = fs_get_order_shipments($order_id);
foreach ($shipments as $shipment) {
$this->add_shipment($shipment);
}
}
}
/**
* Add shipment to labels builder.
*
* @param \WPDesk_Flexible_Shipping_Shipment $shipment .
*/
public function add_shipment($shipment)
{
if (isset($this->builders_collection[$shipment->get_integration()])) {
$this->builders_collection[$shipment->get_integration()]->add_shipment($shipment);
} else {
$this->shipments[] = $shipment;
}
}
/**
* Get labels for shipments from builders.
*
* @return array
*/
private function get_labels_for_shipments_from_builders()
{
$labels = array();
foreach ($this->builders_collection as $labels_builder) {
$labels = \array_merge($labels, $labels_builder->get_labels_for_shipments());
}
return $labels;
}
/**
* Get labels for shipments.
*
* @return array
* @throws \Exception
*/
public function get_labels_for_shipments()
{
$labels = $this->get_labels_for_shipments_from_builders();
foreach ($this->shipments as $shipment) {
$labels[] = $shipment->get_label();
}
return $labels;
}
/**
* Get builders.
*
* @return LabelsBulkActionHandler
*/
public static function get_labels_bulk_actions_handler()
{
if (empty(static::$labels_builder)) {
static::$labels_builder = new self();
}
return static::$labels_builder;
}
}

View File

@@ -0,0 +1,107 @@
<?php
/**
* Labels file creator.
*
* @package Flexible Shipping
*/
namespace FSVendor\WPDesk\FS\Shipment\Label;
use FSVendor\WPDesk\FS\Shipment\Exception\UnableToCreateTmpFileException;
use FSVendor\WPDesk\FS\Shipment\Exception\UnableToCreateTmpZipFileException;
/**
* Can create labels file.
* When there is one label file it creates file from this label.
* When there is more than one label file it creates zip file with all labels.
*/
class LabelsFileCreator
{
/**
* Labels.
*
* @var array
*/
private $labels = array();
/**
* File name.
*
* @var string
*/
private $file_name;
/**
* Tmp file name.
*
* @var string
*/
private $tmp_file_name;
/**
* .
*
* @param array $labels .
* @see WPDesk_Flexible_Shipping_Integration_Label_Builder::get_labels_for_shipments()
*/
public function __construct(array $labels)
{
$this->labels = $labels;
$this->prepare_file_names();
}
/**
* Create labels file.
*
* @throws UnableToCreateTmpZipFileException .
*/
public function create_labels_file()
{
if (1 === \count($this->labels)) {
\file_put_contents($this->tmp_file_name, $this->labels[0]['content']);
// phpcs:ignore
} else {
$zip = new \ZipArchive();
if (!$zip->open($this->tmp_file_name, \ZipArchive::CREATE)) {
throw new \FSVendor\WPDesk\FS\Shipment\Exception\UnableToCreateTmpZipFileException();
}
foreach ($this->labels as $label) {
if (isset($label['content'])) {
$zip->addFromString($label['file_name'], $label['content']);
}
}
}
}
/**
* Prepare file names.
*
* @throws UnableToCreateTmpFileException .
*/
private function prepare_file_names()
{
if (1 === \count($this->labels)) {
$this->file_name = $this->labels[0]['file_name'];
} else {
$this->file_name = 'labels.zip';
}
$this->tmp_file_name = @\tempnam('tmp', 'labels_');
// phpcs:ignore
if (!$this->tmp_file_name) {
throw new \FSVendor\WPDesk\FS\Shipment\Exception\UnableToCreateTmpFileException();
}
}
/**
* Get file name.
*
* @return string
*/
public function get_file_name()
{
return $this->file_name;
}
/**
* Get temporary file name.
* In this file we save labels.
*
* @return string
*/
public function get_tmp_file_name()
{
return $this->tmp_file_name;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Labels file dispatcher.
*
* @package Flexible Shipping
*/
namespace FSVendor\WPDesk\FS\Shipment\Label;
/**
* Can dispatch file to browser.
*/
class LabelsFileDispatcher
{
/**
* Dispatches and delete temporary labels file.
*
* @param string $file_name Filename to send to browser.
* @param string $tmp_file_path Temporary labels file name.
*/
public function dispatch_and_delete_labels_file($file_name, $tmp_file_path)
{
\header('Content-Description: File Transfer');
\header('Content-Type: application/octet-stream');
\header('Content-Disposition: attachment; filename="' . \basename($file_name) . '"');
\header('Expires: 0');
\header('Cache-Control: must-revalidate');
\header('Pragma: public');
\header('Content-Length: ' . \filesize($tmp_file_path));
\readfile($tmp_file_path);
// phpcs:ignore
\unlink($tmp_file_path);
}
}

View File

@@ -0,0 +1,95 @@
<?php
/**
* Single label file dispatcher.
*
* @package Flexible Shipping
*/
namespace FSVendor\WPDesk\FS\Shipment\Label;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
/**
* Can dispatch single label file.
*/
class SingleLabelFileDispatcher implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
const PRIORITY_VERY_LOW = 9999999;
const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
const ACTION_DOWNLOAD = 'download';
const ACTION_OPEN = 'open';
/**
* Hooks.
*/
public function hooks()
{
\add_action('admin_post_flexible_shipping_get_label', array($this, 'dispatch_label_if_requested'), self::PRIORITY_VERY_LOW);
}
/**
* @param array $label_data .
*
* @return string
*/
private function prepare_content_type_from_label_data(array $label_data)
{
if ('html' === $label_data['label_format']) {
return 'text/html';
}
return 'application/' . $label_data['label_format'];
}
/**
* @return string
*/
private function get_action_parameter()
{
return !empty($_GET['label_action']) ? \sanitize_text_field(\wp_unslash($_GET['label_action'])) : self::ACTION_DOWNLOAD;
// phpcs:ignore
}
/**
* @param array $label_data .
*
* @return string
*/
private function prepare_content_type(array $label_data)
{
if ($this->get_action_parameter() === self::ACTION_OPEN) {
return $this->prepare_content_type_from_label_data($label_data);
} else {
return self::DEFAULT_CONTENT_TYPE;
}
}
/**
* @param string $shipment_id .
*/
private function dispatch_label_and_die($shipment_id)
{
$shipment = fs_get_shipment($shipment_id);
$label_data = $shipment->get_label();
\header('Content-type: ' . $this->prepare_content_type($label_data));
if ($this->get_action_parameter() === self::ACTION_DOWNLOAD) {
\header('Content-Disposition: attachment; filename=' . $label_data['file_name']);
}
echo $label_data['content'];
// phpcs:ignore
die;
}
/**
* Output shipping label.
*
* @internal
*/
public function dispatch_label_if_requested()
{
\check_admin_referer('flexible_shipping_get_label');
$shipment_id = \filter_input(\INPUT_GET, 'shipment_id', \FILTER_VALIDATE_INT);
$integration = \get_post_meta($shipment_id, '_integration', \true);
if (!$integration) {
\wp_die(\__('Integration doesn\'t exists.', 'flexible-shipping'));
// phpcs:ignore
}
try {
$this->dispatch_label_and_die($shipment_id);
} catch (\Exception $e) {
\wp_die(\esc_html($e->getMessage()), \esc_html(\__('Label error', 'flexible-shipping')));
}
}
}

View File

@@ -0,0 +1,256 @@
<?php
namespace FSVendor\WPDesk\FS\Shipment\Manifest;
use FSVendor\WPDesk\Notice\Notice;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
class ManifestCustomPostType implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
public function hooks()
{
\add_action('init', [$this, 'register_post_types'], 20);
\add_action('admin_notices', [$this, 'add_admin_notices']);
\add_action('admin_init', [$this, 'cancel_manifest'], 20);
\add_action('admin_init', [$this, 'download_manifest'], 20);
\add_action('admin_menu', [$this, 'admin_menu'], 199);
\add_action('add_meta_boxes', [$this, 'add_meta_boxes'], 20, 2);
\add_action('trash_shipping_manifest', [$this, 'trash_shipping_manifest']);
\add_filter('manage_edit-shipping_manifest_columns', [$this, 'manage_edit_shipping_manifest_columns'], 11);
\add_action('manage_shipping_manifest_posts_custom_column', [$this, 'manage_shipping_manifest_posts_custom_column'], 11);
\add_filter('post_row_actions', [$this, 'shipping_manifest_row_actions'], 10, 2);
\add_action('do_meta_boxes', [$this, 'hide_publish_metabox']);
\add_filter('woocommerce_screen_ids', [$this, 'woocommerce_screen_ids']);
\add_filter('bulk_actions-edit-shipping_manifest', [$this, 'bulk_actions_edit_shipping_manifest']);
\add_action('restrict_manage_posts', [$this, 'restrict_manage_posts'], 9999);
\add_filter('parse_query', [$this, 'parse_query'], 999);
}
/**
* @return void
*
* @internal
*/
public function add_admin_notices()
{
$current_screen = \get_current_screen();
if ($current_screen && $current_screen->id === 'edit-shipping_manifest') {
$success = $_GET['success'] ?? '';
if ($success === '1') {
new \FSVendor\WPDesk\Notice\Notice(\__('Shipping manifest canceled.', 'flexible-shipping'));
}
if ($success === '0' && isset($_GET['message'])) {
$message = \sanitize_text_field($_GET['message']);
new \FSVendor\WPDesk\Notice\Notice($message, \FSVendor\WPDesk\Notice\Notice::NOTICE_TYPE_ERROR);
}
}
}
/**
* Register post types.
*/
public function register_post_types()
{
if (\post_type_exists('shipping_manifest')) {
return;
}
\register_post_type('shipping_manifest', ['labels' => ['name' => \__('Shipping Manifests', 'flexible-shipping'), 'singular_name' => \__('Shipping Manifest', 'flexible-shipping'), 'menu_name' => \__('Shipping Manifests', 'flexible-shipping'), 'parent_item_colon' => '', 'all_items' => \__('Shipping Manifests', 'flexible-shipping'), 'view_item' => \__('View Shipping Manifests', 'flexible-shipping'), 'add_new_item' => \__('Add new Shipping Manifest', 'flexible-shipping'), 'add_new' => \__('Add new Shipping Manifests', 'flexible-shipping'), 'edit_item' => \__('Edit Shipping Manifest', 'flexible-shipping'), 'update_item' => \__('Save Shipping Manifest', 'flexible-shipping'), 'search_items' => \__('Search Shipping Manifests', 'flexible-shipping'), 'not_found' => \__('Shipping Manifests not found', 'flexible-shipping'), 'not_found_in_trash' => \__('Shipping Manifests not found in trash', 'flexible-shipping')], 'description' => \__('Shipping Manifests.', 'flexible-shipping'), 'public' => \false, 'show_ui' => \true, 'capability_type' => 'post', 'capabilities' => ['create_posts' => \false], 'map_meta_cap' => \true, 'publicly_queryable' => \false, 'exclude_from_search' => \true, 'hierarchical' => \false, 'query_var' => \true, 'supports' => ['title'], 'has_archive' => \false, 'show_in_nav_menus' => \false, 'show_in_menu' => 'edit.php?post_type=shop_order', 'menu_icon' => 'dashicons-upload']);
}
public function admin_menu()
{
$show_in_menu = \current_user_can('manage_woocommerce') ? 'woocommerce' : \false;
if (\apply_filters('flexible_shipping_has_manifests', \false)) {
$slug = \add_submenu_page($show_in_menu, \__('Shipping Manifests', 'flexible-shipping'), \__('Shipping Manifests', 'flexible-shipping'), 'manage_woocommerce', 'edit.php?post_type=shipping_manifest');
}
}
public function add_meta_boxes($post_type, $post)
{
if ($post_type == 'shipping_manifest') {
\add_meta_box('shipping_manifest_shipments', \__('Shipments', 'flexible-shipping'), [$this, 'shipments_metabox'], 'shipping_manifest', 'normal', 'high');
}
}
public function metabox()
{
global $post;
echo '<pre>';
\print_r($post);
echo '</pre>';
$meta_data = \get_post_meta($post->ID);
foreach ($meta_data as $key => $val) {
echo '<pre>';
echo $key;
echo ' = ';
\print_r(\maybe_unserialize($val[0]));
echo '</pre>';
}
}
public function shipments_metabox()
{
global $post;
$manifest = fs_get_manifest($post->ID);
$shipments_array = $manifest->get_meta('_shipments', []);
$shipments = [];
foreach ($shipments_array as $shipment_id) {
$shipments[] = fs_get_shipment($shipment_id);
}
include __DIR__ . '/views/manifest-metabox.php';
}
public function manage_edit_shipping_manifest_columns($columns)
{
unset($columns['title']);
unset($columns['date']);
unset($columns['cb']);
$columns['manifest_date'] = \__('Date', 'flexible-shipping');
$columns['integration'] = \__('Integration', 'flexible-shipping');
$columns['external_number'] = \__('Number', 'flexible-shipping');
$columns['shipment_count'] = \__('Shipments count', 'flexible-shipping');
$columns['actions'] = \__('Actions', 'flexible-shipping');
return $columns;
}
public function shipping_manifest_row_actions($actions, $post)
{
if ($post->post_type == 'shipping_manifest') {
$actions = [];
}
return $actions;
}
public function manage_shipping_manifest_posts_custom_column($column)
{
global $post;
global $manifest;
$integrations = \apply_filters('flexible_shipping_integration_options', []);
if (empty($manifest) || $manifest->get_id() != $post->ID) {
$manifest = fs_get_manifest($post->ID);
}
if ($column == 'manifest_date') {
echo $manifest->get_date();
}
if ($column == 'integration') {
echo $integrations[$manifest->get_integration()];
}
if ($column == 'external_number') {
$download_manifest_url = \admin_url('edit.php?post_type=shipping_manifest&flexible_shipping_download_manifest=' . $manifest->get_id() . '&nonce=' . \wp_create_nonce('flexible_shipping_download_manifest'));
include __DIR__ . '/views/column-number.php';
}
if ($column == 'shipment_count') {
echo \count($manifest->get_meta('_shipments', []));
}
if ($column == 'actions') {
if ($manifest->get_status() != 'trash') {
$download_manifest_url = \admin_url('edit.php?post_type=shipping_manifest&flexible_shipping_download_manifest=' . $manifest->get_id() . '&nonce=' . \wp_create_nonce('flexible_shipping_download_manifest'));
$cancel_url = \admin_url('edit.php?post_type=shipping_manifest&flexible_shipping_cancel_manifest=' . $manifest->get_id() . '&nonce=' . \wp_create_nonce('flexible_shipping_cancel_manifest'));
include __DIR__ . '/views/column-actions.php';
}
}
}
public function woocommerce_screen_ids($screen_ids)
{
$screen_ids[] = 'edit-shipping_manifest';
$screen_ids[] = 'shipping_manifest';
return $screen_ids;
}
public function bulk_actions_edit_shipping_manifest($bulk_actions)
{
$bulk_actions = [];
return $bulk_actions;
}
public function cancel_manifest()
{
if (!empty($_GET['flexible_shipping_cancel_manifest']) && !empty($_GET['nonce'])) {
$nonce = \sanitize_text_field($_GET['nonce']);
if (!\wp_verify_nonce($nonce, 'flexible_shipping_cancel_manifest')) {
echo \__('Invalid nonce!', 'flexible-shipping');
exit;
}
$sendback = \admin_url('edit.php?post_type=shipping_manifest');
try {
$shipping_manifest_id = \sanitize_key($_GET['flexible_shipping_cancel_manifest']);
$shipping_manifest = fs_get_manifest($shipping_manifest_id);
$shipping_manifest->cancel();
fs_delete_manifest($shipping_manifest);
$sendback .= '&success=1';
\wp_safe_redirect($sendback);
exit;
} catch (\Exception $e) {
$sendback .= '&success=0&message=' . \sprintf(\__('Wystąpił błąd: %1$s', 'woocommerce-paczkomaty-inpost'), $e->getMessage());
\wp_safe_redirect($sendback);
exit;
}
}
}
public function download_manifest()
{
if (!empty($_GET['flexible_shipping_download_manifest']) && !empty($_GET['nonce'])) {
$nonce = \sanitize_text_field($_GET['nonce']);
if (!\wp_verify_nonce($nonce, 'flexible_shipping_download_manifest')) {
echo \__('Invalid nonce!', 'flexible-shipping');
}
try {
$shipping_manifest_id = \sanitize_key($_GET['flexible_shipping_download_manifest']);
$shipping_manifest = fs_get_manifest($shipping_manifest_id);
$manifest = $shipping_manifest->get_manifest();
\header("Content-type: application/octet-stream");
\header("Content-Disposition: attachment; filename=" . $manifest['file_name']);
echo $manifest['content'];
} catch (\FSVendor\WPDesk\FS\Shipment\Manifest\Exception $e) {
echo $e->getMessage();
}
exit;
}
}
public function hide_publish_metabox()
{
\remove_meta_box('submitdiv', 'shipping_manifest', 'side');
}
public function trash_shipping_manifest($post_id)
{
$manifest = fs_get_manifest($post_id);
$shipments_posts = \get_posts(['posts_per_page' => -1, 'post_type' => 'shipment', 'post_status' => 'any', 'meta_key' => '_manifest', 'meta_value' => $post_id]);
foreach ($shipments_posts as $shipment_post) {
$shipment = fs_get_shipment($shipment_post->ID);
$shipment->delete_meta('_manifest');
$shipment->update_status('fs-confirmed');
$shipment->save();
}
$manifest->delete_meta('_shipments');
$manifest->save();
}
public function restrict_manage_posts()
{
global $typenow;
if ('shipping_manifest' == $typenow) {
$integrations = \apply_filters('flexible_shipping_integration_options', []);
foreach ($integrations as $key => $integration) {
if (!\class_exists('WPDesk_Flexible_Shipping_Manifest_' . $key)) {
unset($integrations[$key]);
}
}
$integration = '';
if (isset($_GET['flexible_shipping_integration_filter'])) {
$integration = \sanitize_key($_GET['flexible_shipping_integration_filter']);
}
include __DIR__ . '/views/filter-form.php';
}
}
/**
* @param WP_Query $query .
*/
public function parse_query($query)
{
global $pagenow;
if ('edit.php' == $pagenow && \is_admin() && isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'shipping_manifest') {
$integration = '';
if (isset($_GET['flexible_shipping_integration_filter'])) {
$integration = \sanitize_key($_GET['flexible_shipping_integration_filter']);
}
if ($integration != '') {
if ($integration != '') {
if (!isset($query->query_vars['meta_query'])) {
$query->query_vars['meta_query'] = [];
}
$meta_query = [];
$meta_query['key'] = '_integration';
$meta_query['value'] = $integration;
$query->query_vars['meta_query'][] = $meta_query;
}
}
}
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace FSVendor;
/**
*
*/
?><a class="button button-primary" target="_blank" href="<?php
echo $download_manifest_url;
?>"><?php
\_e('Download', 'flexible-shipping');
?></a>
<a class="button" href="<?php
echo $cancel_url;
?>"><?php
\_e('Cancel', 'flexible-shipping');
?></a><?php

View File

@@ -0,0 +1,12 @@
<?php
namespace FSVendor;
/**
*
*/
?><a target="_blank" href="<?php
echo $download_manifest_url;
?>"><?php
echo $manifest->get_number();
?></a><?php

View File

@@ -0,0 +1,32 @@
<?php
namespace FSVendor;
/**
*
*/
?><div class="alignleft actions">
<select name="flexible_shipping_integration_filter">
<option value=""><?php
\_e('All manifests', 'flexible-shipping');
?></option>
<optgroup label="<?php
\_e('Integration', 'flexible-shipping');
?>">
<?php
foreach ($integrations as $key => $val) {
?>
<option value="<?php
echo $key;
?>" <?php
echo $key == $integration ? 'selected' : '';
?>><?php
echo $val;
?></option>
<?php
}
?>
</optgroup>
</select>
</div>
<?php

View File

@@ -0,0 +1,85 @@
<?php
namespace FSVendor;
/**
*
*/
?><table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>
</th>
<th>
<?php
\_e('Shipment', 'flexible-shipping');
?>
</th>
<th>
<?php
\_e('Order', 'flexible-shipping');
?>
</th>
</tr>
</thead>
<tbody id="the-list">
<?php
$count = 0;
?>
<?php
foreach ($shipments as $shipment) {
?>
<?php
$count++;
$order = $shipment->get_order();
if (\version_compare(\WC_VERSION, '2.7', '<')) {
$order_id = $order->id;
} else {
$order_id = $order->get_id();
}
?>
<tr>
<td>
<?php
echo $count;
?>
</td>
<td>
<a href="<?php
echo $shipment->get_order_metabox_url();
?>"><?php
echo $shipment->get_tracking_number();
?></a>
</td>
<td>
<a href="<?php
echo \admin_url('post.php?action=edit&post=' . $order_id);
?>"><?php
echo $order->get_order_number();
?></a>
</td>
</tr>
<?php
}
?>
</tbody>
<tfoot>
<tr>
<th>
</th>
<th>
<?php
\_e('Shipment', 'flexible-shipping');
?>
</th>
<th>
<?php
\_e('Order', 'flexible-shipping');
?>
</th>
</tr>
</tfoot>
</table><?php

View File

@@ -0,0 +1,62 @@
<?php
namespace FSVendor\WPDesk\FS\Shipment\Metabox;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
class Ajax implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
public function hooks()
{
\add_action('wp_ajax_flexible_shipping', array($this, 'wp_ajax_flexible_shipping'));
}
public function wp_ajax_flexible_shipping()
{
$json = array('status' => 'fail');
$json['message'] = \__('Unknown error!', 'flexible-shipping');
if (empty($_REQUEST['nonce']) || !\wp_verify_nonce(\sanitize_text_field($_REQUEST['nonce']), 'flexible_shipping_shipment_nonce')) {
$json['status'] = 'fail';
$json['message'] = \__('Nonce verification error! Invalid request.', 'flexible-shipping');
} else {
if (empty($_REQUEST['shipment_id'])) {
$json['status'] = 'fail';
$json['message'] = \__('No shipment id!', 'flexible-shipping');
} else {
if (empty($_REQUEST['data']) || !\is_array($_REQUEST['data'])) {
$json['status'] = 'fail';
$json['message'] = \__('No data!', 'flexible-shipping');
} else {
$shipment = fs_get_shipment(\intval($_REQUEST['shipment_id']));
$action = \sanitize_key($_REQUEST['fs_action']);
$data = $_REQUEST['data'];
try {
$ajax_request = $shipment->ajax_request($action, $data);
if (\is_array($ajax_request)) {
$json['content'] = $ajax_request['content'];
$json['message'] = '';
if (isset($ajax_request['message'])) {
$json['message'] = $ajax_request['message'];
}
} else {
$json['content'] = $ajax_request;
$json['message'] = '';
if ($action == 'save') {
$json['message'] = \__('Saved', 'flexible-shipping');
}
if ($action == 'send') {
$json['message'] = \__('Created', 'flexible-shipping');
}
}
$json['status'] = 'success';
if (!empty($ajax_request['status'])) {
$json['status'] = $ajax_request['status'];
}
} catch (\Exception $e) {
$json['status'] = 'fail';
$json['message'] = $e->getMessage();
}
}
}
}
\wp_send_json($json);
}
}

View File

@@ -0,0 +1,104 @@
<?php
/**
* Class WPDesk_Flexible_Shipping_Add_Shipping
*
* @package Flexible Shipping
*/
namespace FSVendor\WPDesk\FS\Shipment\Order;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
/**
* Can display maetabox and add new shipment.
*/
class AddShippingMetabox implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
/**
* Shipping added?
*
* @var bool
*/
private $shipping_added = \false;
/**
* Hooks.
*/
public function hooks()
{
\add_action('add_meta_boxes', array($this, 'add_meta_box'), 20, 2);
\add_action('admin_init', array($this, 'handle_add_shipping'));
}
/**
* Add shipping.
*
* @param string $integration Integration.
* @param array $get_data .
*/
private function add_shipping($integration, $get_data)
{
$class_name = \apply_filters('flexible_shipping_shipment_class', 'WPDesk_Flexible_Shipping_Shipment_' . $integration, $integration);
if (\class_exists($class_name)) {
$order = \wc_get_order(\sanitize_key($get_data['post']));
if ($order) {
$order_id = $order->get_id();
$integration = \sanitize_key($get_data['fs_add_shipping']);
// Translators: order id and integration.
$post_title = \sprintf(\__('Shipment for order %1$s, %2$s', 'flexible-shipping'), $order_id, $integration);
$shipment_post = array('post_title' => $post_title, 'post_type' => 'shipment', 'post_status' => 'fs-new', 'post_parent' => $order_id);
$shipment_id = \wp_insert_post($shipment_post);
\update_post_meta($shipment_id, '_integration', $integration);
$shipment = fs_get_shipment($shipment_id, $order);
$shipment->set_created_via_add_shipment();
if (\method_exists($shipment, 'admin_add_shipment')) {
$shipment->admin_add_shipment();
}
$shipment->save();
$this->shipping_added = \true;
}
}
}
/**
* Handle add shipping.
*/
public function handle_add_shipping()
{
if (isset($_GET['fs_add_shipping']) && isset($_GET['post']) && isset($_GET['_wpnonce'])) {
if (\wp_verify_nonce(\sanitize_key(\wp_unslash($_GET['_wpnonce'])), 'fs_add_shipping')) {
$integration = \sanitize_key($_GET['fs_add_shipping']);
$this->add_shipping($integration, $_GET);
}
}
}
/**
* Add metabox.
*
* @param string $post_type Post type.
* @param WP_Post $post Post.
*/
public function add_meta_box($post_type, $post)
{
if (\in_array($post_type, ['woocommerce_page_wc-orders', 'shop_order'], \true)) {
$select_options = \apply_filters('flexible_shipping_add_shipping_options', array());
if (\count($select_options)) {
$order = \wc_get_order($post);
$select_options = \array_merge(array('' => \__('Select integration', 'flexible-shipping')), $select_options);
$args = array('select_options' => $select_options, 'order_id' => $order->get_id());
\add_meta_box('add_shipping_meta_box', \__('Add shipping', 'flexible-shipping'), array($this, 'display_order_metabox'), null, 'side', 'default', $args);
}
}
}
/**
* Display order metabox.
*
* @param WP_Post $post Post.
* @param array $args Args.
*/
public function display_order_metabox($post, $args)
{
$select_options = $args['args']['select_options'];
$order_id = $args['args']['order_id'];
$add_shipping_url = \admin_url('post.php?post=' . $order_id . '&action=edit');
$add_shipping_url = \wp_nonce_url($add_shipping_url, 'fs_add_shipping');
$add_shipping_url = \str_replace('&amp;', '&', $add_shipping_url);
include __DIR__ . '/views/html-order-add_shipping-metabox.php';
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace FSVendor;
if (!\defined('ABSPATH')) {
exit;
}
$params = array(
'type' => 'select',
'options' => $select_options,
'class' => array('first', 'paczkomaty'),
//'label' => __( 'Integration ', 'flexible-shipping' ),
'id' => 'fs_add_shipping',
);
\woocommerce_form_field('fs_add_shipping', $params);
?>
<button id="fs_add_shipping_button" class="button button-primary" href="" disabled="disabled"><?php
\_e('Add', 'flexible-shipping');
?></button>
<script type="text/javascript">
jQuery('#fs_add_shipping').change(function(){
if ( jQuery(this).val() != '' ) {
jQuery('#fs_add_shipping_button').attr( 'disabled', false );
}
else {
jQuery('#fs_add_shipping_button').attr( 'disabled', true );
}
})
jQuery('#fs_add_shipping_button').click(function(e){
e.preventDefault();
window.location.href = '<?php
echo $add_shipping_url;
?>' + '&fs_add_shipping=' + jQuery('#fs_add_shipping').val();
});
if ( typeof window.history.pushState == 'function' ) {
var url = document.location.href;
var url2 = document.location.href;
url = fs_shipment_removeParam('_wpnonce', url);
url = fs_shipment_removeParam('fs_add_shipping', url);
url = fs_shipment_trimChar(url,'?');
if ( url != url2 ) {
window.history.pushState({}, "", url);
}
}
</script>
<?php

View File

@@ -0,0 +1,18 @@
<?php
namespace FSVendor\WPDesk\FS\Shipment\RestApi;
/**
* Defines interface that REST API Order Data Provider should implement.
*/
interface OrderDataProvider
{
/**
* Get data from shipment.
*
* @param \WPDesk_Flexible_Shipping_Shipment $shipment .
*
* @return array
*/
public function get_data_from_shipment($shipment);
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* Class WPDesk_Flexible_Shipping_Rest_Api_Order_Data_Provider_Default
*
* @package Flexible Shipping
*/
namespace FSVendor\WPDesk\FS\Shipment\RestApi;
/**
* Default data provider. Can get data from shipment.
*/
class OrderDataProviderDefault implements \FSVendor\WPDesk\FS\Shipment\RestApi\OrderDataProvider
{
const FS_INTEGRATION = '_fs_integration';
const FS_METHOD = '_fs_method';
const COMMON_KEYS_TO_REMOVE = array(self::FS_METHOD, self::FS_INTEGRATION, '_shipping_method', '_package', '_packages');
/**
* Keys to remove.
*
* @var array
*/
protected $keys_to_remove = array();
/**
* Get data from shipment.
*
* @param \WPDesk_Flexible_Shipping_Shipment $shipment .
*
* @return array
*/
public function get_data_from_shipment($shipment)
{
return $this->remove_internal_data_from_shipment_data(\get_post_meta($shipment->get_id()));
}
/**
* Filter data.
*
* @param array $data .
*
* @return array
*/
protected function remove_internal_data_from_shipment_data(array $data)
{
$keys_to_remove = \array_merge(self::COMMON_KEYS_TO_REMOVE, $this->keys_to_remove);
foreach ($keys_to_remove as $key) {
if (isset($data[$key])) {
unset($data[$key]);
}
}
return $this->format_data($data);
}
/**
* Format data.
*
* @param array $data .
*
* @return array
*/
private function format_data(array $data)
{
$formatted_data = array();
foreach ($data as $key => $value) {
if (\is_array($value) && isset($value[0])) {
$formatted_data[$key] = $value[0];
} else {
$formatted_data[$key] = $value;
}
}
return $formatted_data;
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace FSVendor\WPDesk\FS\Shipment\RestApi;
/**
* Data providers.
* Collects data providers and can return provider per integration or default provider.
*/
class OrderDataProvidersCollection
{
/**
* Providers.
*
* @var OrderDataProvider[]
*/
private $providers = array();
/**
* Add provider.
*
* @param string $integration .
* @param OrderDataProvider $provider .
*/
public function set_provider($integration, \FSVendor\WPDesk\FS\Shipment\RestApi\OrderDataProvider $provider)
{
$this->providers[$integration] = $provider;
}
/**
* Get provider for integration.
*
* @param string $integration .
*
* @return OrderDataProvider
*/
public function get_provider_for_integration($integration)
{
if (isset($this->providers[$integration])) {
return $this->providers[$integration];
}
return new \FSVendor\WPDesk\FS\Shipment\RestApi\OrderDataProviderDefault();
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace FSVendor\WPDesk\FS\Shipment\RestApi;
/**
* Data providers factory.
* @codeCoverageIgnore
*/
class OrderDataProvidersFactory
{
/**
* Providers.
*
* @var OrderDataProvidersCollection
*/
private static $data_providers;
/**
* Get data providers.
*
* @return OrderDataProvidersCollection
*/
public static function get_providers()
{
if (empty(self::$data_providers)) {
self::$data_providers = new \FSVendor\WPDesk\FS\Shipment\RestApi\OrderDataProvidersCollection();
}
return self::$data_providers;
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace FSVendor\WPDesk\FS\Shipment\RestApi;
use WC_Order;
use WP_REST_Request;
use WP_REST_Response;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
/**
* Can append shipments data to WooCommerce REST API Order response.
*/
class OrderResponseDataAppender implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
const REST_API_DATA_KEY = 'fs_shipping_lines';
/**
* Hooks.
*/
public function hooks()
{
\add_filter('woocommerce_rest_prepare_shop_order_object', array($this, 'maybe_append_shipment_to_order_data'), 10, 3);
}
/**
* Appends shipment data if exists to order in REST API response.
*
* @param WP_REST_Response $response .
* @param WC_Order $order .
* @param WP_REST_Request $request .
*
* @return WP_REST_Response
*/
public function maybe_append_shipment_to_order_data($response, $order, $request)
{
$shipments = fs_get_order_shipments($order->get_id());
if (!empty($shipments)) {
return $this->append_shipment_to_order_data($response, $order, $request, $shipments);
}
return $response;
}
/**
* Appends shipment data to order in REST API response.
*
* @param WP_REST_Response $response .
* @param WC_Order $order .
* @param WP_REST_Request $request .
* @param \WPDesk_Flexible_Shipping_Shipment[] $shipments .
*
* @return WP_REST_Response
*/
private function append_shipment_to_order_data($response, $order, $request, $shipments)
{
$response_data = $response->get_data();
if (empty($response_data[self::REST_API_DATA_KEY])) {
$response_data[self::REST_API_DATA_KEY] = array();
}
$providers = $this->get_providers();
foreach ($shipments as $shipment) {
$integration = $shipment->get_integration();
$data_provider = $providers->get_provider_for_integration($integration);
$response_data[self::REST_API_DATA_KEY][] = $data_provider->get_data_from_shipment($shipment);
}
$response->set_data($response_data);
return $response;
}
/**
* @return OrderDataProvidersCollection
* @codeCoverageIgnore
*/
protected function get_providers()
{
return \FSVendor\WPDesk\FS\Shipment\RestApi\OrderDataProvidersFactory::get_providers();
}
}

View File

@@ -0,0 +1,139 @@
<?php
/**
* Class ShipmentFunctionality
*
* @package WPDesk\FS\Shipment
*/
namespace FSVendor\WPDesk\FS\Shipment;
use Psr\Log\LoggerInterface;
use FSVendor\WPDesk\FS\Shipment\Label\SingleLabelFileDispatcher;
use FSVendor\WPDesk\FS\Shipment\Manifest\ManifestCustomPostType;
use FSVendor\WPDesk\FS\Shipment\Metabox\Ajax;
use FSVendor\WPDesk\FS\Shipment\Order\AddShippingMetabox;
use FSVendor\WPDesk\FS\Shipment\RestApi\OrderResponseDataAppender;
use FSVendor\WPDesk\FS\Shipment\Subscriptions\SubscriptionsIntegration;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
/**
* Can load shipment functionality.
*/
class ShipmentFunctionality implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
const LOAD_PRIORITY = -1;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var string
*/
private $assets_url;
/**
* @var string
*/
private $scripts_version;
/**
* @var bool
*/
private $already_loaded = \false;
/**
* ShipmentFunctionality constructor.
*
* @param LoggerInterface $logger .
* @param string $assets_url .
* @param string $scripts_version .
*/
public function __construct(\Psr\Log\LoggerInterface $logger, $assets_url, $scripts_version)
{
$this->logger = $logger;
$this->assets_url = $assets_url;
$this->scripts_version = $scripts_version;
}
/**
* Hooks.
*/
public function hooks()
{
\add_action('plugins_loaded', [$this, 'load_functionality_on_init'], self::LOAD_PRIORITY);
\add_filter('flexible-shipping/shipment/load-functionality', [$this, 'load_functionality_if_not_already_loaded']);
}
/**
* @internal
*/
public function load_functionality_on_init()
{
$this->already_loaded = (bool) \apply_filters('flexible-shipping/shipment/load-functionality', $this->already_loaded);
}
/**
* Load functionality if not already loaded;
*
* @param bool $already_loaded .
*
* @return bool
*
* @internal
*/
public function load_functionality_if_not_already_loaded($already_loaded)
{
$class = 'WPDesk_Flexible_Shipping_Shipment';
if (!$already_loaded && !\class_exists($class)) {
$this->load_functionality();
}
$this->already_loaded = \true;
return \true;
}
/**
* Load functionalituy.
* @codeCoverageIgnore
*/
protected function load_functionality()
{
$this->load_dependencies();
$class = 'WPDesk_Flexible_Shipping_Shipment';
$class::set_fs_logger($this->logger);
$shipment_cpt = new \FSVendor\WPDesk\FS\Shipment\CustomPostType();
$shipment_cpt->hooks();
$shipment_creator = new \FSVendor\WPDesk\FS\Shipment\Checkout\ShipmentCreator();
$shipment_creator->hooks();
$subscriptions_integration = new \FSVendor\WPDesk\FS\Shipment\Subscriptions\SubscriptionsIntegration($shipment_creator);
$subscriptions_integration->hooks();
$add_shipping_metabox = new \FSVendor\WPDesk\FS\Shipment\Order\AddShippingMetabox();
$add_shipping_metabox->hooks();
$single_label_file_dispatcher = new \FSVendor\WPDesk\FS\Shipment\Label\SingleLabelFileDispatcher();
$single_label_file_dispatcher->hooks();
$metabox_ajax = new \FSVendor\WPDesk\FS\Shipment\Metabox\Ajax();
$metabox_ajax->hooks();
$manifest_cpt = new \FSVendor\WPDesk\FS\Shipment\Manifest\ManifestCustomPostType();
$manifest_cpt->hooks();
$rest_api_order_response_data_appender = new \FSVendor\WPDesk\FS\Shipment\RestApi\OrderResponseDataAppender();
$rest_api_order_response_data_appender->hooks();
$assets = new \FSVendor\WPDesk\FS\Shipment\Assets($this->assets_url, $this->scripts_version);
$assets->hooks();
}
/**
* Load dependencies.
* @codeCoverageIgnore
*/
protected function load_dependencies()
{
$interfaces_dir = __DIR__ . '/../../../../../../../vendor/wpdesk/wp-wpdesk-fs-shipment-interfaces';
require_once $interfaces_dir . '/classes/shipment/interface-shipment.php';
require_once $interfaces_dir . '/classes/shipment/class-shipment.php';
require_once $interfaces_dir . '/classes/shipment/functions.php';
require_once $interfaces_dir . '/classes/manifest/functions.php';
require_once $interfaces_dir . '/classes/exception/class-cancel-shipment-exception.php';
require_once $interfaces_dir . '/classes/exception/class-get-label-exception.php';
require_once $interfaces_dir . '/classes/exception/class-label-not-available-exception.php';
require_once $interfaces_dir . '/classes/exception/class-send-shipment-exception.php';
require_once $interfaces_dir . '/classes/exception/class-shipment-plan-exceeded-exception.php';
require_once $interfaces_dir . '/classes/exception/class-shipment-unable-to-create-tmp-file-exception.php';
require_once $interfaces_dir . '/classes/exception/class-shipment-unable-to-create-tmp-zip-file-exception.php';
require_once $interfaces_dir . '/classes/label/interface-labels-builder.php';
require_once $interfaces_dir . '/classes/label/class-integration-label-builder.php';
require_once $interfaces_dir . '/classes/manifest/interface-manifest.php';
require_once $interfaces_dir . '/classes/manifest/class-manifest.php';
require_once $interfaces_dir . '/classes/manifest/class-manifest-fs.php';
require_once $interfaces_dir . '/classes/manifest/functions.php';
}
}

View File

@@ -0,0 +1,96 @@
<?php
/**
* Class SubscriptionsIntegration
*
* @package WPDesk\FS\Shipment
*/
namespace FSVendor\WPDesk\FS\Shipment\Subscriptions;
use FSVendor\WC_Subscriptions_Cart;
use FSVendor\WPDesk\FS\Shipment\Checkout\ShipmentCreator;
use FSVendor\WPDesk\FS\Shipment\CustomPostType;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
/**
* Integrates Shipments with WooCommerce Subscriptions plugin.
*/
class SubscriptionsIntegration implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
/**
* @var ShipmentCreator
*/
private $shipment_creator;
/**
* SubscriptionsIntegration constructor.
*
* @param ShipmentCreator $shipment_creator .
*/
public function __construct(\FSVendor\WPDesk\FS\Shipment\Checkout\ShipmentCreator $shipment_creator)
{
$this->shipment_creator = $shipment_creator;
}
/**
* .
*/
public function hooks()
{
$last_priority = \PHP_INT_MAX;
\add_action('woocommerce_checkout_subscription_created', array($this, 'create_shipping_for_subscription'), $last_priority, 3);
\add_filter('wcs_renewal_order_created', array($this, 'create_shipping_for_order_from_subscription'), 10, 2);
}
/**
* @param \WC_Subscription $subscription .
* @param \WC_Order $order .
* @param \WC_Cart $recurring_cart .
*/
public function create_shipping_for_subscription($subscription, $order, $recurring_cart)
{
$WC_Subscriptions_Cart = '\\' . 'WC_Subscriptions_Cart';
$WC_Subscriptions_Cart::set_calculation_type('recurring_total');
$this->shipment_creator->create_shipping_for_order_and_cart($subscription, $recurring_cart);
}
/**
* @param \WC_Order $order .
* @param \WC_Subscription $subscription .
*/
public function create_shipping_for_order_from_subscription($order, $subscription)
{
$subscription_shipments = fs_get_order_shipments($subscription->get_id());
foreach ($subscription_shipments as $shipment) {
$this->create_single_shipment($shipment, $order);
}
return $order;
}
/**
* @param \WPDesk_Flexible_Shipping_Shipment $shipment .
* @param \WC_Order $order .
*/
private function create_single_shipment($shipment, $order)
{
$meta_data = $shipment->get_meta_data();
$fs_method = $shipment->get_meta('_fs_method', array('method_integration' => $shipment->get_integration()));
$order_shipment = fs_create_shipment($order, $fs_method);
$integration = $order_shipment->get_integration();
$this->setup_shipment_meta_data($meta_data, $integration, $shipment, $order_shipment);
$order_shipment->save();
/**
* New shipment created from subscription.
*
* @param \WPDesk_Flexible_Shipping_Shipment $order_shipment Created shipment.
*/
\do_action('flexible-shipping/shipment-from-subscription/created/' . $integration, $order_shipment);
}
/**
* @param array $meta_data .
* @param string $integration .
* @param \WPDesk_Flexible_Shipping_Shipment $shipment .
* @param \WPDesk_Flexible_Shipping_Shipment $order_shipment .
*/
private function setup_shipment_meta_data(array $meta_data, $integration, $shipment, $order_shipment)
{
foreach ($meta_data as $meta_key => $meta_value) {
$order_shipment_meta_value = \apply_filters('flexible-shipping/shipment-from-subscription/meta-value/' . $integration, $shipment->get_meta($meta_key), $meta_key, $order_shipment);
$order_shipment->set_meta($meta_key, $order_shipment_meta_value);
}
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace FSVendor;
/**
*
*/
?><div class="flexible_shipping_shipment" id="flexible_shipping_shipment_<?php
echo $shipment->get_id();
?>" data-id="<?php
echo $shipment_id;
?>">
<?php
\wp_nonce_field('flexible_shipping_shipment_nonce', 'flexible_shipping_shipment_nonce_' . $shipment_id, \false);
?>
<div class="flexible_shipping_shipment_content">
<?php
$shipment->order_metabox();
?>
</div>
<div class="flexible_shipping_shipment_message flexible_shipping_shipment_message_error" style="<?php
echo $message_css_style;
?>">
<?php
echo $message;
?>
</div>
</div>
<?php