文件
mashangyoujiu/Application/Cron/Controller/OrderSyncController.class.php

376 行
14 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?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()
)
));
}
}