326 lines
9.2 KiB
JavaScript
326 lines
9.2 KiB
JavaScript
/**
|
|
* 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<Object|null>} 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>} 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<Object>} 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<Object>} 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<Object>} 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<void>}
|
|
*/
|
|
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;
|
|
}
|
|
}
|