MarkitMall:
';
foreach ( $flags as $f ) {
echo '- ' . esc_html( $f ) . '
';
}
echo '
';
}
/**
* Apply a catalog product (from a webhook) to the local product: stock per
* variant, and prices raised to the minimum if MarkitMall raised it. The
* reseller's own title, description and higher prices are left alone.
*/
public static function apply_remote_product( WC_Product $product, array $remote ) {
$by_variant = array();
foreach ( (array) $remote['variants'] as $v ) {
$by_variant[ $v['id'] ] = $v;
}
$targets = $product->is_type( 'variable' ) ? array_map( 'wc_get_product', $product->get_children() ) : array( $product );
foreach ( $targets as $target ) {
if ( ! $target ) {
continue;
}
$vid = $target->get_meta( MARKITMALL_DS_META_VARIANT );
if ( ! $vid ) {
continue;
}
if ( ! isset( $by_variant[ $vid ] ) ) {
// The option was removed upstream.
$target->set_stock_quantity( 0 );
$target->save();
continue;
}
$v = $by_variant[ $vid ];
$target->set_manage_stock( true );
$target->set_stock_quantity( max( 0, (int) $v['stock'] ) );
self::raise_to_floor( $target, isset( $v['minResalePrice'] ) ? (int) $v['minResalePrice'] : 0 );
MarkitMall_DS_Catalog::set_cost( $target, isset( $v['wholesalePrice'] ) ? $v['wholesalePrice'] : null );
$target->save();
}
// MarkitMall started or stopped delivering it free.
if ( isset( $remote['shipping'] ) ) {
$free = MarkitMall_DS_Delivery::is_free( $remote ) ? 'yes' : 'no';
if ( $product->get_meta( MarkitMall_DS_Delivery::META_FREE ) !== $free ) {
$product->update_meta_data( MarkitMall_DS_Delivery::META_FREE, $free );
$product->save();
}
}
if ( $product->is_type( 'variable' ) ) {
WC_Product_Variable::sync( $product->get_id() );
}
}
/** Raise a price that fell below MarkitMall's minimum (never lower one). */
private static function raise_to_floor( WC_Product $target, $floor ) {
if ( $floor > 0 && (float) $target->get_regular_price() < $floor ) {
$target->set_regular_price( (string) $floor );
self::flag( sprintf( 'The minimum price of ā%sā rose to Rs %s; your price was raised to match.', $target->get_name(), number_format_i18n( $floor ) ) );
return true;
}
return false;
}
/** Every product and variation carrying a MarkitMall variant id. */
private static function mapped_items() {
global $wpdb;
// Product meta is still post meta (HPOS moves orders only).
$rows = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->prepare( "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s", MARKITMALL_DS_META_VARIANT )
);
$map = array();
foreach ( (array) $rows as $row ) {
$map[ (int) $row->post_id ] = (string) $row->meta_value;
}
return $map;
}
public static function reconcile() {
if ( ! MarkitMall_DS_API::is_configured() ) {
return;
}
$map = self::mapped_items();
$parents = array();
foreach ( array_chunk( $map, 100, true ) as $chunk ) {
$result = MarkitMall_DS_API::get( '/inventory?ids=' . rawurlencode( implode( ',', array_unique( array_values( $chunk ) ) ) ) );
if ( is_wp_error( $result ) ) {
return; // Try again at the next run.
}
$by_variant = array();
foreach ( (array) $result['data'] as $row ) {
$by_variant[ $row['variantId'] ] = $row;
}
foreach ( $chunk as $post_id => $variant_id ) {
$item = wc_get_product( $post_id );
if ( ! $item || ! isset( $by_variant[ $variant_id ] ) ) {
continue;
}
$row = $by_variant[ $variant_id ];
$parent_id = $item->get_parent_id() ? $item->get_parent_id() : $item->get_id();
// A null productId: MarkitMall no longer has the product at all.
$gone = empty( $row['productId'] );
$parents[ $parent_id ] = isset( $parents[ $parent_id ] ) ? $parents[ $parent_id ] && $gone : $gone;
$stock = ! empty( $row['available'] ) ? max( 0, (int) $row['stock'] ) : 0;
$changed = false;
if ( (int) $item->get_stock_quantity() !== $stock || ! $item->get_manage_stock() ) {
$item->set_manage_stock( true );
$item->set_stock_quantity( $stock );
$changed = true;
}
if ( ! $gone ) {
$changed = self::raise_to_floor( $item, isset( $row['minResalePrice'] ) ? (int) $row['minResalePrice'] : 0 ) || $changed;
$changed = MarkitMall_DS_Catalog::set_cost( $item, isset( $row['wholesalePrice'] ) ? $row['wholesalePrice'] : null ) || $changed;
}
if ( $changed ) {
$item->save();
}
}
}
foreach ( $parents as $parent_id => $gone ) {
$product = wc_get_product( $parent_id );
if ( ! $product ) {
continue;
}
if ( $gone && 'publish' === $product->get_status() ) {
// No longer for sale: take it off the store rather than sell what cannot ship.
$product->set_status( 'draft' );
$product->save();
self::flag( sprintf( 'ā%sā is no longer available from MarkitMall and was unpublished.', $product->get_name() ) );
} elseif ( $product->is_type( 'variable' ) ) {
WC_Product_Variable::sync( $parent_id );
}
}
self::backfill_free_delivery();
}
/**
* Products imported before free delivery was recorded: look each up on
* MarkitMall once, 25 a run, so MarkitMall delivery charges them right.
*/
public static function backfill_free_delivery() {
$ids = wc_get_products(
array(
'limit' => 25,
'return' => 'ids',
'status' => array( 'publish', 'draft', 'pending', 'private' ),
'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery
array(
'key' => MARKITMALL_DS_META_PRODUCT,
'compare' => 'EXISTS',
),
array(
'key' => MarkitMall_DS_Delivery::META_FREE,
'compare' => 'NOT EXISTS',
),
),
)
);
foreach ( $ids as $id ) {
$product = wc_get_product( $id );
$remote = MarkitMall_DS_API::get( '/catalog/products/' . rawurlencode( (string) $product->get_meta( MARKITMALL_DS_META_PRODUCT ) ) );
if ( is_wp_error( $remote ) ) {
if ( 'not_found' !== $remote->get_error_code() ) {
return; // MarkitMall unreachable: carry on next run.
}
$remote = array();
}
$product->update_meta_data( MarkitMall_DS_Delivery::META_FREE, MarkitMall_DS_Delivery::is_free( $remote ) ? 'yes' : 'no' );
$product->save();
}
}
}