farmcontrol-api/src/services/sales/marketplaces.js

377 lines
11 KiB
JavaScript

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 });
}
};