Files
cosmopet-woozoho-fulfillment/inc/class-tools.php
2026-05-15 21:06:41 +07:00

206 lines
9.5 KiB
PHP

<?php
if (!defined('ABSPATH')) exit;
class WZHF_Tools {
public static function bootstrap(){
add_action('rest_api_init', function(){
register_rest_route(WZHF_NS, '/tools', array(
'methods' => WP_REST_Server::CREATABLE,
'permission_callback' => function(){ return current_user_can('manage_woocommerce'); },
'callback' => array(__CLASS__, 'handle'),
));
});
}
public static function patch_so_from_order($order_id){
$order = wc_get_order($order_id);
if (!$order) return array('ok'=>false,'error'=>'order_not_found');
global $wpdb; $map = $wpdb->prefix . 'wzhf_orders';
$so_id = $wpdb->get_var($wpdb->prepare("SELECT zoho_salesorder_id FROM $map WHERE wc_order_id=%d", $order_id));
if(!$so_id) return array('ok'=>false,'error'=>'no_mapping');
// Build clamped shipping address from order (fallback billing)
$ship_addr1 = trim($order->get_shipping_address_1());
$ship_addr2 = trim($order->get_shipping_address_2());
if($ship_addr1==='' && $ship_addr2===''){
$ship_addr1 = trim($order->get_billing_address_1());
$ship_addr2 = trim($order->get_billing_address_2());
}
$ship_city = trim($order->get_shipping_city()) ?: trim($order->get_billing_city());
$ship_state = trim($order->get_shipping_state()) ?: trim($order->get_billing_state());
$ship_zip = trim($order->get_shipping_postcode()) ?: trim($order->get_billing_postcode());
$ship_ctry = trim($order->get_shipping_country()) ?: trim($order->get_billing_country());
$addr_line = trim(preg_replace('/\s+/u',' ', trim($ship_addr1.' '.($ship_addr2?:''))));
if(function_exists('mb_substr')){
$address = mb_substr($addr_line,0,90,'UTF-8');
$city = mb_substr($ship_city,0,40,'UTF-8');
$state = mb_substr($ship_state,0,30,'UTF-8');
$zip = mb_substr($ship_zip,0,20,'UTF-8');
$country = mb_substr($ship_ctry,0,30,'UTF-8');
} else {
$address = substr($addr_line,0,90);
$city = substr($ship_city,0,40);
$state = substr($ship_state,0,30);
$zip = substr($ship_zip,0,20);
$country = substr($ship_ctry,0,30);
}
$payload = array('shipping_address'=>array(
'address'=>$address,'city'=>$city,'state'=>$state,'zip'=>$zip,'country'=>$country
));
WZHF_Logger::log('SO patch:addr-lengths', array(
'order_id'=>$order_id,
'address'=> (function_exists('mb_strlen')?mb_strlen($address,'UTF-8'):strlen($address)),
'city'=> (function_exists('mb_strlen')?mb_strlen($city,'UTF-8'):strlen($city)),
'state'=> (function_exists('mb_strlen')?mb_strlen($state,'UTF-8'):strlen($state)),
'zip'=> (function_exists('mb_strlen')?mb_strlen($zip,'UTF-8'):strlen($zip)),
'country'=> (function_exists('mb_strlen')?mb_strlen($country,'UTF-8'):strlen($country))
));
$z = new WZHF_Zoho();
if(!$z->is_connected()) return array('ok'=>false,'error'=>'zoho_disconnected');
// Reuse private request via reflection
$ref = new ReflectionClass('WZHF_Zoho');
$m = $ref->getMethod('request'); $m->setAccessible(true);
$res = $m->invoke($z, 'PUT', '/salesorders/'.rawurlencode($so_id), $payload);
$body = $res[0]; $err = $res[1];
if($body && !empty($body['salesorder'])){
WZHF_Logger::log('SO patch:ok', array('order_id'=>$order_id,'so'=>$so_id));
return array('ok'=>true,'so'=>$so_id);
} else {
WZHF_Logger::log('SO patch:error', array('order_id'=>$order_id,'so'=>$so_id,'err'=>$err));
return array('ok'=>false,'error'=>'patch_failed','details'=>$err);
}
}
public static function handle(WP_REST_Request $req){
if (!current_user_can('manage_woocommerce')) {
return new WP_REST_Response(array('error' => 'forbidden'), 403);
}
$op = sanitize_text_field($req->get_param('op') ? $req->get_param('op') : '');
switch ($op) {
case 'reset_map': {
$order_id = absint($req->get_param('order_id'));
if (!$order_id) return new WP_REST_Response(array('error' => 'order_id required'), 400);
global $wpdb;
$map = $wpdb->prefix . 'wzhf_orders';
$wpdb->delete($map, array('wc_order_id' => $order_id));
delete_post_meta($order_id, '_tracking_number');
delete_post_meta($order_id, '_tracking_carrier');
WZHF_Logger::log('tools:reset_map', array('order_id' => $order_id));
return new WP_REST_Response(array('ok' => true, 'message' => 'Mapping reset'), 200);
}
case 'resend_so': {
$order_id = absint($req->get_param('order_id'));
if (!$order_id) return new WP_REST_Response(array('error' => 'order_id required'), 400);
$order = wc_get_order($order_id);
if (!$order) return new WP_REST_Response(array('error' => 'order_not_found'), 404);
global $wpdb;
$map = $wpdb->prefix . 'wzhf_orders';
// Drop mapping to allow re-send
$wpdb->delete($map, array('wc_order_id' => $order_id));
WZHF_Logger::log('tools:resend_so', array('order_id' => $order_id));
// Try to create
WZHF_Orders_Sync::create_sales_order($order_id);
// Check result
$created = $wpdb->get_var($wpdb->prepare("SELECT zoho_salesorder_id FROM $map WHERE wc_order_id=%d", $order_id));
if ($created) {
return new WP_REST_Response(array('ok' => true, 'message' => 'Created SO: ' . $created), 200);
}
// Not created; hint common reasons
$z = new WZHF_Zoho();
if (!$z->is_connected()) {
return new WP_REST_Response(array('error' => 'zoho_disconnected', 'message' => 'Zoho not connected (refresh OAuth).'), 500);
}
return new WP_REST_Response(array('error' => 'resend_failed', 'message' => 'SO not created. See WooZoho → Логи for details.'), 500);
}
case 'patch_so_address': {
$order_id = absint($req->get_param('order_id'));
if (!$order_id) return new WP_REST_Response(array('error' => 'order_id required'), 400);
$order = wc_get_order($order_id);
if (!$order) return new WP_REST_Response(array('error' => 'order_not_found'), 404);
global $wpdb; $map = $wpdb->prefix . 'wzhf_orders';
$so_id = $wpdb->get_var($wpdb->prepare("SELECT zoho_salesorder_id FROM $map WHERE wc_order_id=%d", $order_id));
if(!$so_id) return new WP_REST_Response(array('error'=>'no_mapping','message'=>'SO mapping not found. Создайте SO сначала.'), 400);
// Build clamped shipping address from order
$ship_addr1 = trim($order->get_shipping_address_1());
$ship_addr2 = trim($order->get_shipping_address_2());
if($ship_addr1==='' && $ship_addr2===''){
// fallback to billing
$ship_addr1 = trim($order->get_billing_address_1());
$ship_addr2 = trim($order->get_billing_address_2());
}
$ship_city = trim($order->get_shipping_city()) ?: trim($order->get_billing_city());
$ship_state = trim($order->get_shipping_state()) ?: trim($order->get_billing_state());
$ship_zip = trim($order->get_shipping_postcode()) ?: trim($order->get_billing_postcode());
$ship_ctry = trim($order->get_shipping_country()) ?: trim($order->get_billing_country());
$addr_line = trim(preg_replace('/\s+/u',' ', trim($ship_addr1.' '.($ship_addr2?:''))));
// Clamp
if(function_exists('mb_substr')){
$address = mb_substr($addr_line,0,90,'UTF-8');
$city = mb_substr($ship_city,0,40,'UTF-8');
$state = mb_substr($ship_state,0,30,'UTF-8');
$zip = mb_substr($ship_zip,0,20,'UTF-8');
$country = mb_substr($ship_ctry,0,30,'UTF-8');
} else {
$address = substr($addr_line,0,90);
$city = substr($ship_city,0,40);
$state = substr($ship_state,0,30);
$zip = substr($ship_zip,0,20);
$country = substr($ship_ctry,0,30);
}
$payload = array('shipping_address'=>array(
'address'=>$address,'city'=>$city,'state'=>$state,'zip'=>$zip,'country'=>$country
));
WZHF_Logger::log('SO patch:addr-lengths', array(
'order_id'=>$order_id,
'address'=> (function_exists('mb_strlen')?mb_strlen($address,'UTF-8'):strlen($address)),
'city'=> (function_exists('mb_strlen')?mb_strlen($city,'UTF-8'):strlen($city)),
'state'=> (function_exists('mb_strlen')?mb_strlen($state,'UTF-8'):strlen($state)),
'zip'=> (function_exists('mb_strlen')?mb_strlen($zip,'UTF-8'):strlen($zip)),
'country'=> (function_exists('mb_strlen')?mb_strlen($country,'UTF-8'):strlen($country))
));
$z = new WZHF_Zoho();
if(!$z->is_connected()) return new WP_REST_Response(array('error'=>'zoho_disconnected'),500);
// Use Zoho request via reflection (quick reuse)
$ref = new ReflectionClass('WZHF_Zoho');
$m = $ref->getMethod('request'); $m->setAccessible(true);
$res = $m->invoke($z, 'PUT', '/salesorders/'.rawurlencode($so_id), $payload);
$body = $res[0]; $err = $res[1];
if($body && !empty($body['salesorder'])){
WZHF_Logger::log('SO patch:ok', array('order_id'=>$order_id,'so'=>$so_id));
return new WP_REST_Response(array('ok'=>true,'message'=>'Patched SO address: '+$so_id),200);
} else {
WZHF_Logger::log('SO patch:error', array('order_id'=>$order_id,'so'=>$so_id,'err'=>$err));
return new WP_REST_Response(array('error'=>'patch_failed','details'=>$err),500);
}
}
default:
return new WP_REST_Response(array('error' => 'unknown_op'), 400);
}
}
}