193 lines
6.9 KiB
TypeScript
193 lines
6.9 KiB
TypeScript
import { getSquareClient, getSquareLocationId, checkSquareConnection } from "@/lib/square-client"
|
|
import type { SquareProduct, SquareCategory } from "@/lib/square-types"
|
|
|
|
export async function GET(request: Request) {
|
|
try {
|
|
console.log("=== Square Catalog API Request ===")
|
|
|
|
// First, check if Square is properly configured
|
|
const connectionCheck = await checkSquareConnection()
|
|
if (!connectionCheck.success) {
|
|
console.error("Square connection failed:", connectionCheck.error)
|
|
return Response.json({
|
|
success: false,
|
|
error: "Square API connection failed",
|
|
details: connectionCheck.error,
|
|
products: [],
|
|
categories: []
|
|
}, { status: 500 })
|
|
}
|
|
|
|
console.log("Square connection verified:", connectionCheck.message)
|
|
|
|
const { searchParams } = new URL(request.url)
|
|
const categoryId = searchParams.get('categoryId')
|
|
const includeInventory = searchParams.get('includeInventory') === 'true'
|
|
|
|
console.log("Category filter:", categoryId)
|
|
console.log("Include inventory:", includeInventory)
|
|
|
|
const client = await getSquareClient()
|
|
const locationId = getSquareLocationId()
|
|
const catalogApi = client.catalogApi
|
|
|
|
// Build search request
|
|
const searchRequest: any = {
|
|
objectTypes: ["ITEM"],
|
|
includeDeletedObjects: false,
|
|
includeRelatedObjects: true,
|
|
}
|
|
|
|
// Add category filter if specified
|
|
if (categoryId) {
|
|
searchRequest.query = {
|
|
exactQuery: {
|
|
attributeName: "category_id",
|
|
attributeValue: categoryId
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log("Searching catalog with request:", searchRequest)
|
|
|
|
// Search catalog items
|
|
const catalogResponse = await catalogApi.searchCatalogObjects(searchRequest)
|
|
|
|
console.log("Catalog response received:", {
|
|
objectCount: catalogResponse.result.objects?.length || 0,
|
|
hasObjects: !!catalogResponse.result.objects
|
|
})
|
|
|
|
if (!catalogResponse.result.objects || catalogResponse.result.objects.length === 0) {
|
|
return Response.json({
|
|
success: true,
|
|
products: [],
|
|
categories: [],
|
|
message: "No products found in Square catalog. Add products in your Square Dashboard."
|
|
})
|
|
}
|
|
|
|
// Separate items and categories
|
|
const items = catalogResponse.result.objects.filter(obj => obj.type === "ITEM")
|
|
const categories = catalogResponse.result.objects.filter(obj => obj.type === "CATEGORY")
|
|
|
|
console.log("Found items:", items.length, "categories:", categories.length)
|
|
|
|
// Process categories
|
|
const processedCategories: SquareCategory[] = categories.map(cat => ({
|
|
id: cat.id!,
|
|
name: cat.categoryData?.name || "Unnamed Category",
|
|
imageUrl: cat.categoryData?.imageIds?.[0]
|
|
? `/api/square/catalog/image/${cat.categoryData.imageIds[0]}`
|
|
: undefined
|
|
}))
|
|
|
|
// Get inventory data if requested
|
|
let inventoryData: Record<string, number> = {}
|
|
if (includeInventory) {
|
|
try {
|
|
const variationIds = items.flatMap(item =>
|
|
item.itemData?.variations?.map(v => v.id!) || []
|
|
).filter(Boolean)
|
|
|
|
if (variationIds.length > 0) {
|
|
console.log("Fetching inventory for", variationIds.length, "variations")
|
|
const inventoryApi = client.inventoryApi
|
|
const inventoryResponse = await inventoryApi.batchRetrieveInventoryCounts({
|
|
catalogObjectIds: variationIds,
|
|
locationIds: [locationId]
|
|
})
|
|
|
|
inventoryResponse.result.counts?.forEach(count => {
|
|
if (count.catalogObjectId) {
|
|
inventoryData[count.catalogObjectId] = parseInt(count.quantity || "0")
|
|
}
|
|
})
|
|
console.log("Inventory data loaded for", Object.keys(inventoryData).length, "items")
|
|
}
|
|
} catch (inventoryError) {
|
|
console.warn("Failed to fetch inventory:", inventoryError)
|
|
// Continue without inventory data
|
|
}
|
|
}
|
|
|
|
// Process items into products
|
|
const products: SquareProduct[] = items
|
|
.filter(item => {
|
|
const hasVariations = item.itemData?.variations && item.itemData.variations.length > 0
|
|
if (!hasVariations) {
|
|
console.warn("Skipping item without variations:", item.id, item.itemData?.name)
|
|
}
|
|
return hasVariations
|
|
})
|
|
.map(item => {
|
|
const itemData = item.itemData!
|
|
const primaryVariation = itemData.variations![0]
|
|
const variationData = primaryVariation.itemVariationData!
|
|
const price = variationData.priceMoney
|
|
|
|
// Get inventory for primary variation
|
|
const inventory = inventoryData[primaryVariation.id!] || 0
|
|
|
|
// Process all variations
|
|
const variations = itemData.variations!.map(variation => {
|
|
const vData = variation.itemVariationData!
|
|
const vPrice = vData.priceMoney
|
|
return {
|
|
id: variation.id!,
|
|
name: vData.name || itemData.name || "Default",
|
|
price: vPrice ? Number(vPrice.amount) / 100 : 0,
|
|
currency: vPrice?.currency || "USD",
|
|
inventory: inventoryData[variation.id!] || 0,
|
|
sku: vData.sku
|
|
}
|
|
})
|
|
|
|
return {
|
|
id: item.id!,
|
|
variationId: primaryVariation.id!,
|
|
name: itemData.name || "Unnamed Product",
|
|
description: itemData.description || "",
|
|
price: price ? Number(price.amount) / 100 : 0,
|
|
currency: price?.currency || "USD",
|
|
imageUrl: itemData.imageIds?.[0]
|
|
? `/api/square/catalog/image/${itemData.imageIds[0]}`
|
|
: "/placeholder.svg?height=400&width=400&text=Product+Image",
|
|
inventory,
|
|
category: itemData.categoryId || "uncategorized",
|
|
categoryName: categories.find(c => c.id === itemData.categoryId)?.categoryData?.name,
|
|
isAvailable: inventory > 0,
|
|
variations
|
|
}
|
|
})
|
|
|
|
console.log("Successfully processed", products.length, "products")
|
|
|
|
return Response.json({
|
|
success: true,
|
|
products,
|
|
categories: processedCategories,
|
|
message: `Found ${products.length} products and ${processedCategories.length} categories`
|
|
})
|
|
|
|
} catch (error) {
|
|
console.error("=== Square Catalog Error ===")
|
|
console.error("Error type:", error?.constructor?.name)
|
|
console.error("Error message:", error instanceof Error ? error.message : String(error))
|
|
console.error("Stack trace:", error instanceof Error ? error.stack : "No stack")
|
|
|
|
// Return detailed error information
|
|
return Response.json({
|
|
success: false,
|
|
error: error instanceof Error ? error.message : "Unknown catalog error",
|
|
details: {
|
|
type: error?.constructor?.name || "Unknown",
|
|
message: error instanceof Error ? error.message : String(error),
|
|
suggestion: "Check your Square API credentials and ensure products exist in your Square catalog"
|
|
},
|
|
products: [],
|
|
categories: []
|
|
}, { status: 500 })
|
|
}
|
|
}
|