40346-vm/backend/src/db/migrations/20260629030000-add-reviewflow-payment-webhooks.js
2026-06-29 03:58:56 +00:00

113 lines
3.5 KiB
JavaScript

'use strict';
const businessColumns = {
stripe_webhook_token: { type: 'TEXT' },
square_account_reference: { type: 'TEXT' },
square_connected: { type: 'BOOLEAN', defaultValue: false, allowNull: false },
square_connected_at: { type: 'DATE' },
square_webhook_token: { type: 'TEXT' },
paypal_merchant_reference: { type: 'TEXT' },
paypal_connected: { type: 'BOOLEAN', defaultValue: false, allowNull: false },
paypal_connected_at: { type: 'DATE' },
paypal_webhook_token: { type: 'TEXT' },
};
const customerColumns = {
square_customer_reference: { type: 'TEXT' },
paypal_customer_reference: { type: 'TEXT' },
};
const transactionColumns = {
businessId: { type: 'UUID', references: { model: 'businesses', key: 'id' } },
payment_provider: { type: 'TEXT' },
square_payment_reference: { type: 'TEXT' },
paypal_payment_reference: { type: 'TEXT' },
provider_event_reference: { type: 'TEXT' },
};
const eventColumns = {
provider: { type: 'TEXT' },
provider_event_type: { type: 'TEXT' },
};
function normalizeColumnDefinition(Sequelize, definition) {
const normalized = { ...definition };
if (definition.type === 'TEXT') {
normalized.type = Sequelize.DataTypes.TEXT;
}
if (definition.type === 'BOOLEAN') {
normalized.type = Sequelize.DataTypes.BOOLEAN;
}
if (definition.type === 'DATE') {
normalized.type = Sequelize.DataTypes.DATE;
}
if (definition.type === 'UUID') {
normalized.type = Sequelize.DataTypes.UUID;
}
return normalized;
}
async function addColumnsIfMissing(queryInterface, Sequelize, transaction, tableName, columns) {
const table = await queryInterface.describeTable(tableName);
for (const [columnName, definition] of Object.entries(columns)) {
if (!table[columnName]) {
await queryInterface.addColumn(
tableName,
columnName,
normalizeColumnDefinition(Sequelize, definition),
{ transaction },
);
}
}
}
async function removeColumnsIfPresent(queryInterface, transaction, tableName, columns) {
const table = await queryInterface.describeTable(tableName);
for (const columnName of Object.keys(columns).reverse()) {
if (table[columnName]) {
await queryInterface.removeColumn(tableName, columnName, { transaction });
}
}
}
module.exports = {
async up(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
await addColumnsIfMissing(queryInterface, Sequelize, transaction, 'businesses', businessColumns);
await addColumnsIfMissing(queryInterface, Sequelize, transaction, 'customers', customerColumns);
await addColumnsIfMissing(queryInterface, Sequelize, transaction, 'transactions', transactionColumns);
await addColumnsIfMissing(queryInterface, Sequelize, transaction, 'stripe_events', eventColumns);
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
},
async down(queryInterface) {
const transaction = await queryInterface.sequelize.transaction();
try {
await removeColumnsIfPresent(queryInterface, transaction, 'stripe_events', eventColumns);
await removeColumnsIfPresent(queryInterface, transaction, 'transactions', transactionColumns);
await removeColumnsIfPresent(queryInterface, transaction, 'customers', customerColumns);
await removeColumnsIfPresent(queryInterface, transaction, 'businesses', businessColumns);
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
},
};