Merge pull request #22329 from woocommerce/enhancement-manual-stock-changes/21754
Product stock adjustments with manual order line item changes
This commit is contained in:
commit
5397e4ec1a
|
@ -560,6 +560,13 @@ jQuery( function ( $ ) {
|
||||||
if ( response.success ) {
|
if ( response.success ) {
|
||||||
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
||||||
$( '#woocommerce-order-items' ).find( '.inside' ).append( response.data.html );
|
$( '#woocommerce-order-items' ).find( '.inside' ).append( response.data.html );
|
||||||
|
|
||||||
|
// Update notes.
|
||||||
|
if ( response.data.notes_html ) {
|
||||||
|
$( 'ul.order_notes' ).empty();
|
||||||
|
$( 'ul.order_notes' ).append( $( response.data.notes_html ).find( 'li' ) );
|
||||||
|
}
|
||||||
|
|
||||||
wc_meta_boxes_order_items.reloaded_items();
|
wc_meta_boxes_order_items.reloaded_items();
|
||||||
wc_meta_boxes_order_items.unblock();
|
wc_meta_boxes_order_items.unblock();
|
||||||
} else {
|
} else {
|
||||||
|
@ -641,7 +648,7 @@ jQuery( function ( $ ) {
|
||||||
items: $( 'table.woocommerce_order_items :input[name], .wc-order-totals-items :input[name]' ).serialize(),
|
items: $( 'table.woocommerce_order_items :input[name], .wc-order-totals-items :input[name]' ).serialize(),
|
||||||
security: woocommerce_admin_meta_boxes.calc_totals_nonce
|
security: woocommerce_admin_meta_boxes.calc_totals_nonce
|
||||||
} );
|
} );
|
||||||
|
|
||||||
$( document.body ).trigger( 'order-totals-recalculate-before', data );
|
$( document.body ).trigger( 'order-totals-recalculate-before', data );
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -680,10 +687,22 @@ jQuery( function ( $ ) {
|
||||||
data: data,
|
data: data,
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
success: function( response ) {
|
success: function( response ) {
|
||||||
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
if ( response.success ) {
|
||||||
$( '#woocommerce-order-items' ).find( '.inside' ).append( response );
|
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
||||||
wc_meta_boxes_order_items.reloaded_items();
|
$( '#woocommerce-order-items' ).find( '.inside' ).append( response.data.html );
|
||||||
wc_meta_boxes_order_items.unblock();
|
|
||||||
|
// Update notes.
|
||||||
|
if ( response.data.notes_html ) {
|
||||||
|
$( 'ul.order_notes' ).empty();
|
||||||
|
$( 'ul.order_notes' ).append( $( response.data.notes_html ).find( 'li' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
wc_meta_boxes_order_items.reloaded_items();
|
||||||
|
wc_meta_boxes_order_items.unblock();
|
||||||
|
} else {
|
||||||
|
wc_meta_boxes_order_items.unblock();
|
||||||
|
window.alert( response.data.error );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -978,6 +997,13 @@ jQuery( function ( $ ) {
|
||||||
if ( response.success ) {
|
if ( response.success ) {
|
||||||
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
||||||
$( '#woocommerce-order-items' ).find( '.inside' ).append( response.data.html );
|
$( '#woocommerce-order-items' ).find( '.inside' ).append( response.data.html );
|
||||||
|
|
||||||
|
// Update notes.
|
||||||
|
if ( response.data.notes_html ) {
|
||||||
|
$( 'ul.order_notes' ).empty();
|
||||||
|
$( 'ul.order_notes' ).append( $( response.data.notes_html ).find( 'li' ) );
|
||||||
|
}
|
||||||
|
|
||||||
wc_meta_boxes_order_items.reloaded_items();
|
wc_meta_boxes_order_items.reloaded_items();
|
||||||
wc_meta_boxes_order_items.unblock();
|
wc_meta_boxes_order_items.unblock();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
/**
|
/**
|
||||||
* Order Notes
|
* Order Notes
|
||||||
*
|
*
|
||||||
* @author WooThemes
|
* @package WooCommerce/Admin/Meta Boxes
|
||||||
* @category Admin
|
|
||||||
* @package WooCommerce/Admin/Meta Boxes
|
|
||||||
* @version 2.1.0
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit; // Exit if accessed directly
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +17,7 @@ class WC_Meta_Box_Order_Notes {
|
||||||
/**
|
/**
|
||||||
* Output the metabox.
|
* Output the metabox.
|
||||||
*
|
*
|
||||||
* @param WP_Post $post
|
* @param WP_Post $post Post object.
|
||||||
*/
|
*/
|
||||||
public static function output( $post ) {
|
public static function output( $post ) {
|
||||||
global $post;
|
global $post;
|
||||||
|
@ -31,52 +28,20 @@ class WC_Meta_Box_Order_Notes {
|
||||||
|
|
||||||
$notes = wc_get_order_notes( $args );
|
$notes = wc_get_order_notes( $args );
|
||||||
|
|
||||||
echo '<ul class="order_notes">';
|
include 'views/html-order-notes.php';
|
||||||
|
|
||||||
if ( $notes ) {
|
|
||||||
|
|
||||||
foreach ( $notes as $note ) {
|
|
||||||
|
|
||||||
$note_classes = array( 'note' );
|
|
||||||
$note_classes[] = $note->customer_note ? 'customer-note' : '';
|
|
||||||
$note_classes[] = 'system' === $note->added_by ? 'system-note' : '';
|
|
||||||
$note_classes = apply_filters( 'woocommerce_order_note_class', array_filter( $note_classes ), $note );
|
|
||||||
?>
|
|
||||||
<li rel="<?php echo absint( $note->id ); ?>" class="<?php echo esc_attr( implode( ' ', $note_classes ) ); ?>">
|
|
||||||
<div class="note_content">
|
|
||||||
<?php echo wpautop( wptexturize( wp_kses_post( make_clickable( $note->content ) ) ) ); ?>
|
|
||||||
</div>
|
|
||||||
<p class="meta">
|
|
||||||
<abbr class="exact-date" title="<?php echo $note->date_created->date( 'y-m-d h:i:s' ); ?>"><?php printf( __( 'added on %1$s at %2$s', 'woocommerce' ), $note->date_created->date_i18n( wc_date_format() ), $note->date_created->date_i18n( wc_time_format() ) ); ?></abbr>
|
|
||||||
<?php
|
|
||||||
if ( 'system' !== $note->added_by ) :
|
|
||||||
/* translators: %s: note author */
|
|
||||||
printf( ' ' . __( 'by %s', 'woocommerce' ), $note->added_by );
|
|
||||||
endif;
|
|
||||||
?>
|
|
||||||
<a href="#" class="delete_note" role="button"><?php _e( 'Delete note', 'woocommerce' ); ?></a>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echo '<li>' . __( 'There are no notes yet.', 'woocommerce' ) . '</li>';
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '</ul>';
|
|
||||||
?>
|
?>
|
||||||
<div class="add_note">
|
<div class="add_note">
|
||||||
<p>
|
<p>
|
||||||
<label for="add_order_note"><?php _e( 'Add note', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'Add a note for your reference, or add a customer note (the user will be notified).', 'woocommerce' ) ); ?></label>
|
<label for="add_order_note"><?php esc_html_e( 'Add note', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'Add a note for your reference, or add a customer note (the user will be notified).', 'woocommerce' ) ); ?></label>
|
||||||
<textarea type="text" name="order_note" id="add_order_note" class="input-text" cols="20" rows="5"></textarea>
|
<textarea type="text" name="order_note" id="add_order_note" class="input-text" cols="20" rows="5"></textarea>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label for="order_note_type" class="screen-reader-text"><?php _e( 'Note type', 'woocommerce' ); ?></label>
|
<label for="order_note_type" class="screen-reader-text"><?php esc_html_e( 'Note type', 'woocommerce' ); ?></label>
|
||||||
<select name="order_note_type" id="order_note_type">
|
<select name="order_note_type" id="order_note_type">
|
||||||
<option value=""><?php _e( 'Private note', 'woocommerce' ); ?></option>
|
<option value=""><?php esc_html_e( 'Private note', 'woocommerce' ); ?></option>
|
||||||
<option value="customer"><?php _e( 'Note to customer', 'woocommerce' ); ?></option>
|
<option value="customer"><?php esc_html_e( 'Note to customer', 'woocommerce' ); ?></option>
|
||||||
</select>
|
</select>
|
||||||
<button type="button" class="add_note button"><?php _e( 'Add', 'woocommerce' ); ?></button>
|
<button type="button" class="add_note button"><?php esc_html_e( 'Add', 'woocommerce' ); ?></button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Order notes HTML for meta box.
|
||||||
|
*
|
||||||
|
* @package WooCommerce/Admin
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined( 'ABSPATH' ) || exit;
|
||||||
|
|
||||||
|
?>
|
||||||
|
<ul class="order_notes">
|
||||||
|
<?php
|
||||||
|
if ( $notes ) {
|
||||||
|
foreach ( $notes as $note ) {
|
||||||
|
$css_class = array( 'note' );
|
||||||
|
$css_class[] = $note->customer_note ? 'customer-note' : '';
|
||||||
|
$css_class[] = 'system' === $note->added_by ? 'system-note' : '';
|
||||||
|
$css_class = apply_filters( 'woocommerce_order_note_class', array_filter( $css_class ), $note );
|
||||||
|
?>
|
||||||
|
<li rel="<?php echo absint( $note->id ); ?>" class="<?php echo esc_attr( implode( ' ', $css_class ) ); ?>">
|
||||||
|
<div class="note_content">
|
||||||
|
<?php echo wpautop( wptexturize( wp_kses_post( $note->content ) ) ); // @codingStandardsIgnoreLine ?>
|
||||||
|
</div>
|
||||||
|
<p class="meta">
|
||||||
|
<abbr class="exact-date" title="<?php echo esc_attr( $note->date_created->date( 'y-m-d h:i:s' ) ); ?>">
|
||||||
|
<?php
|
||||||
|
/* translators: %1$s: note date %2$s: note time */
|
||||||
|
echo esc_html( sprintf( __( '%1$s at %2$s', 'woocommerce' ), $note->date_created->date_i18n( wc_date_format() ), $note->date_created->date_i18n( wc_time_format() ) ) );
|
||||||
|
?>
|
||||||
|
</abbr>
|
||||||
|
<?php
|
||||||
|
if ( 'system' !== $note->added_by ) :
|
||||||
|
/* translators: %s: note author */
|
||||||
|
echo esc_html( sprintf( ' ' . __( 'by %s', 'woocommerce' ), $note->added_by ) );
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
<a href="#" class="delete_note" role="button"><?php esc_html_e( 'Delete note', 'woocommerce' ); ?></a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
?>
|
||||||
|
<li><?php esc_html_e( 'There are no notes yet.', 'woocommerce' ); ?></li>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</ul>
|
|
@ -2,14 +2,12 @@
|
||||||
/**
|
/**
|
||||||
* WooCommerce Admin Functions
|
* WooCommerce Admin Functions
|
||||||
*
|
*
|
||||||
* @author WooThemes
|
|
||||||
* @category Core
|
|
||||||
* @package WooCommerce/Admin/Functions
|
* @package WooCommerce/Admin/Functions
|
||||||
* @version 2.4.0
|
* @version 2.4.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit; // Exit if accessed directly
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,7 +44,9 @@ function wc_get_screen_ids() {
|
||||||
$screen_ids[] = 'edit-' . $type;
|
$screen_ids[] = 'edit-' . $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $attributes = wc_get_attribute_taxonomies() ) {
|
$attributes = wc_get_attribute_taxonomies();
|
||||||
|
|
||||||
|
if ( $attributes ) {
|
||||||
foreach ( $attributes as $attribute ) {
|
foreach ( $attributes as $attribute ) {
|
||||||
$screen_ids[] = 'edit-' . wc_attribute_taxonomy_name( $attribute->attribute_name );
|
$screen_ids[] = 'edit-' . wc_attribute_taxonomy_name( $attribute->attribute_name );
|
||||||
}
|
}
|
||||||
|
@ -58,21 +58,23 @@ function wc_get_screen_ids() {
|
||||||
/**
|
/**
|
||||||
* Create a page and store the ID in an option.
|
* Create a page and store the ID in an option.
|
||||||
*
|
*
|
||||||
* @param mixed $slug Slug for the new page
|
* @param mixed $slug Slug for the new page.
|
||||||
* @param string $option Option name to store the page's ID
|
* @param string $option Option name to store the page's ID.
|
||||||
* @param string $page_title (default: '') Title for the new page
|
* @param string $page_title (default: '') Title for the new page.
|
||||||
* @param string $page_content (default: '') Content for the new page
|
* @param string $page_content (default: '') Content for the new page.
|
||||||
* @param int $post_parent (default: 0) Parent for the new page
|
* @param int $post_parent (default: 0) Parent for the new page.
|
||||||
* @return int page ID
|
* @return int page ID.
|
||||||
*/
|
*/
|
||||||
function wc_create_page( $slug, $option = '', $page_title = '', $page_content = '', $post_parent = 0 ) {
|
function wc_create_page( $slug, $option = '', $page_title = '', $page_content = '', $post_parent = 0 ) {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
$option_value = get_option( $option );
|
$option_value = get_option( $option );
|
||||||
|
|
||||||
if ( $option_value > 0 && ( $page_object = get_post( $option_value ) ) ) {
|
if ( $option_value > 0 ) {
|
||||||
if ( 'page' === $page_object->post_type && ! in_array( $page_object->post_status, array( 'pending', 'trash', 'future', 'auto-draft' ) ) ) {
|
$page_object = get_post( $option_value );
|
||||||
// Valid page is already in place
|
|
||||||
|
if ( $page_object && 'page' === $page_object->post_type && ! in_array( $page_object->post_status, array( 'pending', 'trash', 'future', 'auto-draft' ), true ) ) {
|
||||||
|
// Valid page is already in place.
|
||||||
return $page_object->ID;
|
return $page_object->ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +84,7 @@ function wc_create_page( $slug, $option = '', $page_title = '', $page_content =
|
||||||
$shortcode = str_replace( array( '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ), '', $page_content );
|
$shortcode = str_replace( array( '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ), '', $page_content );
|
||||||
$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_content LIKE %s LIMIT 1;", "%{$shortcode}%" ) );
|
$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_content LIKE %s LIMIT 1;", "%{$shortcode}%" ) );
|
||||||
} else {
|
} else {
|
||||||
// Search for an existing page with the specified page slug
|
// Search for an existing page with the specified page slug.
|
||||||
$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_name = %s LIMIT 1;", $slug ) );
|
$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_name = %s LIMIT 1;", $slug ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,12 +97,12 @@ function wc_create_page( $slug, $option = '', $page_title = '', $page_content =
|
||||||
return $valid_page_found;
|
return $valid_page_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for a matching valid trashed page
|
// Search for a matching valid trashed page.
|
||||||
if ( strlen( $page_content ) > 0 ) {
|
if ( strlen( $page_content ) > 0 ) {
|
||||||
// Search for an existing page with the specified page content (typically a shortcode)
|
// Search for an existing page with the specified page content (typically a shortcode).
|
||||||
$trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_content LIKE %s LIMIT 1;", "%{$page_content}%" ) );
|
$trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_content LIKE %s LIMIT 1;", "%{$page_content}%" ) );
|
||||||
} else {
|
} else {
|
||||||
// Search for an existing page with the specified page slug
|
// Search for an existing page with the specified page slug.
|
||||||
$trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_name = %s LIMIT 1;", $slug ) );
|
$trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_name = %s LIMIT 1;", $slug ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +139,7 @@ function wc_create_page( $slug, $option = '', $page_title = '', $page_content =
|
||||||
*
|
*
|
||||||
* Loops though the woocommerce options array and outputs each field.
|
* Loops though the woocommerce options array and outputs each field.
|
||||||
*
|
*
|
||||||
* @param array $options Opens array to output
|
* @param array $options Opens array to output.
|
||||||
*/
|
*/
|
||||||
function woocommerce_admin_fields( $options ) {
|
function woocommerce_admin_fields( $options ) {
|
||||||
|
|
||||||
|
@ -151,8 +153,8 @@ function woocommerce_admin_fields( $options ) {
|
||||||
/**
|
/**
|
||||||
* Update all settings which are passed.
|
* Update all settings which are passed.
|
||||||
*
|
*
|
||||||
* @param array $options
|
* @param array $options Option fields to save.
|
||||||
* @param array $data
|
* @param array $data Passed data.
|
||||||
*/
|
*/
|
||||||
function woocommerce_update_options( $options, $data = null ) {
|
function woocommerce_update_options( $options, $data = null ) {
|
||||||
|
|
||||||
|
@ -166,8 +168,8 @@ function woocommerce_update_options( $options, $data = null ) {
|
||||||
/**
|
/**
|
||||||
* Get a setting from the settings API.
|
* Get a setting from the settings API.
|
||||||
*
|
*
|
||||||
* @param mixed $option_name
|
* @param mixed $option_name Option name to save.
|
||||||
* @param mixed $default
|
* @param mixed $default Default value to save.
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function woocommerce_settings_get_option( $option_name, $default = '' ) {
|
function woocommerce_settings_get_option( $option_name, $default = '' ) {
|
||||||
|
@ -179,17 +181,61 @@ function woocommerce_settings_get_option( $option_name, $default = '' ) {
|
||||||
return WC_Admin_Settings::get_option( $option_name, $default );
|
return WC_Admin_Settings::get_option( $option_name, $default );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sees if line item stock has already reduced stock, and whether those values need adjusting e.g. after changing item qty.
|
||||||
|
*
|
||||||
|
* @since 3.6.0
|
||||||
|
* @param WC_Order_Item $item Item object.
|
||||||
|
* @param integer $item_quantity Optional quantity to check against. Read from object if not passed.
|
||||||
|
* @return boolean|array|WP_Error Array of changes or error object when stock is updated (@see wc_update_product_stock). False if nothing changes.
|
||||||
|
*/
|
||||||
|
function wc_maybe_adjust_line_item_product_stock( $item, $item_quantity = -1 ) {
|
||||||
|
if ( 'line_item' !== $item->get_type() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$product = $item->get_product();
|
||||||
|
$item_quantity = wc_stock_amount( $item_quantity >= 0 ? $item_quantity : $item->get_quantity() );
|
||||||
|
$already_reduced_stock = wc_stock_amount( $item->get_meta( '_reduced_stock', true ) );
|
||||||
|
|
||||||
|
if ( ! $product || ! $product->managing_stock() || ! $already_reduced_stock || $item_quantity === $already_reduced_stock ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$diff = $item_quantity - $already_reduced_stock;
|
||||||
|
|
||||||
|
if ( $diff < 0 ) {
|
||||||
|
$new_stock = wc_update_product_stock( $product, $diff * -1, 'increase' );
|
||||||
|
} else {
|
||||||
|
$new_stock = wc_update_product_stock( $product, $diff, 'decrease' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_wp_error( $new_stock ) ) {
|
||||||
|
return $new_stock;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->update_meta_data( '_reduced_stock', $item_quantity );
|
||||||
|
$item->save();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'from' => $new_stock + $diff,
|
||||||
|
'to' => $new_stock,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save order items. Uses the CRUD.
|
* Save order items. Uses the CRUD.
|
||||||
*
|
*
|
||||||
* @since 2.2
|
* @since 2.2
|
||||||
* @param int $order_id Order ID
|
* @param int $order_id Order ID.
|
||||||
* @param array $items Order items to save
|
* @param array $items Order items to save.
|
||||||
*/
|
*/
|
||||||
function wc_save_order_items( $order_id, $items ) {
|
function wc_save_order_items( $order_id, $items ) {
|
||||||
// Allow other plugins to check change in order items before they are saved.
|
// Allow other plugins to check change in order items before they are saved.
|
||||||
do_action( 'woocommerce_before_save_order_items', $order_id, $items );
|
do_action( 'woocommerce_before_save_order_items', $order_id, $items );
|
||||||
|
|
||||||
|
$qty_change_order_notes = array();
|
||||||
|
|
||||||
// Line items and fees.
|
// Line items and fees.
|
||||||
if ( isset( $items['order_item_id'] ) ) {
|
if ( isset( $items['order_item_id'] ) ) {
|
||||||
$data_keys = array(
|
$data_keys = array(
|
||||||
|
@ -202,7 +248,9 @@ function wc_save_order_items( $order_id, $items ) {
|
||||||
'line_subtotal' => null,
|
'line_subtotal' => null,
|
||||||
);
|
);
|
||||||
foreach ( $items['order_item_id'] as $item_id ) {
|
foreach ( $items['order_item_id'] as $item_id ) {
|
||||||
if ( ! $item = WC_Order_Factory::get_order_item( absint( $item_id ) ) ) {
|
$item = WC_Order_Factory::get_order_item( absint( $item_id ) );
|
||||||
|
|
||||||
|
if ( ! $item ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +261,10 @@ function wc_save_order_items( $order_id, $items ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( '0' === $item_data['order_item_qty'] ) {
|
if ( '0' === $item_data['order_item_qty'] ) {
|
||||||
|
$changed_stock = wc_maybe_adjust_line_item_product_stock( $item, 0 );
|
||||||
|
if ( $changed_stock && ! is_wp_error( $changed_stock ) ) {
|
||||||
|
$qty_change_order_notes[] = $item->get_name() . ' – ' . $changed_stock['from'] . '→' . $changed_stock['to'];
|
||||||
|
}
|
||||||
$item->delete();
|
$item->delete();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -256,10 +308,15 @@ function wc_save_order_items( $order_id, $items ) {
|
||||||
do_action( 'woocommerce_before_save_order_item', $item );
|
do_action( 'woocommerce_before_save_order_item', $item );
|
||||||
|
|
||||||
$item->save();
|
$item->save();
|
||||||
|
|
||||||
|
$changed_stock = wc_maybe_adjust_line_item_product_stock( $item );
|
||||||
|
if ( $changed_stock && ! is_wp_error( $changed_stock ) ) {
|
||||||
|
$qty_change_order_notes[] = $item->get_name() . ' (' . $changed_stock['from'] . '→' . $changed_stock['to'] . ')';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shipping Rows
|
// Shipping Rows.
|
||||||
if ( isset( $items['shipping_method_id'] ) ) {
|
if ( isset( $items['shipping_method_id'] ) ) {
|
||||||
$data_keys = array(
|
$data_keys = array(
|
||||||
'shipping_method' => null,
|
'shipping_method' => null,
|
||||||
|
@ -269,7 +326,9 @@ function wc_save_order_items( $order_id, $items ) {
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ( $items['shipping_method_id'] as $item_id ) {
|
foreach ( $items['shipping_method_id'] as $item_id ) {
|
||||||
if ( ! $item = WC_Order_Factory::get_order_item( absint( $item_id ) ) ) {
|
$item = WC_Order_Factory::get_order_item( absint( $item_id ) );
|
||||||
|
|
||||||
|
if ( ! $item ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,10 +370,16 @@ function wc_save_order_items( $order_id, $items ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$order = wc_get_order( $order_id );
|
$order = wc_get_order( $order_id );
|
||||||
|
|
||||||
|
if ( ! empty( $qty_change_order_notes ) ) {
|
||||||
|
/* translators: %s item name. */
|
||||||
|
$order->add_order_note( sprintf( __( 'Adjusted stock: %s', 'woocommerce' ), implode( ', ', $qty_change_order_notes ) ), false, true );
|
||||||
|
}
|
||||||
|
|
||||||
$order->update_taxes();
|
$order->update_taxes();
|
||||||
$order->calculate_totals( false );
|
$order->calculate_totals( false );
|
||||||
|
|
||||||
// Inform other plugins that the items have been saved
|
// Inform other plugins that the items have been saved.
|
||||||
do_action( 'woocommerce_saved_order_items', $order_id, $items );
|
do_action( 'woocommerce_saved_order_items', $order_id, $items );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -842,7 +842,7 @@ class WC_AJAX {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add order item via ajax.
|
* Add order item via ajax. Used on the edit order screen in WP Admim.
|
||||||
*/
|
*/
|
||||||
public static function add_order_item() {
|
public static function add_order_item() {
|
||||||
check_ajax_referer( 'order-item', 'security' );
|
check_ajax_referer( 'order-item', 'security' );
|
||||||
|
@ -858,26 +858,25 @@ class WC_AJAX {
|
||||||
throw new Exception( __( 'Invalid order', 'woocommerce' ) );
|
throw new Exception( __( 'Invalid order', 'woocommerce' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$order_id = absint( wp_unslash( $_POST['order_id'] ) ); // WPCS: input var ok.
|
$order_id = absint( wp_unslash( $_POST['order_id'] ) ); // WPCS: input var ok.
|
||||||
$order = wc_get_order( $order_id );
|
$order = wc_get_order( $order_id );
|
||||||
|
|
||||||
if ( ! $order ) {
|
if ( ! $order ) {
|
||||||
throw new Exception( __( 'Invalid order', 'woocommerce' ) );
|
throw new Exception( __( 'Invalid order', 'woocommerce' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we passed through items it means we need to save first before adding a new one.
|
// If we passed through items it means we need to save first before adding a new one.
|
||||||
$items = ( ! empty( $_POST['items'] ) ) ? $_POST['items'] : '';
|
if ( ! empty( $_POST['items'] ) ) {
|
||||||
|
|
||||||
if ( ! empty( $items ) ) {
|
|
||||||
$save_items = array();
|
$save_items = array();
|
||||||
parse_str( $items, $save_items );
|
parse_str( wp_unslash( $_POST['items'] ), $save_items );
|
||||||
// Save order items.
|
|
||||||
wc_save_order_items( $order->get_id(), $save_items );
|
wc_save_order_items( $order->get_id(), $save_items );
|
||||||
}
|
}
|
||||||
|
|
||||||
$items_to_add = array_filter( wp_unslash( (array) $_POST['data'] ) );
|
$items_to_add = array_filter( wp_unslash( (array) $_POST['data'] ) );
|
||||||
|
|
||||||
// Add items to order.
|
// Add items to order.
|
||||||
|
$order_notes = array();
|
||||||
|
|
||||||
foreach ( $items_to_add as $item ) {
|
foreach ( $items_to_add as $item ) {
|
||||||
if ( ! isset( $item['id'], $item['qty'] ) || empty( $item['id'] ) ) {
|
if ( ! isset( $item['id'], $item['qty'] ) || empty( $item['id'] ) ) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -893,17 +892,41 @@ class WC_AJAX {
|
||||||
$item_id = $order->add_product( $product, $qty );
|
$item_id = $order->add_product( $product, $qty );
|
||||||
$item = apply_filters( 'woocommerce_ajax_order_item', $order->get_item( $item_id ), $item_id );
|
$item = apply_filters( 'woocommerce_ajax_order_item', $order->get_item( $item_id ), $item_id );
|
||||||
$added_items[ $item_id ] = $item;
|
$added_items[ $item_id ] = $item;
|
||||||
|
$order_notes[ $item_id ] = $product->get_formatted_name();
|
||||||
|
|
||||||
|
if ( $product->managing_stock() ) {
|
||||||
|
$new_stock = wc_update_product_stock( $product, $qty, 'decrease' );
|
||||||
|
$order_notes[ $item_id ] = $product->get_formatted_name() . ' – ' . ( $new_stock + $qty ) . '→' . $new_stock;
|
||||||
|
$item->add_meta_data( '_reduced_stock', $qty, true );
|
||||||
|
$item->save();
|
||||||
|
}
|
||||||
|
|
||||||
do_action( 'woocommerce_ajax_add_order_item_meta', $item_id, $item, $order );
|
do_action( 'woocommerce_ajax_add_order_item_meta', $item_id, $item, $order );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* translators: %s item name. */
|
||||||
|
$order->add_order_note( sprintf( __( 'Added line items: %s', 'woocommerce' ), implode( ', ', $order_notes ) ), false, true );
|
||||||
|
|
||||||
do_action( 'woocommerce_ajax_order_items_added', $added_items, $order );
|
do_action( 'woocommerce_ajax_order_items_added', $added_items, $order );
|
||||||
|
|
||||||
$data = get_post_meta( $order_id );
|
$data = get_post_meta( $order_id );
|
||||||
|
|
||||||
|
// Get HTML to return.
|
||||||
ob_start();
|
ob_start();
|
||||||
include 'admin/meta-boxes/views/html-order-items.php';
|
include 'admin/meta-boxes/views/html-order-items.php';
|
||||||
$response['html'] = ob_get_clean();
|
$items_html = ob_get_clean();
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$notes = wc_get_order_notes( array( 'order_id' => $order_id ) );
|
||||||
|
include 'admin/meta-boxes/views/html-order-notes.php';
|
||||||
|
$notes_html = ob_get_clean();
|
||||||
|
|
||||||
|
wp_send_json_success(
|
||||||
|
array(
|
||||||
|
'html' => $items_html,
|
||||||
|
'notes_html' => $notes_html,
|
||||||
|
)
|
||||||
|
);
|
||||||
} catch ( Exception $e ) {
|
} catch ( Exception $e ) {
|
||||||
wp_send_json_error( array( 'error' => $e->getMessage() ) );
|
wp_send_json_error( array( 'error' => $e->getMessage() ) );
|
||||||
}
|
}
|
||||||
|
@ -1114,14 +1137,23 @@ class WC_AJAX {
|
||||||
$response = array();
|
$response = array();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$order_id = absint( $_POST['order_id'] );
|
$order_id = absint( $_POST['order_id'] );
|
||||||
$order_item_ids = $_POST['order_item_ids'];
|
$order = wc_get_order( $order_id );
|
||||||
$items = ( ! empty( $_POST['items'] ) ) ? $_POST['items'] : '';
|
|
||||||
|
if ( ! $order ) {
|
||||||
|
throw new Exception( __( 'Invalid order', 'woocommerce' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! isset( $_POST['order_item_ids'] ) ) {
|
||||||
|
throw new Exception( __( 'Invalid items', 'woocommerce' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$order_item_ids = wp_unslash( $_POST['order_item_ids'] );
|
||||||
$calculate_tax_args = array(
|
$calculate_tax_args = array(
|
||||||
'country' => strtoupper( wc_clean( $_POST['country'] ) ),
|
'country' => strtoupper( wc_clean( wp_unslash( $_POST['country'] ) ) ),
|
||||||
'state' => strtoupper( wc_clean( $_POST['state'] ) ),
|
'state' => strtoupper( wc_clean( wp_unslash( $_POST['state'] ) ) ),
|
||||||
'postcode' => strtoupper( wc_clean( $_POST['postcode'] ) ),
|
'postcode' => strtoupper( wc_clean( wp_unslash( $_POST['postcode'] ) ) ),
|
||||||
'city' => strtoupper( wc_clean( $_POST['city'] ) ),
|
'city' => strtoupper( wc_clean( wp_unslash( $_POST['city'] ) ) ),
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( ! is_array( $order_item_ids ) && is_numeric( $order_item_ids ) ) {
|
if ( ! is_array( $order_item_ids ) && is_numeric( $order_item_ids ) ) {
|
||||||
|
@ -1129,16 +1161,33 @@ class WC_AJAX {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we passed through items it means we need to save first before deleting.
|
// If we passed through items it means we need to save first before deleting.
|
||||||
if ( ! empty( $items ) ) {
|
if ( ! empty( $_POST['items'] ) ) {
|
||||||
$save_items = array();
|
$save_items = array();
|
||||||
parse_str( $items, $save_items );
|
parse_str( wp_unslash( $_POST['items'] ), $save_items );
|
||||||
// Save order items
|
wc_save_order_items( $order->get_id(), $save_items );
|
||||||
wc_save_order_items( $order_id, $save_items );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sizeof( $order_item_ids ) > 0 ) {
|
if ( ! empty( $order_item_ids ) ) {
|
||||||
foreach ( $order_item_ids as $id ) {
|
$order_notes = array();
|
||||||
wc_delete_order_item( absint( $id ) );
|
|
||||||
|
foreach ( $order_item_ids as $item_id ) {
|
||||||
|
$item_id = absint( $item_id );
|
||||||
|
$item = $order->get_item( $item_id );
|
||||||
|
|
||||||
|
// Before deleting the item, adjust any stock values already reduced.
|
||||||
|
if ( $item->is_type( 'line_item' ) ) {
|
||||||
|
$changed_stock = wc_maybe_adjust_line_item_product_stock( $item, 0 );
|
||||||
|
|
||||||
|
if ( $changed_stock && ! is_wp_error( $changed_stock ) ) {
|
||||||
|
/* translators: %1$s: item name %2$s: stock change */
|
||||||
|
$order->add_order_note( sprintf( __( 'Deleted %1$s and adjusted stock (%2$s)', 'woocommerce' ), $item->get_name(), $changed_stock['from'] . '→' . $changed_stock['to'] ), false, true );
|
||||||
|
} else {
|
||||||
|
/* translators: %s item name. */
|
||||||
|
$order->add_order_note( sprintf( __( 'Deleted %s', 'woocommerce' ), $item->get_name() ), false, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wc_delete_order_item( $item_id );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1146,9 +1195,22 @@ class WC_AJAX {
|
||||||
$order->calculate_taxes( $calculate_tax_args );
|
$order->calculate_taxes( $calculate_tax_args );
|
||||||
$order->calculate_totals( false );
|
$order->calculate_totals( false );
|
||||||
|
|
||||||
|
// Get HTML to return.
|
||||||
ob_start();
|
ob_start();
|
||||||
include 'admin/meta-boxes/views/html-order-items.php';
|
include 'admin/meta-boxes/views/html-order-items.php';
|
||||||
$response['html'] = ob_get_clean();
|
$items_html = ob_get_clean();
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$notes = wc_get_order_notes( array( 'order_id' => $order_id ) );
|
||||||
|
include 'admin/meta-boxes/views/html-order-notes.php';
|
||||||
|
$notes_html = ob_get_clean();
|
||||||
|
|
||||||
|
wp_send_json_success(
|
||||||
|
array(
|
||||||
|
'html' => $items_html,
|
||||||
|
'notes_html' => $notes_html,
|
||||||
|
)
|
||||||
|
);
|
||||||
} catch ( Exception $e ) {
|
} catch ( Exception $e ) {
|
||||||
wp_send_json_error( array( 'error' => $e->getMessage() ) );
|
wp_send_json_error( array( 'error' => $e->getMessage() ) );
|
||||||
}
|
}
|
||||||
|
@ -1244,7 +1306,23 @@ class WC_AJAX {
|
||||||
|
|
||||||
// Return HTML items
|
// Return HTML items
|
||||||
$order = wc_get_order( $order_id );
|
$order = wc_get_order( $order_id );
|
||||||
|
|
||||||
|
// Get HTML to return.
|
||||||
|
ob_start();
|
||||||
include 'admin/meta-boxes/views/html-order-items.php';
|
include 'admin/meta-boxes/views/html-order-items.php';
|
||||||
|
$items_html = ob_get_clean();
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$notes = wc_get_order_notes( array( 'order_id' => $order_id ) );
|
||||||
|
include 'admin/meta-boxes/views/html-order-notes.php';
|
||||||
|
$notes_html = ob_get_clean();
|
||||||
|
|
||||||
|
wp_send_json_success(
|
||||||
|
array(
|
||||||
|
'html' => $items_html,
|
||||||
|
'notes_html' => $notes_html,
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
wp_die();
|
wp_die();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue