|
@@ -525,4 +525,186 @@ export async function updateImportProgress(
|
|
|
console.error('Error updating import progress:', error);
|
|
console.error('Error updating import progress:', error);
|
|
|
return { success: false, error: 'Failed to update progress' };
|
|
return { success: false, error: 'Failed to update progress' };
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Get imports filtered by layout configuration name
|
|
|
|
|
+export async function getImportsByLayoutName(layoutName: string) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // First find the layout by name
|
|
|
|
|
+ const layout = await prisma.layoutConfiguration.findFirst({
|
|
|
|
|
+ where: { name: layoutName },
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (!layout) {
|
|
|
|
|
+ return { success: true, data: [] };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const imports = await prisma.import.findMany({
|
|
|
|
|
+ where: {
|
|
|
|
|
+ layoutId: layout.id,
|
|
|
|
|
+ },
|
|
|
|
|
+ include: {
|
|
|
|
|
+ layout: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ orderBy: {
|
|
|
|
|
+ importDate: 'desc',
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return { success: true, data: imports };
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('Error fetching imports by layout:', error);
|
|
|
|
|
+ return { success: false, error: 'Failed to fetch imports' };
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TerraTech facility summary result type
|
|
|
|
|
+export interface TerraTechSummaryRow {
|
|
|
|
|
+ wellName: string | null;
|
|
|
|
|
+ corpId: string | null;
|
|
|
|
|
+ facilityId: string | null;
|
|
|
|
|
+ gas: number | null;
|
|
|
|
|
+ oil: number | null;
|
|
|
|
|
+ water: number | null;
|
|
|
|
|
+ state: string | null;
|
|
|
|
|
+ county: string | null;
|
|
|
|
|
+ daysQ1: number | null;
|
|
|
|
|
+ daysQ2: number | null;
|
|
|
|
|
+ daysQ3: number | null;
|
|
|
|
|
+ daysQ4: number | null;
|
|
|
|
|
+ daysQ1Pct: number | null;
|
|
|
|
|
+ daysQ2Pct: number | null;
|
|
|
|
|
+ daysQ3Pct: number | null;
|
|
|
|
|
+ daysQ4Pct: number | null;
|
|
|
|
|
+ gasCorr: number | null;
|
|
|
|
|
+ oilCorr: number | null;
|
|
|
|
|
+ waterCorr: number | null;
|
|
|
|
|
+ isMissingFacilityId: string | null;
|
|
|
|
|
+ isMissingCounty: string | null;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Get TerraTech facility summary for an import
|
|
|
|
|
+export async function getTerraTechFacilitySummary(importId: number) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (!importId || isNaN(importId)) {
|
|
|
|
|
+ return { success: false, error: 'Invalid import ID' };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Check if import exists
|
|
|
|
|
+ const importRecord = await prisma.import.findUnique({
|
|
|
|
|
+ where: { id: importId },
|
|
|
|
|
+ include: { layout: true }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (!importRecord) {
|
|
|
|
|
+ return { success: false, error: 'Import not found' };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Execute the complex aggregation query using raw SQL
|
|
|
|
|
+ const results = await prisma.$queryRaw<TerraTechSummaryRow[]>`
|
|
|
|
|
+ SELECT
|
|
|
|
|
+ s.well_name AS "wellName",
|
|
|
|
|
+ s."corpId" AS "corpId",
|
|
|
|
|
+ gfi.odeq_fac_id AS "facilityId",
|
|
|
|
|
+ CAST(SUM(CAST(s.gas_production AS DECIMAL)) AS DECIMAL(10,2)) AS "gas",
|
|
|
|
|
+ CAST(SUM(CAST(s.oil_production AS DECIMAL)) AS DECIMAL(10,2)) AS "oil",
|
|
|
|
|
+ CAST(SUM(CAST(s.water_production AS DECIMAL)) AS DECIMAL(10,2)) AS "water",
|
|
|
|
|
+ s.state AS "state",
|
|
|
|
|
+ cr.county_parish AS "county",
|
|
|
|
|
+ SUM(CASE WHEN q."Quarter" = 1 THEN q."DaysInMonth" ELSE 0 END) AS "daysQ1",
|
|
|
|
|
+ SUM(CASE WHEN q."Quarter" = 2 THEN q."DaysInMonth" ELSE 0 END) AS "daysQ2",
|
|
|
|
|
+ SUM(CASE WHEN q."Quarter" = 3 THEN q."DaysInMonth" ELSE 0 END) AS "daysQ3",
|
|
|
|
|
+ SUM(CASE WHEN q."Quarter" = 4 THEN q."DaysInMonth" ELSE 0 END) AS "daysQ4",
|
|
|
|
|
+ CAST(
|
|
|
|
|
+ (SUM(CASE WHEN q."Quarter" = 1 THEN q."DaysInMonth" ELSE 0 END)::DECIMAL /
|
|
|
|
|
+ CASE WHEN (EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 4 = 0
|
|
|
|
|
+ AND (EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 100 != 0
|
|
|
|
|
+ OR EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 400 = 0))
|
|
|
|
|
+ THEN 366 ELSE 365 END * 100)
|
|
|
|
|
+ AS DECIMAL(5,1)
|
|
|
|
|
+ ) AS "daysQ1Pct",
|
|
|
|
|
+ CAST(
|
|
|
|
|
+ (SUM(CASE WHEN q."Quarter" = 2 THEN q."DaysInMonth" ELSE 0 END)::DECIMAL /
|
|
|
|
|
+ CASE WHEN (EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 4 = 0
|
|
|
|
|
+ AND (EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 100 != 0
|
|
|
|
|
+ OR EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 400 = 0))
|
|
|
|
|
+ THEN 366 ELSE 365 END * 100)
|
|
|
|
|
+ AS DECIMAL(5,1)
|
|
|
|
|
+ ) AS "daysQ2Pct",
|
|
|
|
|
+ CAST(
|
|
|
|
|
+ (SUM(CASE WHEN q."Quarter" = 3 THEN q."DaysInMonth" ELSE 0 END)::DECIMAL /
|
|
|
|
|
+ CASE WHEN (EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 4 = 0
|
|
|
|
|
+ AND (EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 100 != 0
|
|
|
|
|
+ OR EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 400 = 0))
|
|
|
|
|
+ THEN 366 ELSE 365 END * 100)
|
|
|
|
|
+ AS DECIMAL(5,1)
|
|
|
|
|
+ ) AS "daysQ3Pct",
|
|
|
|
|
+ CAST(
|
|
|
|
|
+ (SUM(CASE WHEN q."Quarter" = 4 THEN q."DaysInMonth" ELSE 0 END)::DECIMAL /
|
|
|
|
|
+ CASE WHEN (EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 4 = 0
|
|
|
|
|
+ AND (EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 100 != 0
|
|
|
|
|
+ OR EXTRACT(YEAR FROM NOW() AT TIME ZONE 'America/Detroit')::INT % 400 = 0))
|
|
|
|
|
+ THEN 366 ELSE 365 END * 100)
|
|
|
|
|
+ AS DECIMAL(5,1)
|
|
|
|
|
+ ) AS "daysQ4Pct",
|
|
|
|
|
+ CAST(CASE WHEN SUM(CAST(s.gas_production AS DECIMAL)) < 0 THEN 0 ELSE SUM(CAST(s.gas_production AS DECIMAL)) END AS DECIMAL(10,2)) AS "gasCorr",
|
|
|
|
|
+ CAST(CASE WHEN SUM(CAST(s.oil_production AS DECIMAL)) < 0 THEN 0 ELSE SUM(CAST(s.oil_production AS DECIMAL)) END AS DECIMAL(10,2)) AS "oilCorr",
|
|
|
|
|
+ CAST(CASE WHEN SUM(CAST(s.water_production AS DECIMAL)) < 0 THEN 0 ELSE SUM(CAST(s.water_production AS DECIMAL)) END AS DECIMAL(10,2)) AS "waterCorr",
|
|
|
|
|
+ CASE WHEN gfi.odeq_fac_id IS NULL THEN 'Yes' ELSE NULL END AS "isMissingFacilityId",
|
|
|
|
|
+ CASE WHEN cr.county_parish IS NULL THEN 'Yes' ELSE NULL END AS "isMissingCounty"
|
|
|
|
|
+ FROM gow_data s
|
|
|
|
|
+ INNER JOIN LATERAL (
|
|
|
|
|
+ SELECT
|
|
|
|
|
+ DATE_PART('quarter', s.month::DATE) AS "Quarter",
|
|
|
|
|
+ DATE_PART('days',
|
|
|
|
|
+ DATE_TRUNC('month', s.month::DATE)
|
|
|
|
|
+ + '1 MONTH'::INTERVAL
|
|
|
|
|
+ - '1 DAY'::INTERVAL
|
|
|
|
|
+ ) AS "DaysInMonth"
|
|
|
|
|
+ ) q ON TRUE
|
|
|
|
|
+ LEFT JOIN gow_fac_id gfi ON s."corpId" = gfi.corp_id AND gfi."importId" = s."importId"
|
|
|
|
|
+ LEFT JOIN gow_corp_ref cr ON cr.corporate_id = s."corpId" AND cr."importId" = s."importId"
|
|
|
|
|
+ WHERE s."importId" = ${importId}
|
|
|
|
|
+ GROUP BY s.well_name, s."corpId", gfi.odeq_fac_id, s.state, cr.county_parish
|
|
|
|
|
+ ORDER BY s.well_name
|
|
|
|
|
+ `;
|
|
|
|
|
+
|
|
|
|
|
+ // Serialize Decimal objects to plain numbers for client components
|
|
|
|
|
+ const serializedRows = results.map(row => ({
|
|
|
|
|
+ wellName: row.wellName,
|
|
|
|
|
+ corpId: row.corpId,
|
|
|
|
|
+ facilityId: row.facilityId,
|
|
|
|
|
+ gas: row.gas !== null ? Number(row.gas) : null,
|
|
|
|
|
+ oil: row.oil !== null ? Number(row.oil) : null,
|
|
|
|
|
+ water: row.water !== null ? Number(row.water) : null,
|
|
|
|
|
+ state: row.state,
|
|
|
|
|
+ county: row.county,
|
|
|
|
|
+ daysQ1: row.daysQ1 !== null ? Number(row.daysQ1) : null,
|
|
|
|
|
+ daysQ2: row.daysQ2 !== null ? Number(row.daysQ2) : null,
|
|
|
|
|
+ daysQ3: row.daysQ3 !== null ? Number(row.daysQ3) : null,
|
|
|
|
|
+ daysQ4: row.daysQ4 !== null ? Number(row.daysQ4) : null,
|
|
|
|
|
+ daysQ1Pct: row.daysQ1Pct !== null ? Number(row.daysQ1Pct) : null,
|
|
|
|
|
+ daysQ2Pct: row.daysQ2Pct !== null ? Number(row.daysQ2Pct) : null,
|
|
|
|
|
+ daysQ3Pct: row.daysQ3Pct !== null ? Number(row.daysQ3Pct) : null,
|
|
|
|
|
+ daysQ4Pct: row.daysQ4Pct !== null ? Number(row.daysQ4Pct) : null,
|
|
|
|
|
+ gasCorr: row.gasCorr !== null ? Number(row.gasCorr) : null,
|
|
|
|
|
+ oilCorr: row.oilCorr !== null ? Number(row.oilCorr) : null,
|
|
|
|
|
+ waterCorr: row.waterCorr !== null ? Number(row.waterCorr) : null,
|
|
|
|
|
+ isMissingFacilityId: row.isMissingFacilityId,
|
|
|
|
|
+ isMissingCounty: row.isMissingCounty,
|
|
|
|
|
+ }));
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ success: true,
|
|
|
|
|
+ data: {
|
|
|
|
|
+ importId,
|
|
|
|
|
+ importName: importRecord.name,
|
|
|
|
|
+ layoutName: importRecord.layout.name,
|
|
|
|
|
+ rows: serializedRows
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('Error fetching TerraTech facility summary:', error);
|
|
|
|
|
+ return { success: false, error: 'Failed to fetch facility summary' };
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|