feat: écriture de l'ID Shopify en col A du Sheets après création produit
Utilise un compte de service Google avec JWT pour authentifier les écritures dans le Sheets — sans dépendance npm supplémentaire (crypto natif Node.js). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { NextRequest } from 'next/server'
|
||||
import { getServerSession } from 'next-auth'
|
||||
import { authOptions } from '@/lib/auth'
|
||||
import { fetchPendingProducts } from '@/lib/creationSheets'
|
||||
import { fetchPendingProducts, writeShopifyIdToSheet } from '@/lib/creationSheets'
|
||||
import { generateDescriptions } from '@/lib/openaiClient'
|
||||
import { ensureMetafieldDefinition, setProductMetafield } from '@/lib/shopifyMetafields'
|
||||
import { addProductToCollection } from '@/lib/shopifyCollections'
|
||||
@@ -92,6 +92,7 @@ export async function POST(req: NextRequest) {
|
||||
await prisma.productCreation.create({
|
||||
data: { userId, sheetTab: product.tab, sheetRow: product.rowNumber, shopifyId, sku: product.sku, title: product.title, status: 'success' },
|
||||
})
|
||||
await writeShopifyIdToSheet(product.tab, product.rowNumber, shopifyId)
|
||||
created++
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : 'Erreur inconnue'
|
||||
|
||||
@@ -80,6 +80,53 @@ export function parseTabRows(tab: string, headers: string[], rows: string[][], d
|
||||
.filter((p): p is PendingProduct => p !== null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Écrit l'ID Shopify en colonne A de la ligne correspondante dans Google Sheets.
|
||||
* Utilise un compte de service avec accès éditeur sur la feuille.
|
||||
*/
|
||||
export async function writeShopifyIdToSheet(tab: string, rowNumber: number, shopifyId: string): Promise<void> {
|
||||
const sheetId = process.env.GOOGLE_SHEETS_ID
|
||||
const email = process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL
|
||||
const rawKey = process.env.GOOGLE_SERVICE_ACCOUNT_KEY
|
||||
if (!sheetId || !email || !rawKey) return
|
||||
|
||||
// Génère un JWT pour l'authentification Google
|
||||
const privateKey = rawKey.replace(/\\n/g, '\n')
|
||||
const now = Math.floor(Date.now() / 1000)
|
||||
const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url')
|
||||
const payload = Buffer.from(JSON.stringify({
|
||||
iss: email,
|
||||
scope: 'https://www.googleapis.com/auth/spreadsheets',
|
||||
aud: 'https://oauth2.googleapis.com/token',
|
||||
iat: now,
|
||||
exp: now + 3600,
|
||||
})).toString('base64url')
|
||||
|
||||
const { createSign } = await import('crypto')
|
||||
const sign = createSign('RSA-SHA256')
|
||||
sign.update(`${header}.${payload}`)
|
||||
const signature = sign.sign(privateKey, 'base64url')
|
||||
const jwt = `${header}.${payload}.${signature}`
|
||||
|
||||
const tokenRes = await fetch('https://oauth2.googleapis.com/token', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion: jwt }),
|
||||
})
|
||||
if (!tokenRes.ok) return
|
||||
const { access_token } = await tokenRes.json() as { access_token: string }
|
||||
|
||||
const range = encodeURIComponent(`${tab}!A${rowNumber}`)
|
||||
await fetch(
|
||||
`https://sheets.googleapis.com/v4/spreadsheets/${sheetId}/values/${range}?valueInputOption=RAW`,
|
||||
{
|
||||
method: 'PUT',
|
||||
headers: { Authorization: `Bearer ${access_token}`, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ range: `${tab}!A${rowNumber}`, majorDimension: 'ROWS', values: [[shopifyId]] }),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export async function fetchPendingProducts(
|
||||
alreadyCreatedRows: Set<string>,
|
||||
tabFilter?: string,
|
||||
|
||||
Reference in New Issue
Block a user