feat: category filter, item reference SKU lookup, brand sync, and on-demand BC write-back
- Filter product sync to an allow-list of BC item category codes - Look up items by ReferenciasArticulo item reference before falling back to GTIN/item number - Sync BC item category to product_brand and parent category to product_cat via a new ItemCategoryHierarchy endpoint - Add on-demand push of product name/photo back to BC (product edit meta box + bulk action), including binary PATCH support for item pictures Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -80,6 +80,12 @@ class WBC_Admin {
|
||||
register_setting( 'wbc_sync', 'wbc_sale_price_list', array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
) );
|
||||
register_setting( 'wbc_sync', 'wbc_category_filter', array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
) );
|
||||
register_setting( 'wbc_sync', 'wbc_enable_brand_sync', array(
|
||||
'sanitize_callback' => array( $this, 'sanitize_checkbox' ),
|
||||
) );
|
||||
|
||||
// Order settings (own group)
|
||||
register_setting( 'wbc_orders', 'wbc_enable_order_sync', array(
|
||||
@@ -356,4 +362,185 @@ class WBC_Admin {
|
||||
'total' => WBC_Logger::get_log_count( $args ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the "Business Central" meta box on the product edit screen
|
||||
*/
|
||||
public function add_product_meta_box() {
|
||||
add_meta_box(
|
||||
'wbc_product_sync',
|
||||
__( 'Business Central', 'woo-business-central' ),
|
||||
array( $this, 'render_product_meta_box' ),
|
||||
'product',
|
||||
'side',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the product meta box with an on-demand push-to-BC button
|
||||
*
|
||||
* @param WP_Post $post Current product post.
|
||||
*/
|
||||
public function render_product_meta_box( $post ) {
|
||||
$product = wc_get_product( $post->ID );
|
||||
$item_number = $product ? $product->get_meta( '_wbc_bc_item_number' ) : '';
|
||||
$last_sync = $product ? $product->get_meta( '_wbc_last_sync' ) : '';
|
||||
?>
|
||||
<p>
|
||||
<?php if ( $item_number ) : ?>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Business Central item number */
|
||||
esc_html__( 'BC item: %s', 'woo-business-central' ),
|
||||
esc_html( $item_number )
|
||||
);
|
||||
?>
|
||||
<br />
|
||||
<?php else : ?>
|
||||
<?php esc_html_e( 'Not yet linked to a BC item.', 'woo-business-central' ); ?>
|
||||
<br />
|
||||
<?php endif; ?>
|
||||
<?php if ( $last_sync ) : ?>
|
||||
<small>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: last sync datetime */
|
||||
esc_html__( 'Last synced: %s', 'woo-business-central' ),
|
||||
esc_html( $last_sync )
|
||||
);
|
||||
?>
|
||||
</small>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<button type="button" class="button button-secondary" id="wbc-push-to-bc" data-product-id="<?php echo esc_attr( $post->ID ); ?>">
|
||||
<?php esc_html_e( 'Push name/photo to Business Central', 'woo-business-central' ); ?>
|
||||
</button>
|
||||
<span id="wbc-push-status" class="wbc-status"></span>
|
||||
<script>
|
||||
( function( $ ) {
|
||||
$( '#wbc-push-to-bc' ).on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
var $btn = $( this );
|
||||
var $status = $( '#wbc-push-status' );
|
||||
$btn.prop( 'disabled', true );
|
||||
$status.removeClass( 'success error' ).addClass( 'loading' ).text( <?php echo wp_json_encode( __( 'Pushing...', 'woo-business-central' ) ); ?> );
|
||||
$.post( ajaxurl, {
|
||||
action: 'wbc_push_single_to_bc',
|
||||
product_id: $btn.data( 'product-id' ),
|
||||
nonce: <?php echo wp_json_encode( wp_create_nonce( 'wbc_admin_nonce' ) ); ?>
|
||||
} ).done( function( response ) {
|
||||
$btn.prop( 'disabled', false );
|
||||
$status.removeClass( 'loading' );
|
||||
if ( response.success ) {
|
||||
$status.addClass( 'success' ).text( response.data.message );
|
||||
} else {
|
||||
$status.addClass( 'error' ).text( ( response.data && response.data.message ) || 'Failed' );
|
||||
}
|
||||
} ).fail( function() {
|
||||
$btn.prop( 'disabled', false );
|
||||
$status.removeClass( 'loading' ).addClass( 'error' ).text( 'Request failed' );
|
||||
} );
|
||||
} );
|
||||
} )( jQuery );
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Push a single product's name/photo to Business Central
|
||||
*/
|
||||
public function ajax_push_single_to_bc() {
|
||||
check_ajax_referer( 'wbc_admin_nonce', 'nonce' );
|
||||
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'woo-business-central' ) ) );
|
||||
}
|
||||
|
||||
$product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
|
||||
|
||||
if ( ! $product_id ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Invalid product.', 'woo-business-central' ) ) );
|
||||
}
|
||||
|
||||
$sync = new WBC_Product_Sync();
|
||||
$result = $sync->push_product_to_bc( $product_id );
|
||||
|
||||
if ( ! empty( $result['success'] ) ) {
|
||||
wp_send_json_success( $result );
|
||||
} else {
|
||||
wp_send_json_error( $result );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "Push to Business Central" bulk action on the Products list
|
||||
*
|
||||
* @param array $actions Existing bulk actions.
|
||||
* @return array Modified bulk actions.
|
||||
*/
|
||||
public function add_bulk_action( $actions ) {
|
||||
$actions['wbc_push_to_bc'] = __( 'Push to Business Central', 'woo-business-central' );
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the "Push to Business Central" bulk action
|
||||
*
|
||||
* @param string $redirect_to Redirect URL.
|
||||
* @param string $action Bulk action name.
|
||||
* @param array $post_ids Selected product IDs.
|
||||
* @return string Modified redirect URL.
|
||||
*/
|
||||
public function handle_bulk_action( $redirect_to, $action, $post_ids ) {
|
||||
if ( $action !== 'wbc_push_to_bc' ) {
|
||||
return $redirect_to;
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
return $redirect_to;
|
||||
}
|
||||
|
||||
$sync = new WBC_Product_Sync();
|
||||
$success = 0;
|
||||
$failed = 0;
|
||||
|
||||
foreach ( $post_ids as $post_id ) {
|
||||
$result = $sync->push_product_to_bc( $post_id );
|
||||
|
||||
if ( ! empty( $result['success'] ) ) {
|
||||
$success++;
|
||||
} else {
|
||||
$failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return add_query_arg( array(
|
||||
'wbc_pushed' => $success,
|
||||
'wbc_push_failed' => $failed,
|
||||
), $redirect_to );
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an admin notice with the result of the bulk push action
|
||||
*/
|
||||
public function bulk_action_admin_notice() {
|
||||
if ( empty( $_REQUEST['wbc_pushed'] ) && empty( $_REQUEST['wbc_push_failed'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$success = isset( $_REQUEST['wbc_pushed'] ) ? absint( $_REQUEST['wbc_pushed'] ) : 0;
|
||||
$failed = isset( $_REQUEST['wbc_push_failed'] ) ? absint( $_REQUEST['wbc_push_failed'] ) : 0;
|
||||
|
||||
printf(
|
||||
'<div class="notice notice-%s is-dismissible"><p>%s</p></div>',
|
||||
esc_attr( $failed > 0 ? 'warning' : 'success' ),
|
||||
esc_html( sprintf(
|
||||
/* translators: 1: success count, 2: failed count */
|
||||
__( 'Pushed %1$d product(s) to Business Central. %2$d failed.', 'woo-business-central' ),
|
||||
$success,
|
||||
$failed
|
||||
) )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user