200 lines
7.3 KiB
PHP
200 lines
7.3 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Models\ShopAuth;
|
||
use App\Models\PlatformOrder;
|
||
use App\Models\Order;
|
||
use App\Models\OrderItem;
|
||
use App\Jobs\ProcessPlatformOrderJob;
|
||
use App\Services\Platform\TaobaoClient;
|
||
use App\Services\Platform\JdClient;
|
||
use App\Services\Platform\PddClient;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Log;
|
||
use Illuminate\Support\Str;
|
||
|
||
class OrderPullService
|
||
{
|
||
// 每批最大拉取数量
|
||
const BATCH_SIZE = 200;
|
||
|
||
// 两次拉取最小间隔(秒)
|
||
const PULL_INTERVAL = 60;
|
||
|
||
/**
|
||
* 生成内部短订单号
|
||
* 规则:纯数字,从1000开始,每次+2,四位数用完自动扩展五位数
|
||
*/
|
||
private function generateShortId(): string
|
||
{
|
||
$maxShortId = Order::where('short_id', 'REGEXP', '^[0-9]+$')
|
||
->orderByDesc('short_id')
|
||
->value('short_id');
|
||
|
||
if ($maxShortId) {
|
||
$nextId = intval($maxShortId) + 2;
|
||
} else {
|
||
$nextId = 1000;
|
||
}
|
||
|
||
return (string) $nextId;
|
||
}
|
||
|
||
/**
|
||
* 拉取订单(支持定量分批)
|
||
*
|
||
* @param string $platform
|
||
* @param string $shopId 店铺授权记录的 ID
|
||
* @param string|null $startTime
|
||
* @param string|null $endTime
|
||
* @param int $limit 最大拉取数量,默认200
|
||
* @return array ['count' => 实际拉取数量, 'has_more' => 是否有更多, 'next_cursor' => 下一页cursor]
|
||
*/
|
||
public function pullOrders($platform, $shopId, $startTime = null, $endTime = null, int $limit = self::BATCH_SIZE)
|
||
{
|
||
// 限制单次最大拉取量
|
||
$limit = min($limit, self::BATCH_SIZE);
|
||
|
||
$shopAuth = ShopAuth::find($shopId);
|
||
if (!$shopAuth) {
|
||
throw new \Exception("店铺授权记录不存在,ID: {$shopId}");
|
||
}
|
||
|
||
$client = $this->getPlatformClient($platform, $shopAuth);
|
||
|
||
$params = [
|
||
'start_time' => $startTime,
|
||
'end_time' => $endTime,
|
||
'limit' => $limit,
|
||
];
|
||
|
||
$result = $client->getOrders($params);
|
||
|
||
$orders = $result['orders'] ?? [];
|
||
$hasMore = $result['has_more'] ?? false;
|
||
$nextCursor = $result['next_cursor'] ?? null;
|
||
|
||
$queuedCount = 0;
|
||
foreach ($orders as $orderData) {
|
||
try {
|
||
// 每个订单放入队列异步处理
|
||
ProcessPlatformOrderJob::dispatch($platform, $shopAuth->id, $orderData);
|
||
$queuedCount++;
|
||
} catch (\Exception $e) {
|
||
Log::error('订单加入队列失败', [
|
||
'platform' => $platform,
|
||
'shop_id' => $shopAuth->id,
|
||
'order_no' => $orderData['platform_order_sn'] ?? 'unknown',
|
||
'error' => $e->getMessage(),
|
||
]);
|
||
}
|
||
}
|
||
|
||
return [
|
||
'count' => $queuedCount,
|
||
'has_more' => $hasMore,
|
||
'next_cursor' => $nextCursor,
|
||
'total_received' => count($orders),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 获取平台客户端
|
||
*/
|
||
private function getPlatformClient($platform, $shopAuth)
|
||
{
|
||
$config = [
|
||
'app_key' => $shopAuth->app_key,
|
||
'app_secret' => $shopAuth->app_secret,
|
||
'access_token' => $shopAuth->access_token,
|
||
];
|
||
|
||
return match ($platform) {
|
||
'taobao' => new TaobaoClient($config),
|
||
'jd' => new JdClient($config),
|
||
'pdd' => new PddClient($config),
|
||
default => throw new \Exception("不支持的平台: {$platform}"),
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 处理单个订单(保存到数据库)
|
||
*/
|
||
public function processSingleOrder($platform, $shopAuthId, $orderData)
|
||
{
|
||
$platformOrderNo = $orderData['platform_order_sn'];
|
||
|
||
return DB::transaction(function () use ($platform, $shopAuthId, $orderData, $platformOrderNo) {
|
||
// 检查平台订单是否已存在
|
||
$exists = PlatformOrder::where([
|
||
'platform_type' => $platform,
|
||
'platform_shop_id' => $shopAuthId,
|
||
'platform_order_no' => $platformOrderNo,
|
||
])->lockForUpdate()->exists();
|
||
|
||
if ($exists) {
|
||
Log::info('订单已存在,跳过', ['order_no' => $platformOrderNo]);
|
||
return ['status' => 'skipped', 'reason' => '订单已存在'];
|
||
}
|
||
|
||
// 创建平台订单原始记录
|
||
$platformOrder = PlatformOrder::create([
|
||
'platform_type' => $platform,
|
||
'platform_shop_id' => $shopAuthId,
|
||
'platform_order_no'=> $platformOrderNo,
|
||
'order_status' => $orderData['platform_status'] ?? null,
|
||
'order_amount' => $orderData['total_amount'] ?? 0,
|
||
'buyer_name' => $orderData['buyer_nick'] ?? null,
|
||
'buyer_phone' => $orderData['receiver_phone'] ?? null,
|
||
'receiver_address' => $orderData['receiver_address'] ?? null,
|
||
'order_time' => $orderData['order_time'],
|
||
'payment_time' => $orderData['payment_time'] ?? null,
|
||
'raw_data' => json_encode($orderData),
|
||
]);
|
||
|
||
// 生成短订单号
|
||
$shortId = $this->generateShortId();
|
||
|
||
// 创建ERP主订单
|
||
$order = Order::create([
|
||
'short_id' => $shortId,
|
||
'platform_order_sn' => $platformOrderNo,
|
||
'platform' => $platform,
|
||
'shop_id' => $shopAuthId,
|
||
'shop_name' => $orderData['shop_name'] ?? '未知店铺',
|
||
'order_time' => $orderData['order_time'],
|
||
'payment_time' => $orderData['payment_time'] ?? null,
|
||
'buyer_nick' => $orderData['buyer_nick'] ?? null,
|
||
'receiver_name' => $orderData['receiver_name'] ?? null,
|
||
'receiver_phone' => $orderData['receiver_phone'] ?? null,
|
||
'receiver_address' => $orderData['receiver_address'] ?? null,
|
||
'goods_amount' => $orderData['goods_amount'] ?? 0,
|
||
'discount_amount' => $orderData['discount_amount'] ?? 0,
|
||
'freight' => $orderData['freight'] ?? 0,
|
||
'total_amount' => $orderData['total_amount'] ?? 0,
|
||
'order_status' => 'pending',
|
||
'platform_status' => $orderData['platform_status'] ?? null,
|
||
'items' => json_encode($orderData['items'] ?? []),
|
||
]);
|
||
|
||
// 创建订单商品明细
|
||
if (!empty($orderData['items'])) {
|
||
foreach ($orderData['items'] as $item) {
|
||
OrderItem::create([
|
||
'order_id' => $order->id,
|
||
'sku_id' => $item['sku_id'] ?? null,
|
||
'sku_code' => $item['sku_code'] ?? null,
|
||
'goods_name' => $item['goods_name'] ?? $item['title'] ?? null,
|
||
'quantity' => $item['num'] ?? $item['quantity'] ?? 1,
|
||
'price' => $item['price'] ?? 0,
|
||
'total' => $item['total'] ?? $item['amount'] ?? 0,
|
||
]);
|
||
}
|
||
}
|
||
|
||
return ['status' => 'success', 'order_id' => $order->id];
|
||
});
|
||
}
|
||
}
|