import config from '../../config.js'; import { marketplaceModel } from '../../database/schemas/sales/marketplace.schema.js'; import log4js from 'log4js'; import mongoose from 'mongoose'; import { deleteObject, listObjects, getObject, editObject, newObject, listObjectsByProperties, getModelStats, getModelHistory, searchObjects } from '../../database/database.js'; import * as marketplaceIntegration from '../../integrations/marketplaceworker.js'; const logger = log4js.getLogger('Marketplaces'); logger.level = config.server.logLevel; export const listMarketplacesRouteHandler = async ( req, res, page = 1, limit = 25, property = '', filter = {}, search = '', sort = '', order = 'ascend' ) => { const result = await listObjects({ model: marketplaceModel, page, limit, property, filter, search, sort, order, }); if (result?.error) { logger.error('Error listing marketplaces.'); res.status(result.code).send(result); return; } logger.debug(`List of marketplaces (Page ${page}, Limit ${limit}). Count: ${result.length}.`); res.send(result); }; export const listMarketplacesByPropertiesRouteHandler = async ( req, res, properties = '', filter = {}, masterFilter = {} ) => { const result = await listObjectsByProperties({ model: marketplaceModel, properties, filter, masterFilter, }); if (result?.error) { logger.error('Error listing marketplaces.'); res.status(result.code).send(result); return; } logger.debug(`List of marketplaces. Count: ${result.length}`); res.send(result); }; export const searchMarketplacesRouteHandler = async (req, res, search) => { const result = await searchObjects({ model: marketplaceModel, search, }); res.send(result); }; export const getMarketplaceRouteHandler = async (req, res) => { const id = req.params.id; const result = await getObject({ model: marketplaceModel, id, }); if (result?.error) { logger.warn(`Marketplace not found with supplied id.`); return res.status(result.code).send(result); } logger.debug(`Retrieved marketplace with ID: ${id}`); res.send(result); }; export const editMarketplaceRouteHandler = async (req, res) => { const id = new mongoose.Types.ObjectId(req.params.id); logger.trace(`Marketplace with ID: ${id}`); const updateData = { updatedAt: new Date(), name: req.body.name, provider: req.body.provider, active: req.body.active, config: req.body.config || {}, }; const result = await editObject({ model: marketplaceModel, id, updateData, user: req.user, }); if (result.error) { logger.error('Error editing marketplace:', result.error); res.status(result.code).send(result); return; } logger.debug(`Edited marketplace with ID: ${id}`); res.send(result); }; export const newMarketplaceRouteHandler = async (req, res) => { const newData = { updatedAt: new Date(), name: req.body.name, provider: req.body.provider, active: req.body.active !== false, connected: req.body.connected === true, state: req.body.state || { type: req.body.active ? 'disconnected' : 'inactive' }, config: req.body.config || {}, }; const result = await newObject({ model: marketplaceModel, newData, user: req.user, }); if (result.error) { logger.error('No marketplace created:', result.error); return res.status(result.code).send(result); } logger.debug(`New marketplace with ID: ${result._id}`); res.send(result); }; export const deleteMarketplaceRouteHandler = async (req, res) => { const id = new mongoose.Types.ObjectId(req.params.id); logger.trace(`Marketplace with ID: ${id}`); const result = await deleteObject({ model: marketplaceModel, id, user: req.user, }); if (result.error) { logger.error('No marketplace deleted:', result.error); return res.status(result.code).send(result); } logger.debug(`Deleted marketplace with ID: ${result._id}`); res.send(result); }; export const getMarketplaceStatsRouteHandler = async (req, res) => { const result = await getModelStats({ model: marketplaceModel }); if (result?.error) { logger.error('Error fetching marketplace stats:', result.error); return res.status(result.code).send(result); } logger.trace('Marketplace stats:', result); res.send(result); }; export const getMarketplaceHistoryRouteHandler = async (req, res) => { const from = req.query.from; const to = req.query.to; const result = await getModelHistory({ model: marketplaceModel, from, to }); if (result?.error) { logger.error('Error fetching marketplace history:', result.error); return res.status(result.code).send(result); } logger.trace('Marketplace history:', result); res.send(result); }; export const getMarketplaceAuthUrlRouteHandler = async (req, res) => { const id = req.params.id; const marketplace = await getObject({ model: marketplaceModel, id }); if (marketplace?.error) { logger.warn('Marketplace not found for authorization URL request.'); return res.status(marketplace.code).send(marketplace); } if (!marketplaceIntegration.hasIntegration(marketplace.provider)) { return res.status(400).send({ error: `No integration available for provider: ${marketplace.provider}`, code: 400, }); } if (!marketplaceIntegration.canAuthorize(marketplace)) { return res.status(400).send({ error: `Provider ${marketplace.provider} does not support marketplace authorization.`, code: 400, }); } try { const url = marketplaceIntegration.getAuthorizationUrl(marketplace, { state: req.query.state, }); res.send({ success: true, url }); } catch (err) { logger.error('Error generating marketplace authorization URL:', err.message); res.status(400).send({ error: err.message, code: 400 }); } }; export const exchangeMarketplaceAuthCodeRouteHandler = async (req, res) => { const id = req.params.id; const { code, state } = req.body; const marketplace = await getObject({ model: marketplaceModel, id }); if (marketplace?.error) { logger.warn('Marketplace not found for authorization exchange.'); return res.status(marketplace.code).send(marketplace); } if (!marketplaceIntegration.hasIntegration(marketplace.provider)) { return res.status(400).send({ error: `No integration available for provider: ${marketplace.provider}`, code: 400, }); } try { const result = await marketplaceIntegration.exchangeAuthorizationCode(marketplace, req.user, { code, state, }); logger.info(`Marketplace authorization completed for ${marketplace.name}`); res.send({ success: true, ...result }); } catch (err) { logger.error('Error exchanging marketplace authorization code:', err.message); res.status(400).send({ error: err.message, code: 400 }); } }; export const refreshMarketplaceAuthRouteHandler = async (req, res) => { const id = req.params.id; const marketplace = await getObject({ model: marketplaceModel, id }); if (marketplace?.error) { logger.warn('Marketplace not found for token refresh.'); return res.status(marketplace.code).send(marketplace); } if (!marketplaceIntegration.hasIntegration(marketplace.provider)) { return res.status(400).send({ error: `No integration available for provider: ${marketplace.provider}`, code: 400, }); } try { const result = await marketplaceIntegration.refreshMarketplaceAuth(marketplace, req.user); logger.info(`Marketplace token refreshed for ${marketplace.name}`); res.send({ success: true, ...result }); } catch (err) { logger.error('Error refreshing marketplace token:', err.message); res.status(400).send({ error: err.message, code: 400 }); } }; export const syncMarketplaceItemsRouteHandler = async (req, res) => { const id = req.params.id; const marketplace = await getObject({ model: marketplaceModel, id }); if (marketplace?.error) { logger.warn('Marketplace not found for sync.'); return res.status(marketplace.code).send(marketplace); } if (!marketplace.active) { return res.status(400).send({ error: 'Marketplace is not active.', code: 400 }); } if (!marketplaceIntegration.hasIntegration(marketplace.provider)) { return res.status(400).send({ error: `No integration available for provider: ${marketplace.provider}`, code: 400, }); } marketplaceIntegration.syncItems(marketplace, req.user); logger.info(`Item sync initiated in background for marketplace ${marketplace.name}`); res.send({ success: true, message: 'Item sync started' }); }; export const syncMarketplaceOrdersRouteHandler = async (req, res) => { const id = req.params.id; const { startTime, endTime } = req.query; const marketplace = await getObject({ model: marketplaceModel, id }); if (marketplace?.error) { logger.warn('Marketplace not found for order sync.'); return res.status(marketplace.code).send(marketplace); } if (!marketplace.active) { return res.status(400).send({ error: 'Marketplace is not active.', code: 400 }); } if (!marketplaceIntegration.hasIntegration(marketplace.provider)) { return res.status(400).send({ error: `No integration available for provider: ${marketplace.provider}`, code: 400, }); } marketplaceIntegration.syncOrders(marketplace, req.user, { startTime: startTime ? parseInt(startTime) : undefined, endTime: endTime ? parseInt(endTime) : undefined, }); logger.info(`Order sync initiated in background for marketplace ${marketplace.name}`); res.send({ success: true, message: 'Order sync started' }); }; export const marketplaceWebhookRouteHandler = async (req, res) => { const id = req.params.id; const marketplace = await getObject({ model: marketplaceModel, id }); if (marketplace?.error) { logger.warn('Marketplace not found for webhook.'); return res.status(404).send({ error: 'Marketplace not found.', code: 404 }); } if (!marketplaceIntegration.hasIntegration(marketplace.provider)) { return res.status(400).send({ error: `No integration available for provider: ${marketplace.provider}`, code: 400, }); } const signature = req.headers['x-tts-signature'] || req.headers['x-ebay-signature'] || req.headers['x-signature'] || ''; const rawBody = JSON.stringify(req.body); if (signature && marketplaceIntegration.canVerifyWebhookSignature(marketplace)) { const valid = marketplaceIntegration.verifyWebhookSignature(marketplace, rawBody, signature); if (!valid) { logger.warn(`Invalid webhook signature for marketplace ${marketplace.name}`); return res.status(401).send({ error: 'Invalid signature.', code: 401 }); } } try { const result = await marketplaceIntegration.handleWebhook(marketplace, req.body); logger.info(`Webhook processed for marketplace ${marketplace.name}: ${result.action}`); res.send({ success: true, ...result }); } catch (err) { logger.error('Error processing marketplace webhook:', err.message); res.status(500).send({ error: err.message, code: 500 }); } };