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 ) {
|
||||
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
||||
$( '#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.unblock();
|
||||
} else {
|
||||
|
@ -641,7 +648,7 @@ jQuery( function ( $ ) {
|
|||
items: $( 'table.woocommerce_order_items :input[name], .wc-order-totals-items :input[name]' ).serialize(),
|
||||
security: woocommerce_admin_meta_boxes.calc_totals_nonce
|
||||
} );
|
||||
|
||||
|
||||
$( document.body ).trigger( 'order-totals-recalculate-before', data );
|
||||
|
||||
$.ajax({
|
||||
|
@ -680,10 +687,22 @@ jQuery( function ( $ ) {
|
|||
data: data,
|
||||
type: 'POST',
|
||||
success: function( response ) {
|
||||
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
||||
$( '#woocommerce-order-items' ).find( '.inside' ).append( response );
|
||||
wc_meta_boxes_order_items.reloaded_items();
|
||||
wc_meta_boxes_order_items.unblock();
|
||||
if ( response.success ) {
|
||||
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
||||
$( '#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.unblock();
|
||||
} else {
|
||||
wc_meta_boxes_order_items.unblock();
|
||||
window.alert( response.data.error );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -978,6 +997,13 @@ jQuery( function ( $ ) {
|
|||
if ( response.success ) {
|
||||
$( '#woocommerce-order-items' ).find( '.inside' ).empty();
|
||||
$( '#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.unblock();
|
||||
} else {
|
||||
|
|
|
@ -2,14 +2,11 @@
|
|||
/**
|
||||
* Order Notes
|
||||
*
|
||||
* @author WooThemes
|
||||
* @category Admin
|
||||
* @package WooCommerce/Admin/Meta Boxes
|
||||
* @version 2.1.0
|
||||
* @package WooCommerce/Admin/Meta Boxes
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +17,7 @@ class WC_Meta_Box_Order_Notes {
|
|||
/**
|
||||
* Output the metabox.
|
||||
*
|
||||
* @param WP_Post $post
|
||||
* @param WP_Post $post Post object.
|
||||
*/
|
||||
public static function output( $post ) {
|
||||
global $post;
|
||||
|
@ -31,52 +28,20 @@ class WC_Meta_Box_Order_Notes {
|
|||
|
||||
$notes = wc_get_order_notes( $args );
|
||||
|
||||
echo '<ul class="order_notes">';
|
||||
|
||||
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>';
|
||||
include 'views/html-order-notes.php';
|
||||
?>
|
||||
<div class="add_note">
|
||||
<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>
|
||||
</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">
|
||||
<option value=""><?php _e( 'Private note', 'woocommerce' ); ?></option>
|
||||
<option value="customer"><?php _e( 'Note to customer', 'woocommerce' ); ?></option>
|
||||
<option value=""><?php esc_html_e( 'Private note', 'woocommerce' ); ?></option>
|
||||
<option value="customer"><?php esc_html_e( 'Note to customer', 'woocommerce' ); ?></option>
|
||||
</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>
|
||||
</div>
|
||||
<?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
|
||||
*
|
||||
* @author WooThemes
|
||||
* @category Core
|
||||
* @package WooCommerce/Admin/Functions
|
||||
* @version 2.4.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +44,9 @@ function wc_get_screen_ids() {
|
|||
$screen_ids[] = 'edit-' . $type;
|
||||
}
|
||||
|
||||
if ( $attributes = wc_get_attribute_taxonomies() ) {
|
||||
$attributes = wc_get_attribute_taxonomies();
|
||||
|
||||
if ( $attributes ) {
|
||||
foreach ( $attributes as $attribute ) {
|
||||
$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.
|
||||
*
|
||||
* @param mixed $slug Slug for the new page
|
||||
* @param string $option Option name to store the page's ID
|
||||
* @param string $page_title (default: '') Title 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
|
||||
* @return int page ID
|
||||
* @param mixed $slug Slug for the new page.
|
||||
* @param string $option Option name to store the page's ID.
|
||||
* @param string $page_title (default: '') Title 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.
|
||||
* @return int page ID.
|
||||
*/
|
||||
function wc_create_page( $slug, $option = '', $page_title = '', $page_content = '', $post_parent = 0 ) {
|
||||
global $wpdb;
|
||||
|
||||
$option_value = get_option( $option );
|
||||
|
||||
if ( $option_value > 0 && ( $page_object = get_post( $option_value ) ) ) {
|
||||
if ( 'page' === $page_object->post_type && ! in_array( $page_object->post_status, array( 'pending', 'trash', 'future', 'auto-draft' ) ) ) {
|
||||
// Valid page is already in place
|
||||
if ( $option_value > 0 ) {
|
||||
$page_object = get_post( $option_value );
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +84,7 @@ function wc_create_page( $slug, $option = '', $page_title = '', $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}%" ) );
|
||||
} 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 ) );
|
||||
}
|
||||
|
||||
|
@ -95,12 +97,12 @@ function wc_create_page( $slug, $option = '', $page_title = '', $page_content =
|
|||
return $valid_page_found;
|
||||
}
|
||||
|
||||
// Search for a matching valid trashed page
|
||||
// Search for a matching valid trashed page.
|
||||
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}%" ) );
|
||||
} 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 ) );
|
||||
}
|
||||
|
||||
|
@ -137,7 +139,7 @@ function wc_create_page( $slug, $option = '', $page_title = '', $page_content =
|
|||
*
|
||||
* 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 ) {
|
||||
|
||||
|
@ -151,8 +153,8 @@ function woocommerce_admin_fields( $options ) {
|
|||
/**
|
||||
* Update all settings which are passed.
|
||||
*
|
||||
* @param array $options
|
||||
* @param array $data
|
||||
* @param array $options Option fields to save.
|
||||
* @param array $data Passed data.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param mixed $option_name
|
||||
* @param mixed $default
|
||||
* @param mixed $option_name Option name to save.
|
||||
* @param mixed $default Default value to save.
|
||||
* @return string
|
||||
*/
|
||||
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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @since 2.2
|
||||
* @param int $order_id Order ID
|
||||
* @param array $items Order items to save
|
||||
* @param int $order_id Order ID.
|
||||
* @param array $items Order items to save.
|
||||
*/
|
||||
function wc_save_order_items( $order_id, $items ) {
|
||||
// Allow other plugins to check change in order items before they are saved.
|
||||
do_action( 'woocommerce_before_save_order_items', $order_id, $items );
|
||||
|
||||
$qty_change_order_notes = array();
|
||||
|
||||
// Line items and fees.
|
||||
if ( isset( $items['order_item_id'] ) ) {
|
||||
$data_keys = array(
|
||||
|
@ -202,7 +248,9 @@ function wc_save_order_items( $order_id, $items ) {
|
|||
'line_subtotal' => null,
|
||||
);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -213,6 +261,10 @@ function wc_save_order_items( $order_id, $items ) {
|
|||
}
|
||||
|
||||
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();
|
||||
continue;
|
||||
}
|
||||
|
@ -256,10 +308,15 @@ function wc_save_order_items( $order_id, $items ) {
|
|||
do_action( 'woocommerce_before_save_order_item', $item );
|
||||
|
||||
$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'] ) ) {
|
||||
$data_keys = array(
|
||||
'shipping_method' => null,
|
||||
|
@ -269,7 +326,9 @@ function wc_save_order_items( $order_id, $items ) {
|
|||
);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -311,10 +370,16 @@ function wc_save_order_items( $order_id, $items ) {
|
|||
}
|
||||
|
||||
$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->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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
check_ajax_referer( 'order-item', 'security' );
|
||||
|
@ -858,26 +858,25 @@ class WC_AJAX {
|
|||
throw new Exception( __( 'Invalid order', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
$order_id = absint( wp_unslash( $_POST['order_id'] ) ); // WPCS: input var ok.
|
||||
$order = wc_get_order( $order_id );
|
||||
$order_id = absint( wp_unslash( $_POST['order_id'] ) ); // WPCS: input var ok.
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( ! $order ) {
|
||||
throw new Exception( __( 'Invalid order', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
// 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( $items ) ) {
|
||||
if ( ! empty( $_POST['items'] ) ) {
|
||||
$save_items = array();
|
||||
parse_str( $items, $save_items );
|
||||
// Save order items.
|
||||
parse_str( wp_unslash( $_POST['items'] ), $save_items );
|
||||
wc_save_order_items( $order->get_id(), $save_items );
|
||||
}
|
||||
|
||||
$items_to_add = array_filter( wp_unslash( (array) $_POST['data'] ) );
|
||||
|
||||
// Add items to order.
|
||||
$order_notes = array();
|
||||
|
||||
foreach ( $items_to_add as $item ) {
|
||||
if ( ! isset( $item['id'], $item['qty'] ) || empty( $item['id'] ) ) {
|
||||
continue;
|
||||
|
@ -893,17 +892,41 @@ class WC_AJAX {
|
|||
$item_id = $order->add_product( $product, $qty );
|
||||
$item = apply_filters( 'woocommerce_ajax_order_item', $order->get_item( $item_id ), $item_id );
|
||||
$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 );
|
||||
}
|
||||
|
||||
/* 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 );
|
||||
|
||||
$data = get_post_meta( $order_id );
|
||||
|
||||
// Get HTML to return.
|
||||
ob_start();
|
||||
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 ) {
|
||||
wp_send_json_error( array( 'error' => $e->getMessage() ) );
|
||||
}
|
||||
|
@ -1114,14 +1137,23 @@ class WC_AJAX {
|
|||
$response = array();
|
||||
|
||||
try {
|
||||
$order_id = absint( $_POST['order_id'] );
|
||||
$order_item_ids = $_POST['order_item_ids'];
|
||||
$items = ( ! empty( $_POST['items'] ) ) ? $_POST['items'] : '';
|
||||
$order_id = absint( $_POST['order_id'] );
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
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(
|
||||
'country' => strtoupper( wc_clean( $_POST['country'] ) ),
|
||||
'state' => strtoupper( wc_clean( $_POST['state'] ) ),
|
||||
'postcode' => strtoupper( wc_clean( $_POST['postcode'] ) ),
|
||||
'city' => strtoupper( wc_clean( $_POST['city'] ) ),
|
||||
'country' => strtoupper( wc_clean( wp_unslash( $_POST['country'] ) ) ),
|
||||
'state' => strtoupper( wc_clean( wp_unslash( $_POST['state'] ) ) ),
|
||||
'postcode' => strtoupper( wc_clean( wp_unslash( $_POST['postcode'] ) ) ),
|
||||
'city' => strtoupper( wc_clean( wp_unslash( $_POST['city'] ) ) ),
|
||||
);
|
||||
|
||||
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 ( ! empty( $items ) ) {
|
||||
if ( ! empty( $_POST['items'] ) ) {
|
||||
$save_items = array();
|
||||
parse_str( $items, $save_items );
|
||||
// Save order items
|
||||
wc_save_order_items( $order_id, $save_items );
|
||||
parse_str( wp_unslash( $_POST['items'] ), $save_items );
|
||||
wc_save_order_items( $order->get_id(), $save_items );
|
||||
}
|
||||
|
||||
if ( sizeof( $order_item_ids ) > 0 ) {
|
||||
foreach ( $order_item_ids as $id ) {
|
||||
wc_delete_order_item( absint( $id ) );
|
||||
if ( ! empty( $order_item_ids ) ) {
|
||||
$order_notes = array();
|
||||
|
||||
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_totals( false );
|
||||
|
||||
// Get HTML to return.
|
||||
ob_start();
|
||||
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 ) {
|
||||
wp_send_json_error( array( 'error' => $e->getMessage() ) );
|
||||
}
|
||||
|
@ -1244,7 +1306,23 @@ class WC_AJAX {
|
|||
|
||||
// Return HTML items
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
// Get HTML to return.
|
||||
ob_start();
|
||||
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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue