ADR1-3 on routes + db files
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 17m30s
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 17m30s
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// src/services/db/admin.db.ts
|
||||
import type { Pool, PoolClient } from 'pg';
|
||||
import { getPool } from './connection.db';
|
||||
import { getPool, withTransaction } from './connection.db';
|
||||
import { ForeignKeyConstraintError, NotFoundError } from './errors.db';
|
||||
import { logger } from '../logger.server';
|
||||
import { SuggestedCorrection, MostFrequentSaleItem, Recipe, RecipeComment, UnmatchedFlyerItem, ActivityLogItem, Receipt, User, AdminUserView } from '../../types';
|
||||
@@ -77,13 +77,11 @@ export class AdminRepository {
|
||||
[correctionId]
|
||||
);
|
||||
if (res.rowCount === 0) {
|
||||
// This could happen if the correction was already processed or doesn't exist.
|
||||
logger.warn(`Attempted to reject correction ID ${correctionId}, but it was not found or not in 'pending' state.`);
|
||||
// We don't throw an error here, as the end state (not pending) is achieved.
|
||||
} else {
|
||||
logger.info(`Successfully rejected correction ID: ${correctionId}`);
|
||||
throw new NotFoundError(`Correction with ID ${correctionId} not found or not in 'pending' state.`);
|
||||
}
|
||||
logger.info(`Successfully rejected correction ID: ${correctionId}`);
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) throw error;
|
||||
logger.error('Database error in rejectCorrection:', { error, correctionId });
|
||||
throw new Error('Failed to reject correction.');
|
||||
}
|
||||
@@ -308,16 +306,14 @@ export class AdminRepository {
|
||||
'UPDATE public.recipes SET status = $1 WHERE recipe_id = $2 RETURNING *',
|
||||
[status, recipeId]
|
||||
);
|
||||
if (res.rowCount === 0) {
|
||||
throw new NotFoundError(`Recipe with ID ${recipeId} not found.`);
|
||||
}
|
||||
if (res.rowCount === 0) throw new NotFoundError(`Recipe with ID ${recipeId} not found.`);
|
||||
return res.rows[0];
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) {
|
||||
throw error;
|
||||
}
|
||||
logger.error('Database error in updateRecipeStatus:', { error, recipeId, status });
|
||||
throw new Error('Failed to update recipe status.');
|
||||
throw new Error('Failed to update recipe status.'); // Keep generic for other DB errors
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,35 +324,31 @@ export class AdminRepository {
|
||||
* @param masterItemId The ID of the `master_grocery_items` to link to.
|
||||
*/
|
||||
async resolveUnmatchedFlyerItem(unmatchedFlyerItemId: number, masterItemId: number): Promise<void> {
|
||||
const client = await getPool().connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
await withTransaction(async (client) => {
|
||||
// First, get the flyer_item_id from the unmatched record
|
||||
const unmatchedRes = await client.query<{
|
||||
flyer_item_id: number;
|
||||
}>('SELECT flyer_item_id FROM public.unmatched_flyer_items WHERE unmatched_flyer_item_id = $1 FOR UPDATE', [
|
||||
unmatchedFlyerItemId,
|
||||
]);
|
||||
|
||||
// First, get the flyer_item_id from the unmatched record
|
||||
const unmatchedRes = await client.query<{ flyer_item_id: number }>(
|
||||
'SELECT flyer_item_id FROM public.unmatched_flyer_items WHERE unmatched_flyer_item_id = $1 FOR UPDATE',
|
||||
[unmatchedFlyerItemId]
|
||||
);
|
||||
if (unmatchedRes.rowCount === 0) {
|
||||
throw new NotFoundError(`Unmatched flyer item with ID ${unmatchedFlyerItemId} not found.`);
|
||||
}
|
||||
const { flyer_item_id } = unmatchedRes.rows[0];
|
||||
|
||||
if (unmatchedRes.rowCount === 0) {
|
||||
throw new NotFoundError(`Unmatched flyer item with ID ${unmatchedFlyerItemId} not found.`);
|
||||
}
|
||||
const { flyer_item_id } = unmatchedRes.rows[0];
|
||||
// Next, update the original flyer_items table with the correct master_item_id
|
||||
await client.query('UPDATE public.flyer_items SET master_item_id = $1 WHERE flyer_item_id = $2', [masterItemId, flyer_item_id]);
|
||||
|
||||
// Next, update the original flyer_items table with the correct master_item_id
|
||||
await client.query('UPDATE public.flyer_items SET master_item_id = $1 WHERE flyer_item_id = $2', [masterItemId, flyer_item_id]);
|
||||
// Finally, update the status of the unmatched record to 'resolved'
|
||||
await client.query("UPDATE public.unmatched_flyer_items SET status = 'resolved' WHERE unmatched_flyer_item_id = $1", [unmatchedFlyerItemId]);
|
||||
|
||||
// Finally, update the status of the unmatched record to 'resolved'
|
||||
await client.query("UPDATE public.unmatched_flyer_items SET status = 'resolved' WHERE unmatched_flyer_item_id = $1", [unmatchedFlyerItemId]);
|
||||
|
||||
await client.query('COMMIT');
|
||||
logger.info(`Successfully resolved unmatched item ${unmatchedFlyerItemId} to master item ${masterItemId}.`);
|
||||
logger.info(`Successfully resolved unmatched item ${unmatchedFlyerItemId} to master item ${masterItemId}.`);
|
||||
});
|
||||
} catch (error) {
|
||||
await client.query('ROLLBACK');
|
||||
logger.error('Database transaction error in resolveUnmatchedFlyerItem:', { error, unmatchedFlyerItemId, masterItemId });
|
||||
throw new Error('Failed to resolve unmatched flyer item.');
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,8 +358,12 @@ export class AdminRepository {
|
||||
*/
|
||||
async ignoreUnmatchedFlyerItem(unmatchedFlyerItemId: number): Promise<void> {
|
||||
try {
|
||||
await this.db.query("UPDATE public.unmatched_flyer_items SET status = 'ignored' WHERE unmatched_flyer_item_id = $1", [unmatchedFlyerItemId]);
|
||||
const res = await this.db.query("UPDATE public.unmatched_flyer_items SET status = 'ignored' WHERE unmatched_flyer_item_id = $1 AND status = 'pending'", [unmatchedFlyerItemId]);
|
||||
if (res.rowCount === 0) {
|
||||
throw new NotFoundError(`Unmatched flyer item with ID ${unmatchedFlyerItemId} not found or not in 'pending' state.`);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) throw error;
|
||||
logger.error('Database error in ignoreUnmatchedFlyerItem:', { error, unmatchedFlyerItemId });
|
||||
throw new Error('Failed to ignore unmatched flyer item.');
|
||||
}
|
||||
@@ -465,11 +461,15 @@ export class AdminRepository {
|
||||
// prettier-ignore
|
||||
async updateBrandLogo(brandId: number, logoUrl: string): Promise<void> {
|
||||
try {
|
||||
await this.db.query(
|
||||
const res = await this.db.query(
|
||||
'UPDATE public.brands SET logo_url = $1 WHERE brand_id = $2',
|
||||
[logoUrl, brandId]
|
||||
);
|
||||
if (res.rowCount === 0) {
|
||||
throw new NotFoundError(`Brand with ID ${brandId} not found.`);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) throw error;
|
||||
logger.error('Database error in updateBrandLogo:', { error, brandId });
|
||||
throw new Error('Failed to update brand logo in database.');
|
||||
}
|
||||
@@ -487,11 +487,10 @@ export class AdminRepository {
|
||||
`UPDATE public.receipts SET status = $1, processed_at = CASE WHEN $1 IN ('completed', 'failed') THEN now() ELSE processed_at END WHERE receipt_id = $2 RETURNING *`,
|
||||
[status, receiptId]
|
||||
);
|
||||
if (res.rowCount === 0) {
|
||||
throw new NotFoundError(`Receipt with ID ${receiptId} not found.`);
|
||||
}
|
||||
if (res.rowCount === 0) throw new NotFoundError(`Receipt with ID ${receiptId} not found.`);
|
||||
return res.rows[0];
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) throw error;
|
||||
logger.error('Database error in updateReceiptStatus:', { error, receiptId, status });
|
||||
throw new Error('Failed to update receipt status.');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user