270 lines
9.4 KiB
JavaScript
270 lines
9.4 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const { Client } = require('ssh2');
|
|
const mysql = require('mysql2/promise');
|
|
|
|
// Helper function to setup SSH tunnel
|
|
async function setupSshTunnel() {
|
|
const sshConfig = {
|
|
host: process.env.PROD_SSH_HOST,
|
|
port: process.env.PROD_SSH_PORT || 22,
|
|
username: process.env.PROD_SSH_USER,
|
|
privateKey: process.env.PROD_SSH_KEY_PATH
|
|
? require('fs').readFileSync(process.env.PROD_SSH_KEY_PATH)
|
|
: undefined,
|
|
compress: true
|
|
};
|
|
|
|
const dbConfig = {
|
|
host: process.env.PROD_DB_HOST || 'localhost',
|
|
user: process.env.PROD_DB_USER,
|
|
password: process.env.PROD_DB_PASSWORD,
|
|
database: process.env.PROD_DB_NAME,
|
|
port: process.env.PROD_DB_PORT || 3306,
|
|
timezone: 'Z'
|
|
};
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const ssh = new Client();
|
|
|
|
ssh.on('error', (err) => {
|
|
console.error('SSH connection error:', err);
|
|
reject(err);
|
|
});
|
|
|
|
ssh.on('ready', () => {
|
|
ssh.forwardOut(
|
|
'127.0.0.1',
|
|
0,
|
|
dbConfig.host,
|
|
dbConfig.port,
|
|
(err, stream) => {
|
|
if (err) reject(err);
|
|
resolve({ ssh, stream, dbConfig });
|
|
}
|
|
);
|
|
}).connect(sshConfig);
|
|
});
|
|
}
|
|
|
|
// Get all options for import fields
|
|
router.get('/field-options', async (req, res) => {
|
|
let ssh;
|
|
let connection;
|
|
|
|
try {
|
|
// Setup SSH tunnel and get database connection
|
|
const tunnel = await setupSshTunnel();
|
|
ssh = tunnel.ssh;
|
|
|
|
// Create MySQL connection over SSH tunnel
|
|
connection = await mysql.createConnection({
|
|
...tunnel.dbConfig,
|
|
stream: tunnel.stream
|
|
});
|
|
|
|
// Fetch companies (type 1)
|
|
const [companies] = await connection.query(`
|
|
SELECT cat_id, name
|
|
FROM product_categories
|
|
WHERE type = 1
|
|
ORDER BY name
|
|
`);
|
|
|
|
// Fetch artists (type 40)
|
|
const [artists] = await connection.query(`
|
|
SELECT cat_id, name
|
|
FROM product_categories
|
|
WHERE type = 40
|
|
ORDER BY name
|
|
`);
|
|
|
|
// Fetch sizes (type 50)
|
|
const [sizes] = await connection.query(`
|
|
SELECT cat_id, name
|
|
FROM product_categories
|
|
WHERE type = 50
|
|
ORDER BY name
|
|
`);
|
|
|
|
// Fetch themes with subthemes
|
|
const [themes] = await connection.query(`
|
|
SELECT t.cat_id, t.name AS display_name, t.type, t.name AS sort_theme,
|
|
'' AS sort_subtheme, 1 AS level_order
|
|
FROM product_categories t
|
|
WHERE t.type = 20
|
|
UNION ALL
|
|
SELECT ts.cat_id, CONCAT(t.name,' - ',ts.name) AS display_name, ts.type,
|
|
t.name AS sort_theme, ts.name AS sort_subtheme, 2 AS level_order
|
|
FROM product_categories ts
|
|
JOIN product_categories t ON ts.master_cat_id = t.cat_id
|
|
WHERE ts.type = 21 AND t.type = 20
|
|
ORDER BY sort_theme, sort_subtheme
|
|
`);
|
|
|
|
// Fetch categories with all levels
|
|
const [categories] = await connection.query(`
|
|
SELECT s.cat_id, s.name AS display_name, s.type, s.name AS sort_section,
|
|
'' AS sort_category, '' AS sort_subcategory, '' AS sort_subsubcategory,
|
|
1 AS level_order
|
|
FROM product_categories s
|
|
WHERE s.type = 10
|
|
UNION ALL
|
|
SELECT c.cat_id, CONCAT(s.name,' - ',c.name) AS display_name, c.type,
|
|
s.name AS sort_section, c.name AS sort_category, '' AS sort_subcategory,
|
|
'' AS sort_subsubcategory, 2 AS level_order
|
|
FROM product_categories c
|
|
JOIN product_categories s ON c.master_cat_id = s.cat_id
|
|
WHERE c.type = 11 AND s.type = 10
|
|
UNION ALL
|
|
SELECT sc.cat_id, CONCAT(s.name,' - ',c.name,' - ',sc.name) AS display_name,
|
|
sc.type, s.name AS sort_section, c.name AS sort_category,
|
|
sc.name AS sort_subcategory, '' AS sort_subsubcategory, 3 AS level_order
|
|
FROM product_categories sc
|
|
JOIN product_categories c ON sc.master_cat_id = c.cat_id
|
|
JOIN product_categories s ON c.master_cat_id = s.cat_id
|
|
WHERE sc.type = 12 AND c.type = 11 AND s.type = 10
|
|
UNION ALL
|
|
SELECT ssc.cat_id, CONCAT(s.name,' - ',c.name,' - ',sc.name,' - ',ssc.name) AS display_name,
|
|
ssc.type, s.name AS sort_section, c.name AS sort_category,
|
|
sc.name AS sort_subcategory, ssc.name AS sort_subsubcategory, 4 AS level_order
|
|
FROM product_categories ssc
|
|
JOIN product_categories sc ON ssc.master_cat_id = sc.cat_id
|
|
JOIN product_categories c ON sc.master_cat_id = c.cat_id
|
|
JOIN product_categories s ON c.master_cat_id = s.cat_id
|
|
WHERE ssc.type = 13 AND sc.type = 12 AND c.type = 11 AND s.type = 10
|
|
ORDER BY sort_section, sort_category, sort_subcategory, sort_subsubcategory
|
|
`);
|
|
|
|
// Fetch colors
|
|
const [colors] = await connection.query(`
|
|
SELECT color, name, hex_color
|
|
FROM product_color_list
|
|
ORDER BY \`order\`
|
|
`);
|
|
|
|
// Fetch suppliers
|
|
const [suppliers] = await connection.query(`
|
|
SELECT supplierid as value, companyname as label
|
|
FROM suppliers
|
|
WHERE companyname <> ''
|
|
ORDER BY companyname
|
|
`);
|
|
|
|
// Fetch tax categories
|
|
const [taxCategories] = await connection.query(`
|
|
SELECT tax_code_id as value, name as label
|
|
FROM product_tax_codes
|
|
ORDER BY tax_code_id = 0 DESC, name
|
|
`);
|
|
|
|
res.json({
|
|
companies: companies.map(c => ({ label: c.name, value: c.cat_id.toString() })),
|
|
artists: artists.map(a => ({ label: a.name, value: a.cat_id.toString() })),
|
|
sizes: sizes.map(s => ({ label: s.name, value: s.cat_id.toString() })),
|
|
themes: themes.map(t => ({
|
|
label: t.display_name,
|
|
value: t.cat_id.toString(),
|
|
type: t.type,
|
|
level: t.level_order
|
|
})),
|
|
categories: categories.map(c => ({
|
|
label: c.display_name,
|
|
value: c.cat_id.toString(),
|
|
type: c.type,
|
|
level: c.level_order
|
|
})),
|
|
colors: colors.map(c => ({
|
|
label: c.name,
|
|
value: c.color,
|
|
hexColor: c.hex_color
|
|
})),
|
|
suppliers: suppliers,
|
|
taxCategories: taxCategories,
|
|
shippingRestrictions: [
|
|
{ label: "None", value: "0" },
|
|
{ label: "US Only", value: "1" },
|
|
{ label: "Limited Quantity", value: "2" },
|
|
{ label: "US/CA Only", value: "3" },
|
|
{ label: "No FedEx 2 Day", value: "4" },
|
|
{ label: "North America Only", value: "5" }
|
|
]
|
|
});
|
|
} catch (error) {
|
|
console.error('Error fetching import field options:', error);
|
|
res.status(500).json({ error: 'Failed to fetch import field options' });
|
|
} finally {
|
|
if (connection) await connection.end();
|
|
if (ssh) ssh.end();
|
|
}
|
|
});
|
|
|
|
// Get product lines for a specific company
|
|
router.get('/product-lines/:companyId', async (req, res) => {
|
|
let ssh;
|
|
let connection;
|
|
|
|
try {
|
|
// Setup SSH tunnel and get database connection
|
|
const tunnel = await setupSshTunnel();
|
|
ssh = tunnel.ssh;
|
|
|
|
// Create MySQL connection over SSH tunnel
|
|
connection = await mysql.createConnection({
|
|
...tunnel.dbConfig,
|
|
stream: tunnel.stream
|
|
});
|
|
|
|
const [lines] = await connection.query(`
|
|
SELECT cat_id as value, name as label
|
|
FROM product_categories
|
|
WHERE type = 2
|
|
AND master_cat_id = ?
|
|
ORDER BY name
|
|
`, [req.params.companyId]);
|
|
|
|
res.json(lines.map(l => ({ label: l.label, value: l.value.toString() })));
|
|
} catch (error) {
|
|
console.error('Error fetching product lines:', error);
|
|
res.status(500).json({ error: 'Failed to fetch product lines' });
|
|
} finally {
|
|
if (connection) await connection.end();
|
|
if (ssh) ssh.end();
|
|
}
|
|
});
|
|
|
|
// Get sublines for a specific product line
|
|
router.get('/sublines/:lineId', async (req, res) => {
|
|
let ssh;
|
|
let connection;
|
|
|
|
try {
|
|
// Setup SSH tunnel and get database connection
|
|
const tunnel = await setupSshTunnel();
|
|
ssh = tunnel.ssh;
|
|
|
|
// Create MySQL connection over SSH tunnel
|
|
connection = await mysql.createConnection({
|
|
...tunnel.dbConfig,
|
|
stream: tunnel.stream
|
|
});
|
|
|
|
const [sublines] = await connection.query(`
|
|
SELECT cat_id as value, name as label
|
|
FROM product_categories
|
|
WHERE type = 3
|
|
AND master_cat_id = ?
|
|
ORDER BY name
|
|
`, [req.params.lineId]);
|
|
|
|
res.json(sublines.map(s => ({ label: s.label, value: s.value.toString() })));
|
|
} catch (error) {
|
|
console.error('Error fetching sublines:', error);
|
|
res.status(500).json({ error: 'Failed to fetch sublines' });
|
|
} finally {
|
|
if (connection) await connection.end();
|
|
if (ssh) ssh.end();
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|