import product catalogue
This commit is contained in:
147
setup-stock-trigger.js
Normal file
147
setup-stock-trigger.js
Normal file
@@ -0,0 +1,147 @@
|
||||
import dotenv from 'dotenv';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
// Load .env variables
|
||||
const envPath = path.resolve(process.cwd(), '.env');
|
||||
if (fs.existsSync(envPath)) {
|
||||
dotenv.config({ path: envPath });
|
||||
}
|
||||
|
||||
const HASURA_ADMIN_SECRET = process.env.HASURA_ADMIN_SECRET || 'nearle-admin-secret';
|
||||
const HASURA_QUERY_URL = 'https://api.workolik.com/v2/query';
|
||||
const HASURA_METADATA_URL = 'https://api.workolik.com/v1/metadata';
|
||||
|
||||
let sourceName = 'default';
|
||||
|
||||
async function getSourceName() {
|
||||
const response = await fetch(HASURA_METADATA_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-hasura-admin-secret': HASURA_ADMIN_SECRET,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'export_metadata',
|
||||
args: {}
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
throw new Error(`Hasura Metadata Error: ${data.error}`);
|
||||
}
|
||||
|
||||
if (data.sources && data.sources.length > 0) {
|
||||
return data.sources[0].name;
|
||||
}
|
||||
return 'default';
|
||||
}
|
||||
|
||||
async function runSql(sqlQuery) {
|
||||
const response = await fetch(HASURA_QUERY_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-hasura-admin-secret': HASURA_ADMIN_SECRET,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'run_sql',
|
||||
args: {
|
||||
source: sourceName,
|
||||
sql: sqlQuery,
|
||||
cascade: false,
|
||||
check_metadata_consistency: false,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
throw new Error(`Hasura SQL Error: ${data.error}`);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('🔄 Connecting to Hasura Database...');
|
||||
sourceName = await getSourceName();
|
||||
console.log(`✅ Using database source: "${sourceName}"`);
|
||||
|
||||
// 1. Let's introspect the tables to ensure we have the correct table names before running the trigger.
|
||||
const targetTables = ['orders', 'orderdetails', 'productstocks'];
|
||||
const columnsCheckSql = `
|
||||
SELECT table_name, column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name IN ('orders', 'orderdetails', 'productstocks');
|
||||
`;
|
||||
|
||||
console.log('🔍 Introspecting columns for orders, orderdetails, productstocks...');
|
||||
const colData = await runSql(columnsCheckSql);
|
||||
const cols = colData.result.slice(1);
|
||||
|
||||
const getCols = (table) => cols.filter(r => r[0] === table).map(r => r[1]);
|
||||
const ordersCols = getCols('orders');
|
||||
const orderDetailsCols = getCols('orderdetails');
|
||||
const productStockCols = getCols('productstocks');
|
||||
|
||||
console.log(`✅ orders columns: ${ordersCols.join(', ')}`);
|
||||
console.log(`✅ orderdetails columns: ${orderDetailsCols.join(', ')}`);
|
||||
console.log(`✅ productstocks columns: ${productStockCols.join(', ')}`);
|
||||
|
||||
// Determine exact column names
|
||||
const orderPk = ordersCols.includes('orderheaderid') ? 'orderheaderid' : 'orderid';
|
||||
const detailOrderId = orderDetailsCols.includes('orderheaderid') ? 'orderheaderid' : 'orderid';
|
||||
const qtyCol = orderDetailsCols.includes('qty') ? 'qty' : 'orderqty';
|
||||
const stockCol = productStockCols.includes('physicalstock') ? 'physicalstock' : (productStockCols.includes('closing') ? 'closing' : 'stock');
|
||||
|
||||
// 2. Define the SQL for the Trigger Functions
|
||||
console.log('🛠️ Creating trigger functions...');
|
||||
|
||||
const createTriggerSql = `
|
||||
-- Function to reduce stock when a new order detail is inserted
|
||||
CREATE OR REPLACE FUNCTION update_stock_on_order_insert()
|
||||
RETURNS trigger AS $$
|
||||
DECLARE
|
||||
v_locationid INT;
|
||||
BEGIN
|
||||
-- Try to fetch locationid from orders
|
||||
BEGIN
|
||||
SELECT locationid INTO v_locationid FROM orders WHERE ${orderPk} = NEW.${detailOrderId};
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
v_locationid := NULL;
|
||||
END;
|
||||
|
||||
IF v_locationid IS NOT NULL THEN
|
||||
UPDATE productstocks
|
||||
SET ${stockCol} = GREATEST(0, COALESCE(${stockCol}, 0) - COALESCE(NEW.${qtyCol}, 1))
|
||||
WHERE productid = NEW.productid AND locationid = v_locationid;
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Create the trigger on orderdetails table
|
||||
DROP TRIGGER IF EXISTS trigger_reduce_stock_on_order ON orderdetails;
|
||||
CREATE TRIGGER trigger_reduce_stock_on_order
|
||||
AFTER INSERT ON orderdetails
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_stock_on_order_insert();
|
||||
`;
|
||||
|
||||
console.log('Deploying trigger...');
|
||||
await runSql(createTriggerSql);
|
||||
console.log('✅ Stock Reduction Trigger successfully deployed!');
|
||||
|
||||
console.log('🎉 Setup complete. The database will now automatically reduce physicalstock when an order is created.');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error executing deployment script:');
|
||||
console.error(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user