- Created metrcApi.ts client for all METRC endpoints - Created MetrcDashboardPage with Overview, Plant Locations, Audit tabs - Shows demo mode banner when METRC API not connected - CSV export for manual METRC upload - Plant location table with sync status - Audit trail with location change history - Added METRC to navigation under Compliance section
145 lines
3.7 KiB
TypeScript
145 lines
3.7 KiB
TypeScript
import api from './api';
|
|
|
|
// METRC Location report entry
|
|
export interface MetrcLocation {
|
|
plantId: string;
|
|
tagNumber: string;
|
|
metrcTag?: string;
|
|
location: string;
|
|
room: string;
|
|
section?: string;
|
|
position?: string;
|
|
}
|
|
|
|
// METRC Discrepancy
|
|
export interface MetrcDiscrepancy {
|
|
plantId: string;
|
|
tagNumber: string;
|
|
type: 'MISSING_IN_METRC' | 'MISSING_LOCALLY' | 'LOCATION_MISMATCH' | 'STATUS_MISMATCH';
|
|
internalValue?: string;
|
|
metrcValue?: string;
|
|
severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
|
}
|
|
|
|
// Report response
|
|
export interface MetrcReportResponse {
|
|
generatedAt: string;
|
|
plantCount: number;
|
|
plants: MetrcLocation[];
|
|
}
|
|
|
|
// Discrepancy check response
|
|
export interface MetrcDiscrepancyResponse {
|
|
checkedAt: string;
|
|
totalDiscrepancies: number;
|
|
critical: number;
|
|
high: number;
|
|
medium: number;
|
|
low: number;
|
|
discrepancies: MetrcDiscrepancy[];
|
|
}
|
|
|
|
// Sync response
|
|
export interface MetrcSyncResponse {
|
|
success: boolean;
|
|
synced?: number;
|
|
errorCount?: number;
|
|
errors?: string[];
|
|
message?: string;
|
|
}
|
|
|
|
// Audit response
|
|
export interface MetrcAuditResponse {
|
|
generatedAt: string;
|
|
dateRange: {
|
|
start: string;
|
|
end: string;
|
|
};
|
|
summary: {
|
|
totalPlants: number;
|
|
totalMoves: number;
|
|
uniquePlantsMoved: number;
|
|
};
|
|
currentLocations: MetrcLocation[];
|
|
recentMoves: {
|
|
plantTag: string;
|
|
from: string;
|
|
to: string;
|
|
movedAt: string;
|
|
reason?: string;
|
|
}[];
|
|
}
|
|
|
|
export const metrcApi = {
|
|
/**
|
|
* Get METRC location report for all plants
|
|
*/
|
|
async getReport(propertyId?: string): Promise<MetrcReportResponse> {
|
|
const response = await api.get('/metrc/report', {
|
|
params: propertyId ? { propertyId } : undefined
|
|
});
|
|
return response.data;
|
|
},
|
|
|
|
/**
|
|
* Check for discrepancies between local data and METRC
|
|
*/
|
|
async checkDiscrepancies(metrcData: any[]): Promise<MetrcDiscrepancyResponse> {
|
|
const response = await api.post('/metrc/discrepancies', { metrcData });
|
|
return response.data;
|
|
},
|
|
|
|
/**
|
|
* Sync a single plant to METRC
|
|
*/
|
|
async syncPlant(plantId: string): Promise<MetrcSyncResponse> {
|
|
const response = await api.post(`/metrc/sync/${plantId}`);
|
|
return response.data;
|
|
},
|
|
|
|
/**
|
|
* Bulk sync all plants to METRC
|
|
*/
|
|
async syncAll(propertyId?: string): Promise<MetrcSyncResponse> {
|
|
const response = await api.post('/metrc/sync-all', { propertyId });
|
|
return response.data;
|
|
},
|
|
|
|
/**
|
|
* Export CSV for manual METRC upload
|
|
*/
|
|
async exportCsv(propertyId?: string): Promise<string> {
|
|
const response = await api.get('/metrc/export/csv', {
|
|
params: propertyId ? { propertyId } : undefined,
|
|
responseType: 'text'
|
|
});
|
|
return response.data;
|
|
},
|
|
|
|
/**
|
|
* Get audit report for compliance
|
|
*/
|
|
async getAuditReport(params?: {
|
|
propertyId?: string;
|
|
startDate?: string;
|
|
endDate?: string;
|
|
}): Promise<MetrcAuditResponse> {
|
|
const response = await api.get('/metrc/audit', { params });
|
|
return response.data;
|
|
},
|
|
|
|
/**
|
|
* Download CSV file
|
|
*/
|
|
downloadCsv(csvContent: string, filename?: string) {
|
|
const blob = new Blob([csvContent], { type: 'text/csv' });
|
|
const url = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename || `metrc-export-${new Date().toISOString().split('T')[0]}.csv`;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
window.URL.revokeObjectURL(url);
|
|
}
|
|
};
|