376 行
14 KiB
PHP
376 行
14 KiB
PHP
<?php
|
||
namespace Cron\Controller;
|
||
use Think\Controller;
|
||
use Common\Business\OrderSyncService;
|
||
|
||
/**
|
||
* 订单同步定时任务控制器 - Web访问版本
|
||
* 用于定时同步骑手订单状态到原始订单系统
|
||
*
|
||
* 使用方法:
|
||
* Web访问:http://your-domain.com/Cron/OrderSync/syncRiderOrderStatus?key=your_secret_key
|
||
* Cron示例:* * * * * curl "http://your-domain.com/Cron/OrderSync/syncRiderOrderStatus?key=your_secret_key"
|
||
*
|
||
* 注意:请在配置文件中设置 CRON_SECRET_KEY 常量以保护接口安全
|
||
*/
|
||
class OrderSyncController extends Controller {
|
||
|
||
// 定时任务密钥(建议在配置文件中设置)
|
||
const SECRET_KEY = 'your_secret_key_here'; // 请修改为安全的密钥
|
||
|
||
/**
|
||
* 构造函数 - 验证访问权限
|
||
*/
|
||
public function _initialize() {
|
||
// 验证密钥
|
||
$key = I('get.key', '');
|
||
$configKey = defined('CRON_SECRET_KEY') ? CRON_SECRET_KEY : self::SECRET_KEY;
|
||
|
||
if ($key !== $configKey) {
|
||
$this->ajaxReturn(array(
|
||
'code' => 0,
|
||
'msg' => '访问密钥错误',
|
||
'data' => null
|
||
));
|
||
}
|
||
|
||
// 设置最大执行时间
|
||
set_time_limit(300);
|
||
}
|
||
|
||
/**
|
||
* 同步骑手订单状态到原始订单
|
||
* 当骑手接单后,修改原始订单状态为发货
|
||
* 当骑手配送完成后,修改原始订单状态为完成
|
||
*/
|
||
public function syncRiderOrderStatus() {
|
||
$startTime = microtime(true);
|
||
$result = array(
|
||
'code' => 1,
|
||
'msg' => '执行成功',
|
||
'data' => array(
|
||
'start_time' => date('Y-m-d H:i:s'),
|
||
'end_time' => '',
|
||
'duration' => 0,
|
||
'accept_sync' => array('success' => 0, 'fail' => 0),
|
||
'complete_sync' => array('success' => 0, 'fail' => 0),
|
||
'total_success' => 0,
|
||
'total_fail' => 0
|
||
)
|
||
);
|
||
|
||
try {
|
||
// 1. 检查是否启用自动同步
|
||
if (!$this->isAutoSyncEnabled()) {
|
||
$result['msg'] = '自动同步未启用';
|
||
$this->log('自动同步未启用,任务终止');
|
||
$this->ajaxReturn($result);
|
||
}
|
||
|
||
// 2. 同步骑手接单状态(将原始订单状态改为发货)
|
||
$acceptResult = $this->syncAcceptedOrders();
|
||
$result['data']['accept_sync'] = $acceptResult;
|
||
|
||
// 3. 同步骑手配送完成状态(将原始订单状态改为完成)
|
||
$completeResult = $this->syncCompletedOrders();
|
||
$result['data']['complete_sync'] = $completeResult;
|
||
|
||
// 4. 计算总计
|
||
$result['data']['total_success'] = $acceptResult['success'] + $completeResult['success'];
|
||
$result['data']['total_fail'] = $acceptResult['fail'] + $completeResult['fail'];
|
||
$result['data']['end_time'] = date('Y-m-d H:i:s');
|
||
$result['data']['duration'] = round(microtime(true) - $startTime, 2);
|
||
|
||
// 记录日志
|
||
$this->log("同步任务完成,成功 {$result['data']['total_success']} 个,失败 {$result['data']['total_fail']} 个");
|
||
|
||
} catch (\Exception $e) {
|
||
$result['code'] = 0;
|
||
$result['msg'] = '同步任务异常:' . $e->getMessage();
|
||
$result['data']['error'] = $e->getTraceAsString();
|
||
$this->log('同步任务异常:' . $e->getMessage());
|
||
}
|
||
|
||
$this->ajaxReturn($result);
|
||
}
|
||
|
||
/**
|
||
* 检查是否启用自动同步
|
||
* @return bool
|
||
*/
|
||
private function isAutoSyncEnabled() {
|
||
$config = M('rider_config')->where(array('merchant_id' => 0))->find();
|
||
if (!$config) {
|
||
// 如果没有配置,尝试获取任意一个商户的配置
|
||
$config = M('rider_config')->where(array('auto_sync_enabled' => 1))->find();
|
||
}
|
||
return $config && $config['auto_sync_enabled'] == 1;
|
||
}
|
||
|
||
/**
|
||
* 同步骑手接单状态
|
||
* 将原始订单状态更新为发货(status=2)
|
||
*
|
||
* @return array 统计结果
|
||
*/
|
||
private function syncAcceptedOrders() {
|
||
$successCount = 0;
|
||
$failCount = 0;
|
||
$errors = array();
|
||
|
||
// 查询已接单但原订单未发货的骑手订单
|
||
$where = array();
|
||
$where['ro.order_status'] = array('in', array(1, 2, 3, 4, 5)); // 已接单到配送中的状态
|
||
$where['o.status'] = 1; // 原订单状态为未发货
|
||
|
||
$orders = M('rider_order')->alias('ro')
|
||
->join('LEFT JOIN ls_retail_bill_online o ON ro.bill_id = o.bill_id')
|
||
->where($where)
|
||
->field('ro.id as rider_order_id, ro.bill_id, ro.order_status, ro.rider_id, o.status as original_status')
|
||
->select();
|
||
|
||
if (empty($orders)) {
|
||
return array('success' => 0, 'fail' => 0, 'message' => '没有需要同步的接单订单');
|
||
}
|
||
|
||
foreach ($orders as $order) {
|
||
try {
|
||
// 更新原始订单状态为发货(status=2)
|
||
$result = M('retail_bill_online')->where(array('bill_id' => $order['bill_id']))->save(array(
|
||
'status' => 2,
|
||
'send_time' => date('Y-m-d H:i:s')
|
||
));
|
||
|
||
if ($result !== false) {
|
||
$successCount++;
|
||
|
||
// 记录同步日志
|
||
$this->logSyncStatus(
|
||
$order['bill_id'],
|
||
$order['rider_order_id'],
|
||
$order['rider_id'],
|
||
'accept',
|
||
$order['original_status'],
|
||
2,
|
||
1,
|
||
''
|
||
);
|
||
} else {
|
||
$failCount++;
|
||
$errors[] = "订单 {$order['bill_id']} 状态更新失败";
|
||
|
||
$this->logSyncStatus(
|
||
$order['bill_id'],
|
||
$order['rider_order_id'],
|
||
$order['rider_id'],
|
||
'accept',
|
||
$order['original_status'],
|
||
2,
|
||
0,
|
||
'数据库更新失败'
|
||
);
|
||
}
|
||
|
||
} catch (\Exception $e) {
|
||
$failCount++;
|
||
$errors[] = "订单 {$order['bill_id']} 处理异常:{$e->getMessage()}";
|
||
|
||
$this->logSyncStatus(
|
||
$order['bill_id'],
|
||
$order['rider_order_id'],
|
||
$order['rider_id'],
|
||
'accept',
|
||
$order['original_status'],
|
||
2,
|
||
0,
|
||
$e->getMessage()
|
||
);
|
||
}
|
||
}
|
||
|
||
return array(
|
||
'success' => $successCount,
|
||
'fail' => $failCount,
|
||
'total' => count($orders),
|
||
'errors' => $errors
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 同步骑手配送完成状态
|
||
* 将原始订单状态更新为完成(status=3)
|
||
*
|
||
* @return array 统计结果
|
||
*/
|
||
private function syncCompletedOrders() {
|
||
$successCount = 0;
|
||
$failCount = 0;
|
||
$errors = array();
|
||
|
||
// 查询配送完成但原订单未完成的骑手订单
|
||
$where = array();
|
||
$where['ro.order_status'] = 6; // 已送达
|
||
$where['o.status'] = array('in', array(1, 2)); // 原订单状态为未发货或已发货
|
||
|
||
$orders = M('rider_order')->alias('ro')
|
||
->join('LEFT JOIN ls_retail_bill_online o ON ro.bill_id = o.bill_id')
|
||
->where($where)
|
||
->field('ro.id as rider_order_id, ro.bill_id, ro.order_status, ro.rider_id, ro.delivery_time, o.status as original_status')
|
||
->select();
|
||
|
||
if (empty($orders)) {
|
||
return array('success' => 0, 'fail' => 0, 'message' => '没有需要同步的完成订单');
|
||
}
|
||
|
||
foreach ($orders as $order) {
|
||
try {
|
||
// 更新原始订单状态为完成(status=3)
|
||
$updateData = array(
|
||
'status' => 3,
|
||
'receipt_time' => !empty($order['delivery_time']) ? $order['delivery_time'] : date('Y-m-d H:i:s')
|
||
);
|
||
|
||
$result = M('retail_bill_online')->where(array('bill_id' => $order['bill_id']))->save($updateData);
|
||
|
||
if ($result !== false) {
|
||
$successCount++;
|
||
|
||
// 记录同步日志
|
||
$this->logSyncStatus(
|
||
$order['bill_id'],
|
||
$order['rider_order_id'],
|
||
$order['rider_id'],
|
||
'complete',
|
||
$order['original_status'],
|
||
3,
|
||
1,
|
||
''
|
||
);
|
||
} else {
|
||
$failCount++;
|
||
$errors[] = "订单 {$order['bill_id']} 状态更新失败";
|
||
|
||
$this->logSyncStatus(
|
||
$order['bill_id'],
|
||
$order['rider_order_id'],
|
||
$order['rider_id'],
|
||
'complete',
|
||
$order['original_status'],
|
||
3,
|
||
0,
|
||
'数据库更新失败'
|
||
);
|
||
}
|
||
|
||
} catch (\Exception $e) {
|
||
$failCount++;
|
||
$errors[] = "订单 {$order['bill_id']} 处理异常:{$e->getMessage()}";
|
||
|
||
$this->logSyncStatus(
|
||
$order['bill_id'],
|
||
$order['rider_order_id'],
|
||
$order['rider_id'],
|
||
'complete',
|
||
$order['original_status'],
|
||
3,
|
||
0,
|
||
$e->getMessage()
|
||
);
|
||
}
|
||
}
|
||
|
||
return array(
|
||
'success' => $successCount,
|
||
'fail' => $failCount,
|
||
'total' => count($orders),
|
||
'errors' => $errors
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 记录同步状态日志
|
||
*
|
||
* @param int $billId 原订单ID
|
||
* @param int $riderOrderId 骑手订单ID
|
||
* @param int $riderId 骑手ID
|
||
* @param string $operationType 操作类型
|
||
* @param int $oldStatus 原状态
|
||
* @param int $newStatus 新状态
|
||
* @param int $syncResult 同步结果
|
||
* @param string $errorMsg 错误信息
|
||
*/
|
||
private function logSyncStatus($billId, $riderOrderId, $riderId, $operationType, $oldStatus, $newStatus, $syncResult, $errorMsg = '') {
|
||
$now = date('Y-m-d H:i:s');
|
||
|
||
$logData = array(
|
||
'bill_id' => intval($billId),
|
||
'rider_order_id' => intval($riderOrderId),
|
||
'rider_id' => intval($riderId),
|
||
'operation_type' => $operationType,
|
||
'old_status' => intval($oldStatus),
|
||
'new_status' => intval($newStatus),
|
||
'sync_result' => intval($syncResult),
|
||
'error_msg' => $errorMsg ? $errorMsg : null,
|
||
'sync_time' => $now,
|
||
'retry_count' => 0,
|
||
'add_time' => $now,
|
||
'update_time' => $now,
|
||
);
|
||
|
||
M('rider_order_sync_log')->add($logData);
|
||
}
|
||
|
||
/**
|
||
* 记录运行日志到文件
|
||
*
|
||
* @param string $message 日志消息
|
||
*/
|
||
private function log($message) {
|
||
$logFile = RUNTIME_PATH . 'Logs/OrderSync/' . date('Y-m-d') . '.log';
|
||
$logDir = dirname($logFile);
|
||
|
||
if (!is_dir($logDir)) {
|
||
mkdir($logDir, 0755, true);
|
||
}
|
||
|
||
$logContent = '[' . date('Y-m-d H:i:s') . '] ' . $message . "\n";
|
||
file_put_contents($logFile, $logContent, FILE_APPEND);
|
||
}
|
||
|
||
/**
|
||
* 手动触发批量同步(供管理员使用)
|
||
* 用于将原始订单同步创建为骑手订单
|
||
*/
|
||
public function batchSync() {
|
||
try {
|
||
$syncService = new OrderSyncService();
|
||
$result = $syncService->batchSyncOrders();
|
||
|
||
$this->log("批量同步完成:{$result['message']}");
|
||
$this->ajaxReturn($result);
|
||
|
||
} catch (\Exception $e) {
|
||
$this->log('批量同步异常:' . $e->getMessage());
|
||
$this->ajaxReturn(array(
|
||
'success' => false,
|
||
'message' => '批量同步异常:' . $e->getMessage()
|
||
));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 健康检查接口
|
||
*/
|
||
public function health() {
|
||
$this->ajaxReturn(array(
|
||
'code' => 1,
|
||
'msg' => 'OK',
|
||
'data' => array(
|
||
'time' => date('Y-m-d H:i:s'),
|
||
'auto_sync_enabled' => $this->isAutoSyncEnabled()
|
||
)
|
||
));
|
||
}
|
||
}
|
||
|