productService = $productService; } public function upsert(Request $request) { $request->validate([ 'external_pos_id' => 'required|string|max:255', 'name' => 'required|string|max:255', 'price' => 'nullable|numeric|min:0|max:99999999.99', 'barcode' => 'nullable|string|max:100', 'category' => 'required|string|max:100', 'unit' => 'required|string|max:100', 'brand' => 'nullable|string|max:100', 'specification' => 'nullable|string|max:255', 'cost_price' => 'nullable|numeric|min:0|max:99999999.99', 'member_price' => 'nullable|numeric|min:0|max:99999999.99', 'wholesale_price' => 'nullable|numeric|min:0|max:99999999.99', 'updated_at' => 'nullable|date', ]); try { $product = $this->productService->upsertFromPos($request->all()); return response()->json([ 'message' => 'Product synced successfully', 'data' => [ 'id' => $product->id, 'external_pos_id' => $product->external_pos_id, 'code' => $product->code, 'barcode' => $product->barcode, ] ]); } catch (\Exception $e) { Log::error('Product Sync Failed', ['error' => $e->getMessage(), 'payload' => $request->all()]); return response()->json([ 'message' => 'Sync failed: ' . $e->getMessage(), ], 500); } } /** * 搜尋商品(供外部 API 使用)。 * * @param Request $request * @return \Illuminate\Http\JsonResponse */ public function index(Request $request) { $request->validate([ 'product_id' => 'nullable|integer', 'external_pos_id' => 'nullable|string|max:255', 'barcode' => 'nullable|string|max:100', 'code' => 'nullable|string|max:100', 'category' => 'nullable|string|max:100', 'updated_after' => 'nullable|date', 'per_page' => 'nullable|integer|min:1|max:100', ]); try { $perPage = $request->input('per_page', 50); $products = $this->productService->searchProducts($request->all(), $perPage); return response()->json([ 'status' => 'success', 'data' => $products->getCollection()->map(function ($product) { return [ 'id' => $product->id, 'code' => $product->code, 'barcode' => $product->barcode, 'name' => $product->name, 'external_pos_id' => $product->external_pos_id, 'category_name' => $product->category?->name ?? '未分類', 'brand' => $product->brand, 'specification' => $product->specification, 'unit_name' => $product->baseUnit?->name ?? '個', 'price' => (float) $product->price, 'cost_price' => (float) $product->cost_price, 'member_price' => (float) $product->member_price, 'wholesale_price' => (float) $product->wholesale_price, 'is_active' => (bool) $product->is_active, 'updated_at' => $product->updated_at->format('Y-m-d H:i:s'), ]; }), 'meta' => [ 'current_page' => $products->currentPage(), 'last_page' => $products->lastPage(), 'per_page' => $products->perPage(), 'total' => $products->total(), ] ]); } catch (\Exception $e) { Log::error('Product Search Failed', ['error' => $e->getMessage()]); return response()->json([ 'status' => 'error', 'message' => 'Search failed: ' . $e->getMessage(), ], 500); } } }