/** * Accounts Service * CRUD-Operationen für Accounts aus Appwrite * Verwaltet nur "Managed Accounts" (account_owner_user_id == authUserId) */ import { databases, databaseId, accountsCollectionId } from "../lib/appwrite"; import { ID, Query } from "appwrite"; /** * Lädt ein einzelnes Account nach ID * @param {string} accountId - ID des Accounts * @returns {Promise} Account-Dokument oder null */ export async function getAccountById(accountId) { if (!accountId) { console.warn("getAccountById: accountId fehlt"); return null; } try { const document = await databases.getDocument( databaseId, accountsCollectionId, accountId ); return document; } catch (e) { // 404 bedeutet, dass das Dokument nicht existiert if (e.code === 404 || e.type === 'document_not_found') { return null; } console.error("Fehler beim Laden des Accounts:", e); throw e; } } /** * Leitet den Market-Code aus einem Account ab * @param {Object} account - Account-Dokument * @returns {string} Market-Code (z.B. "DE", "US", "UNKNOWN") */ export function deriveMarketFromAccount(account) { if (!account) { return "UNKNOWN"; } // Priority 1: account_platform_market Feld vorhanden if (account.account_platform_market && account.account_platform_market.trim()) { return account.account_platform_market.trim().toUpperCase(); } // Priority 2: Ableitung aus account_url Hostname if (account.account_url) { try { const url = new URL(account.account_url); const hostname = url.hostname.toLowerCase(); // Mapping von Hostname zu Market-Code const hostnameToMarket = { "ebay.de": "DE", "www.ebay.de": "DE", "ebay.com": "US", "www.ebay.com": "US", "ebay.co.uk": "UK", "www.ebay.co.uk": "UK", "ebay.fr": "FR", "www.ebay.fr": "FR", "ebay.it": "IT", "www.ebay.it": "IT", "ebay.es": "ES", "www.ebay.es": "ES", "ebay.ca": "CA", "www.ebay.ca": "CA", "ebay.com.au": "AU", "www.ebay.com.au": "AU", }; if (hostnameToMarket[hostname]) { return hostnameToMarket[hostname]; } // Fallback: Prüfe ob hostname ein bekanntes Pattern enthält if (hostname.includes("ebay.de")) return "DE"; if (hostname.includes("ebay.com") && !hostname.includes("ebay.com.au")) return "US"; if (hostname.includes("ebay.co.uk")) return "UK"; if (hostname.includes("ebay.fr")) return "FR"; if (hostname.includes("ebay.it")) return "IT"; if (hostname.includes("ebay.es")) return "ES"; if (hostname.includes("ebay.ca")) return "CA"; if (hostname.includes("ebay.com.au")) return "AU"; } catch (e) { // URL parsing fehlgeschlagen console.debug("Fehler beim Parsen der Account-URL:", e); } } return "UNKNOWN"; } /** * Leitet die Währung aus einem Market-Code ab * @param {string} market - Market-Code (z.B. "DE", "US", "UK") * @returns {string} Währungscode (z.B. "EUR", "USD", "GBP") */ export function deriveCurrencyFromMarket(market) { if (!market || market === "UNKNOWN") { return "EUR"; // Fallback } const marketUpper = market.toUpperCase(); // Mapping Market -> Currency const marketToCurrency = { // EUR Länder "DE": "EUR", "FR": "EUR", "IT": "EUR", "ES": "EUR", "NL": "EUR", "AT": "EUR", "BE": "EUR", "IE": "EUR", // Andere Währungen "US": "USD", "UK": "GBP", "CA": "CAD", "AU": "AUD", }; return marketToCurrency[marketUpper] || "EUR"; // Fallback zu EUR } /** * Lädt alle Managed Accounts für einen User * @param {string} authUserId - ID des eingeloggten Users * @returns {Promise} Array von Account-Dokumenten */ export async function fetchManagedAccounts(authUserId) { if (!authUserId) { console.warn("fetchManagedAccounts: authUserId fehlt"); return []; } try { const response = await databases.listDocuments( databaseId, accountsCollectionId, [ Query.equal("account_owner_user_id", authUserId), Query.orderDesc("$createdAt"), ] ); return response.documents; } catch (e) { console.error("Fehler beim Laden der Accounts:", e); // Wenn Collection nicht existiert oder Berechtigungen fehlen if (e.code === 404 || e.code === 401) { return []; } throw e; } } /** * Erstellt ein neues Managed Account * @param {string} authUserId - ID des eingeloggten Users * @param {Object} accountData - Account-Daten * @param {string} accountData.account_platform_market - Required: Market (z.B. "DE", "US") * @param {string} accountData.account_platform_account_id - Required: Platform Account ID * @param {string} [accountData.account_shop_name] - Optional: Shop-Name * @param {string} [accountData.account_url] - Optional: Account URL * @param {string} [accountData.account_status] - Optional: Status (z.B. "active", "unknown", "disabled") * @returns {Promise} Erstelltes Account-Dokument */ export async function createManagedAccount(authUserId, accountData) { if (!authUserId) { throw new Error("authUserId ist erforderlich"); } // Validierung der Required-Felder const { account_platform_market, account_platform_account_id } = accountData; // account_platform wird IMMER "ebay" gesetzt (eBay-only Tool) if (!account_platform_market) { throw new Error("account_platform_market ist erforderlich"); } if (!account_platform_account_id) { throw new Error("account_platform_account_id ist erforderlich"); } // Payload zusammenstellen const payload = { account_owner_user_id: authUserId, account_platform: "ebay", // IMMER "ebay" für über UI erstellte Accounts account_platform_market, account_platform_account_id, account_shop_name: accountData.account_shop_name || null, account_url: accountData.account_url || null, account_sells: accountData.account_sells ?? null, // Setze account_sells wenn verfügbar }; // account_status ist optional - aufgrund Schema-Konflikt vorerst weglassen // TODO: Schema in Appwrite prüfen und korrigieren (Enum-Feld sollte String akzeptieren, nicht Array) // Das Feld wird erst wieder hinzugefügt, wenn das Schema korrekt konfiguriert ist // Document-Level Permissions für den User setzen const permissions = [ `read("user:${authUserId}")`, `update("user:${authUserId}")`, `delete("user:${authUserId}")`, ]; try { const document = await databases.createDocument( databaseId, accountsCollectionId, ID.unique(), payload, permissions ); return document; } catch (e) { // Duplicate-Conflict behandeln (falls Unique-Index auf platform+market+platform_account_id existiert) if (e.code === 409 || e.message?.includes("duplicate") || e.message?.includes("unique")) { throw new Error( "Dieser Account ist bereits verbunden." ); } console.error("Fehler beim Erstellen des Accounts:", e); throw e; } } /** * Aktualisiert ein Managed Account (optional für v1) * @param {string} accountId - ID des Accounts * @param {Object} accountData - Zu aktualisierende Account-Daten * @returns {Promise} Aktualisiertes Account-Dokument */ export async function updateManagedAccount(accountId, accountData) { if (!accountId) { throw new Error("accountId ist erforderlich"); } try { // Entferne undefined/null Werte aus accountData (behalte nur geänderte Felder) const payload = {}; Object.keys(accountData).forEach((key) => { if (accountData[key] !== undefined && accountData[key] !== null) { payload[key] = accountData[key]; } }); const document = await databases.updateDocument( databaseId, accountsCollectionId, accountId, payload ); return document; } catch (e) { console.error("Fehler beim Aktualisieren des Accounts:", e); throw e; } } /** * Aktualisiert das account_last_scan_at Feld eines Accounts * @param {string} accountId - ID des Accounts * @param {string} isoString - ISO 8601 Datum-String (z.B. "2026-01-18T12:34:56.000Z") * @returns {Promise} Aktualisiertes Account-Dokument */ export async function updateAccountLastScanAt(accountId, isoString) { if (!accountId) { throw new Error("accountId ist erforderlich"); } if (!isoString) { throw new Error("isoString ist erforderlich"); } try { const document = await databases.updateDocument( databaseId, accountsCollectionId, accountId, { account_last_scan_at: isoString, } ); return document; } catch (e) { console.error("Fehler beim Aktualisieren des account_last_scan_at:", e); throw e; } } /** * Löscht ein Managed Account (optional für v1) * @param {string} accountId - ID des Accounts * @returns {Promise} */ export async function deleteManagedAccount(accountId) { if (!accountId) { throw new Error("accountId ist erforderlich"); } try { await databases.deleteDocument( databaseId, accountsCollectionId, accountId ); } catch (e) { console.error("Fehler beim Löschen des Accounts:", e); throw e; } }