bianjunhui преди 3 дни
родител
ревизия
82f5f87a52
променени са 2 файла, в които са добавени 281 реда и са изтрити 0 реда
  1. 271 0
      packages/Webkul/Shop/src/Http/Controllers/API/OrderController.php
  2. 10 0
      packages/Webkul/Shop/src/Routes/api-token.php

+ 271 - 0
packages/Webkul/Shop/src/Http/Controllers/API/OrderController.php

@@ -0,0 +1,271 @@
+<?php
+
+namespace Webkul\Shop\Http\Controllers\API;
+
+use Carbon\Carbon;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Longyi\RewardPoints\Helpers\ApiResponse;
+use Webkul\Sales\Models\Order;
+use Webkul\Sales\Repositories\OrderRepository;
+
+class OrderController extends APIController
+{
+    /**
+     * Create a new controller instance.
+     */
+    public function __construct(protected OrderRepository $orderRepository) {}
+
+    /**
+     * 获取当前客户订单列表(分页)
+     *
+     * @param  Request  $request
+     * @return JsonResponse
+     */
+    public function index(Request $request): JsonResponse
+    {
+        $customer = auth()->guard('customer')->user();
+        if (! $customer) {
+            return ApiResponse::unauthorized();
+        }
+
+        $page  = (int) $request->input('page', 1);
+        $limit = (int) $request->input('limit', 10);
+        $limit = min(max($limit, 1), 100);
+
+        $status = $request->input('status');
+
+        $query = Order::query()
+            ->where('customer_id', $customer->id)
+            ->orderBy('created_at', 'desc');
+
+        if ($status) {
+            $query->where('status', $status);
+        }
+
+        $paginator = $query->paginate($limit, ['*'], 'page', $page);
+
+        $orders = $paginator->through(function ($order) {
+            return $this->formatOrderListItem($order);
+        });
+
+        return ApiResponse::paginated($orders->values(), $paginator);
+    }
+
+    /**
+     * 获取订单详情
+     *
+     * @param  int  $id
+     * @return JsonResponse
+     */
+    public function show(int $id): JsonResponse
+    {
+        $customer = auth()->guard('customer')->user();
+        if (! $customer) {
+            return ApiResponse::unauthorized();
+        }
+
+        $order = Order::query()
+            ->with([
+                'items' => function ($q) {
+                    $q->whereNull('parent_id');
+                },
+                'items.child',
+                'items.additional',
+                'billing_address',
+                'shipping_address',
+                'payment',
+                'invoices',
+                'invoices.items',
+                'shipments',
+                'shipments.items',
+                'refunds',
+                'comments',
+            ])
+            ->where('customer_id', $customer->id)
+            ->where('id', $id)
+            ->first();
+
+        if (! $order) {
+            return ApiResponse::notFound('Order not found');
+        }
+
+        return ApiResponse::success($this->formatOrderDetail($order));
+    }
+
+    /**
+     * 格式化订单列表项
+     */
+    protected function formatOrderListItem(Order $order): array
+    {
+        return [
+            'id'                  => $order->id,
+            'increment_id'        => $order->increment_id,
+            'status'              => $order->status,
+            'status_label'        => $this->getStatusLabel($order->status),
+            'grand_total'         => (float) $order->grand_total,
+            'order_currency_code' => $order->order_currency_code,
+            'item_count'          => $order->items->sum('qty_ordered'),
+            'items'               => $order->items->map(fn ($item) => [
+                'id'          => $item->id,
+                'name'        => $item->name,
+                'sku'         => $item->sku,
+                'qty_ordered' => $item->qty_ordered,
+                'price'       => (float) $item->price,
+                'total'       => (float) $item->total,
+                'product_id'  => $item->product_id,
+            ])->values(),
+            'created_at'          => $order->created_at ? Carbon::parse($order->created_at)->toDateTimeString() : null,
+            'can_cancel'          => $order->canCancel(),
+            'can_reorder'         => $order->canReorder(),
+        ];
+    }
+
+    /**
+     * 格式化订单详情
+     */
+    protected function formatOrderDetail(Order $order): array
+    {
+        return [
+            'id'                  => $order->id,
+            'increment_id'        => $order->increment_id,
+            'status'              => $order->status,
+            'status_label'        => $this->getStatusLabel($order->status),
+            'customer_email'      => $order->customer_email,
+            'customer_first_name' => $order->customer_first_name,
+            'customer_last_name'  => $order->customer_last_name,
+            'channel_name'        => $order->channel_name,
+            'order_currency_code' => $order->order_currency_code,
+
+            'sub_total'        => (float) $order->sub_total,
+            'shipping_amount'  => (float) $order->shipping_amount,
+            'tax_amount'       => (float) ($order->tax_amount ?? 0),
+            'discount_amount'  => (float) ($order->discount_amount ?? 0),
+            'grand_total'      => (float) $order->grand_total,
+            'total_qty_ordered'=> $order->total_qty_ordered,
+
+            'shipping_method'  => $order->shipping_method,
+            'shipping_title'   => $order->shipping_title,
+
+            'billing_address'  => $this->formatAddress($order->billing_address),
+            'shipping_address' => $this->formatAddress($order->shipping_address),
+
+            'payment'          => $order->payment ? [
+                'method'       => $order->payment->method,
+                'method_title' => $order->payment->method_title,
+            ] : null,
+
+            'items'            => $order->items->map(fn ($item) => [
+                'id'           => $item->id,
+                'name'         => $item->name,
+                'sku'          => $item->sku,
+                'type'         => $item->type,
+                'qty_ordered'  => $item->qty_ordered,
+                'qty_shipped'  => (int) ($item->qty_shipped ?? 0),
+                'qty_invoiced' => (int) ($item->qty_invoiced ?? 0),
+                'qty_canceled' => (int) ($item->qty_canceled ?? 0),
+                'qty_refunded' => (int) ($item->qty_refunded ?? 0),
+                'price'        => (float) $item->price,
+                'total'        => (float) $item->total,
+                'weight'       => (float) ($item->weight ?? 0),
+                'product_id'   => $item->product_id,
+                'additional'   => $item->additional ? $item->additional->toArray() : null,
+            ])->values(),
+
+            'invoices'         => $order->invoices->map(fn ($invoice) => [
+                'id'           => $invoice->id,
+                'increment_id' => $invoice->increment_id ?? ('#' . $invoice->id),
+                'state'        => $invoice->state,
+                'email_sent'   => $invoice->email_sent,
+                'total_qty'    => $invoice->total_qty,
+                'sub_total'    => (float) $invoice->sub_total,
+                'grand_total'  => (float) $invoice->grand_total,
+                'created_at'   => $invoice->created_at ? Carbon::parse($invoice->created_at)->toDateTimeString() : null,
+                'items'        => $invoice->items->map(fn ($invItem) => [
+                    'name'  => $invItem->name,
+                    'qty'   => $invItem->qty,
+                    'price' => (float) $invItem->price,
+                    'total' => (float) $invItem->total,
+                ])->values(),
+            ])->values(),
+
+            'shipments'        => $order->shipments->map(fn ($shipment) => [
+                'id'           => $shipment->id,
+                'increment_id' => $shipment->increment_id ?? ('#' . $shipment->id),
+                'status'       => $shipment->status,
+                'total_qty'    => $shipment->total_qty,
+                'total_weight' => (float) $shipment->total_weight,
+                'carrier_code' => $shipment->carrier_code,
+                'carrier_title'=> $shipment->carrier_title,
+                'track_number' => $shipment->track_number,
+                'created_at'   => $shipment->created_at ? Carbon::parse($shipment->created_at)->toDateTimeString() : null,
+                'items'        => $shipment->items->map(fn ($shipItem) => [
+                    'name'     => $shipItem->name,
+                    'qty'      => $shipItem->qty,
+                ])->values(),
+            ])->values(),
+
+            'refunds'          => $order->refunds->map(fn ($refund) => [
+                'id'           => $refund->id,
+                'increment_id' => $refund->increment_id ?? ('#' . $refund->id),
+                'state'        => $refund->state,
+                'total_qty'    => $refund->total_qty,
+                'grand_total'  => (float) $refund->grand_total,
+                'created_at'   => $refund->created_at ? Carbon::parse($refund->created_at)->toDateTimeString() : null,
+            ])->values(),
+
+            'comments'         => $order->comments->map(fn ($comment) => [
+                'comment'           => $comment->comment,
+                'customer_notified' => $comment->customer_notified,
+                'created_at'        => $comment->created_at ? Carbon::parse($comment->created_at)->toDateTimeString() : null,
+            ])->values(),
+
+            'can_cancel'       => $order->canCancel(),
+            'can_reorder'      => $order->canReorder(),
+
+            'created_at'       => $order->created_at ? Carbon::parse($order->created_at)->toDateTimeString() : null,
+            'updated_at'       => $order->updated_at ? Carbon::parse($order->updated_at)->toDateTimeString() : null,
+        ];
+    }
+
+    /**
+     * 格式化地址
+     */
+    protected function formatAddress($address): ?array
+    {
+        if (! $address) {
+            return null;
+        }
+
+        return [
+            'first_name' => $address->first_name,
+            'last_name'  => $address->last_name,
+            'email'      => $address->email,
+            'phone'      => $address->phone,
+            'address1'   => $address->address1,
+            'address2'   => $address->address2,
+            'city'       => $address->city,
+            'state'      => $address->state,
+            'country'    => $address->country,
+            'postcode'   => $address->postcode,
+            'company'    => $address->company_name,
+        ];
+    }
+
+    /**
+     * 获取状态中文标签
+     */
+    protected function getStatusLabel(string $status): string
+    {
+        return match ($status) {
+            Order::STATUS_PENDING         => '待处理',
+            Order::STATUS_PENDING_PAYMENT => '待付款',
+            Order::STATUS_PROCESSING      => '处理中',
+            Order::STATUS_COMPLETED       => '已完成',
+            Order::STATUS_CANCELED        => '已取消',
+            Order::STATUS_CLOSED          => '已关闭',
+            Order::STATUS_FRAUD           => '欺诈',
+            default                       => $status,
+        };
+    }
+}

+ 10 - 0
packages/Webkul/Shop/src/Routes/api-token.php

@@ -3,6 +3,7 @@
 use Illuminate\Support\Facades\Route;
 use Webkul\Shop\Http\Controllers\API\BearerAddressController;
 use Webkul\Shop\Http\Controllers\API\CouponController;
+use Webkul\Shop\Http\Controllers\API\OrderController;
 
 /**
  * Bearer Token 认证的 API 路由
@@ -34,4 +35,13 @@ Route::group(['prefix' => 'api'], function () {
             Route::post('claim', 'claim')->name('shop.api.token.customer.coupons.claim');
         });
 
+    /** 客户订单管理(Bearer Token 认证) */
+    Route::controller(OrderController::class)
+        ->middleware('bearer.token')
+        ->prefix('customer/orders')
+        ->group(function () {
+            Route::get('', 'index')->name('shop.api.token.customer.orders.index');
+            Route::get('{id}', 'show')->name('shop.api.token.customer.orders.show');
+        });
+
 });