Spaces:
Runtime error
Runtime error
Bansari Akhani commited on
Commit ·
9d33d07
1
Parent(s): aee85dc
#8641 - sync workorders from json url, remove sync from PW api
Browse files- .env.example +2 -1
- src/config/app.config.ts +7 -0
- src/controllers/propertyware/workorders.controller.ts +4 -3
- src/shared/interfaces/pwWorkOrdersInterface.ts +14 -1
- src/shared/services/cronJobs.ts +2 -2
- src/shared/services/propertyware.service.ts +19 -3
- src/shared/services/units.service.ts +2 -2
- src/shared/services/workorder.service.ts +62 -2
.env.example
CHANGED
|
@@ -36,4 +36,5 @@ SMTP_SENDER_EMAIL=
|
|
| 36 |
FRONTEND_URL=
|
| 37 |
|
| 38 |
CRON_SCHEDULE="0 0 * * *"
|
| 39 |
-
SYNC_INVOICES=true
|
|
|
|
|
|
| 36 |
FRONTEND_URL=
|
| 37 |
|
| 38 |
CRON_SCHEDULE="0 0 * * *"
|
| 39 |
+
SYNC_INVOICES=true
|
| 40 |
+
PW_FETCH_ALL_WORKORDERS=
|
src/config/app.config.ts
CHANGED
|
@@ -23,3 +23,10 @@ export const SMTP_CONFIG = {
|
|
| 23 |
SECURE: process.env.SMTP_SECURE,
|
| 24 |
SENDER: process.env.SMTP_SENDER_EMAIL,
|
| 25 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
SECURE: process.env.SMTP_SECURE,
|
| 24 |
SENDER: process.env.SMTP_SENDER_EMAIL,
|
| 25 |
};
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
export const PW_CONFIG= {
|
| 29 |
+
PW_FETCH_ALL_UNITS:process.env.PW_FETCH_ALL_UNITS || '',
|
| 30 |
+
PW_FETCH_ALL_WORKORDERS:process.env.PW_FETCH_ALL_WORKORDERS || '',
|
| 31 |
+
PW_FETCH_LATEST_WORKORDERS:process.env.PW_FETCH_LATEST_WORKORDERS || ''
|
| 32 |
+
};
|
src/controllers/propertyware/workorders.controller.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
import { Request, Response } from 'express';
|
| 2 |
import { logger } from '../../utils/logger';
|
| 3 |
-
import { syncWorkOrderDataService } from '../../shared/services/workorder.service';
|
| 4 |
import PwWorkOrders from '../../models/pwWorkOrders';
|
| 5 |
|
| 6 |
export const fetchWorkorders = async (req: Request, res: Response) => {
|
|
@@ -27,9 +27,10 @@ export const fetchWorkorders = async (req: Request, res: Response) => {
|
|
| 27 |
|
| 28 |
export const syncWorkOrders = async (req: Request, res: Response) => {
|
| 29 |
try {
|
| 30 |
-
const
|
|
|
|
| 31 |
res.status(200).send(result);
|
| 32 |
} catch (error) {
|
| 33 |
res.status(500).send((error as Error).message);
|
| 34 |
}
|
| 35 |
-
};
|
|
|
|
| 1 |
import { Request, Response } from 'express';
|
| 2 |
import { logger } from '../../utils/logger';
|
| 3 |
+
import { syncWorkOrderDataFromJsonService, syncWorkOrderDataService } from '../../shared/services/workorder.service';
|
| 4 |
import PwWorkOrders from '../../models/pwWorkOrders';
|
| 5 |
|
| 6 |
export const fetchWorkorders = async (req: Request, res: Response) => {
|
|
|
|
| 27 |
|
| 28 |
export const syncWorkOrders = async (req: Request, res: Response) => {
|
| 29 |
try {
|
| 30 |
+
const syncAll = true;
|
| 31 |
+
const result = await syncWorkOrderDataFromJsonService(syncAll);
|
| 32 |
res.status(200).send(result);
|
| 33 |
} catch (error) {
|
| 34 |
res.status(500).send((error as Error).message);
|
| 35 |
}
|
| 36 |
+
};
|
src/shared/interfaces/pwWorkOrdersInterface.ts
CHANGED
|
@@ -8,4 +8,17 @@ export interface PwWorkOrdersInterface {
|
|
| 8 |
unit_id: number;
|
| 9 |
status: string;
|
| 10 |
assigned_vendors: string[];
|
| 11 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
unit_id: number;
|
| 9 |
status: string;
|
| 10 |
assigned_vendors: string[];
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
export interface Column {
|
| 14 |
+
index: string;
|
| 15 |
+
dataType: string;
|
| 16 |
+
label: string;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
export interface DataStructure {
|
| 20 |
+
totalCount: number;
|
| 21 |
+
columns: Column[];
|
| 22 |
+
records: any[];
|
| 23 |
+
}
|
| 24 |
+
|
src/shared/services/cronJobs.ts
CHANGED
|
@@ -2,7 +2,7 @@ import cron from 'node-cron';
|
|
| 2 |
import { logger } from '../../utils/logger';
|
| 3 |
import { syncInvoicesService } from './bills.service';
|
| 4 |
import { syncUnitsDataFromUrlService } from './units.service';
|
| 5 |
-
import {
|
| 6 |
|
| 7 |
const CRON_SCHEDULE = process.env.CRON_SCHEDULE || '0 0 * * *';
|
| 8 |
const SYNC_INVOICES = process.env.SYNC_INVOICES;
|
|
@@ -28,7 +28,7 @@ export const setupCronJobs = () => {
|
|
| 28 |
await syncUnitsDataFromUrlService();
|
| 29 |
logger.info('Scheduled properties sync completed successfully');
|
| 30 |
|
| 31 |
-
await
|
| 32 |
logger.info('Scheduled work order sync completed successfully');
|
| 33 |
|
| 34 |
if (SYNC_INVOICES === "true") {
|
|
|
|
| 2 |
import { logger } from '../../utils/logger';
|
| 3 |
import { syncInvoicesService } from './bills.service';
|
| 4 |
import { syncUnitsDataFromUrlService } from './units.service';
|
| 5 |
+
import { syncWorkOrderDataFromJsonService } from './workorder.service';
|
| 6 |
|
| 7 |
const CRON_SCHEDULE = process.env.CRON_SCHEDULE || '0 0 * * *';
|
| 8 |
const SYNC_INVOICES = process.env.SYNC_INVOICES;
|
|
|
|
| 28 |
await syncUnitsDataFromUrlService();
|
| 29 |
logger.info('Scheduled properties sync completed successfully');
|
| 30 |
|
| 31 |
+
await syncWorkOrderDataFromJsonService();
|
| 32 |
logger.info('Scheduled work order sync completed successfully');
|
| 33 |
|
| 34 |
if (SYNC_INVOICES === "true") {
|
src/shared/services/propertyware.service.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
|
|
|
|
|
| 1 |
import { apiClientPW } from "./api.service";
|
| 2 |
import axios from 'axios';
|
| 3 |
|
|
@@ -81,9 +83,23 @@ export const fetchAllWorkorders = async () => {
|
|
| 81 |
};
|
| 82 |
|
| 83 |
|
| 84 |
-
export const fetchUnitsJson = async (
|
| 85 |
-
const
|
| 86 |
-
const response = await axios.get(url);
|
| 87 |
return response.data;
|
| 88 |
};
|
| 89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { Column, DataStructure } from "shared/interfaces/pwWorkOrdersInterface";
|
| 2 |
+
import { PW_CONFIG } from "../../config/app.config";
|
| 3 |
import { apiClientPW } from "./api.service";
|
| 4 |
import axios from 'axios';
|
| 5 |
|
|
|
|
| 83 |
};
|
| 84 |
|
| 85 |
|
| 86 |
+
export const fetchUnitsJson = async () => {
|
| 87 |
+
const response = await axios.get(PW_CONFIG.PW_FETCH_ALL_UNITS);
|
|
|
|
| 88 |
return response.data;
|
| 89 |
};
|
| 90 |
|
| 91 |
+
export const fetchAllWorkordersJson = async () => {
|
| 92 |
+
const response = await axios.get(PW_CONFIG.PW_FETCH_ALL_WORKORDERS);
|
| 93 |
+
return response.data;
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
export const fetchLatestWorkordersJson = async () => {
|
| 97 |
+
const response = await axios.get(PW_CONFIG.PW_FETCH_LATEST_WORKORDERS);
|
| 98 |
+
return response.data;
|
| 99 |
+
};
|
| 100 |
+
|
| 101 |
+
export const getIndexByLabel = (data: Column[], label: string): number | undefined => {
|
| 102 |
+
const column = data.find((col) => col.label === label);
|
| 103 |
+
return column ? parseInt(column.index) : undefined;
|
| 104 |
+
};
|
| 105 |
+
|
src/shared/services/units.service.ts
CHANGED
|
@@ -46,10 +46,10 @@ export const syncUnitsDataFromUrlService = async (): Promise<string> => {
|
|
| 46 |
});
|
| 47 |
|
| 48 |
unitsBulkData.push({
|
| 49 |
-
pw_id: record['
|
| 50 |
name: record['1'], // Unit Name
|
| 51 |
pw_portfolio_id: record['10'], // Portfolio ID
|
| 52 |
-
pw_building_id: record['7'], // Building ID
|
| 53 |
});
|
| 54 |
}
|
| 55 |
|
|
|
|
| 46 |
});
|
| 47 |
|
| 48 |
unitsBulkData.push({
|
| 49 |
+
pw_id: record['9'], // Unit Entity ID
|
| 50 |
name: record['1'], // Unit Name
|
| 51 |
pw_portfolio_id: record['10'], // Portfolio ID
|
| 52 |
+
pw_building_id: record['7'], // Building ID Number
|
| 53 |
});
|
| 54 |
}
|
| 55 |
|
src/shared/services/workorder.service.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
-
import { fetchAllWorkorders, } from './propertyware.service';
|
| 2 |
import { logger } from '../../utils/logger';
|
| 3 |
import PwWorkOrders from '../../models/pwWorkOrders';
|
|
|
|
| 4 |
|
| 5 |
export const syncWorkOrderDataService = async (): Promise<string> => {
|
| 6 |
try {
|
|
@@ -35,4 +36,63 @@ export const syncWorkOrderDataService = async (): Promise<string> => {
|
|
| 35 |
logger.error("Error syncing Work order: ", error);
|
| 36 |
throw new Error("Error syncing Work order");
|
| 37 |
}
|
| 38 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { fetchAllWorkorders, fetchAllWorkordersJson, fetchLatestWorkordersJson, getIndexByLabel } from './propertyware.service';
|
| 2 |
import { logger } from '../../utils/logger';
|
| 3 |
import PwWorkOrders from '../../models/pwWorkOrders';
|
| 4 |
+
import PwUnit from '../../models/pwUnits';
|
| 5 |
|
| 6 |
export const syncWorkOrderDataService = async (): Promise<string> => {
|
| 7 |
try {
|
|
|
|
| 36 |
logger.error("Error syncing Work order: ", error);
|
| 37 |
throw new Error("Error syncing Work order");
|
| 38 |
}
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
export const syncWorkOrderDataFromJsonService = async (syncAll = false): Promise<string> => {
|
| 42 |
+
try {
|
| 43 |
+
let workOrderData;
|
| 44 |
+
if (syncAll) {
|
| 45 |
+
workOrderData = await fetchAllWorkordersJson();
|
| 46 |
+
} else {
|
| 47 |
+
workOrderData = await fetchLatestWorkordersJson();
|
| 48 |
+
}
|
| 49 |
+
const indexes = {
|
| 50 |
+
pw_id: getIndexByLabel(workOrderData.columns, "WO Entity ID"),
|
| 51 |
+
number:getIndexByLabel(workOrderData.columns, "WO#"),
|
| 52 |
+
portfolio: getIndexByLabel(workOrderData.columns, "Portfolio"),
|
| 53 |
+
building: getIndexByLabel(workOrderData.columns, "Building"),
|
| 54 |
+
unit: getIndexByLabel(workOrderData.columns, "Unit"),
|
| 55 |
+
buildingID: getIndexByLabel(workOrderData.columns, "Building ID"),
|
| 56 |
+
unitID: getIndexByLabel(workOrderData.columns, "Unit ID"),
|
| 57 |
+
status: getIndexByLabel(workOrderData.columns, "Status"),
|
| 58 |
+
assignedVendors: getIndexByLabel(workOrderData.columns, "Vendors"),
|
| 59 |
+
};
|
| 60 |
+
const workOrderResponseData: any[] = [];
|
| 61 |
+
|
| 62 |
+
for (const record of workOrderData.records) {
|
| 63 |
+
const portfolioData = await PwUnit.findOne({
|
| 64 |
+
where: {
|
| 65 |
+
pw_id: record[indexes.unitID as number],
|
| 66 |
+
},
|
| 67 |
+
attributes: ['pw_portfolio_id'],
|
| 68 |
+
});
|
| 69 |
+
|
| 70 |
+
const portfolio_id= portfolioData ? portfolioData.getDataValue('pw_portfolio_id') : null;
|
| 71 |
+
workOrderResponseData.push({
|
| 72 |
+
pw_id: record[indexes.pw_id as number],
|
| 73 |
+
number: extractWorkOrderNumber(record[indexes.number as number]),
|
| 74 |
+
portfolio_id: portfolio_id,
|
| 75 |
+
building_id: record[indexes.buildingID as number],
|
| 76 |
+
unit_id: record[indexes.unitID as number],
|
| 77 |
+
location: record[indexes.portfolio as number] + " " + record[indexes.building as number] + " " + record[indexes.unit as number],
|
| 78 |
+
status: record[indexes.status as number],
|
| 79 |
+
assigned_vendors: record[indexes.assignedVendors as number] || []
|
| 80 |
+
});
|
| 81 |
+
}
|
| 82 |
+
await PwWorkOrders.bulkCreate(workOrderResponseData, {
|
| 83 |
+
updateOnDuplicate: ['number', 'location', 'portfolio_id', 'building_id', 'unit_id', 'status', 'assigned_vendors'],
|
| 84 |
+
});
|
| 85 |
+
|
| 86 |
+
logger.info("Total " + workOrderResponseData.length + "Work orders synced successfully");
|
| 87 |
+
return "Total " + workOrderResponseData.length + "Work orders synced successfully";
|
| 88 |
+
} catch (error) {
|
| 89 |
+
console.log(error);
|
| 90 |
+
logger.error("Error syncing Work order: ", error);
|
| 91 |
+
throw new Error("Error syncing Work order");
|
| 92 |
+
}
|
| 93 |
+
};
|
| 94 |
+
|
| 95 |
+
const extractWorkOrderNumber = (workOrder: string): string | null => {
|
| 96 |
+
const match = workOrder.match(/#(\d+)/); // Matches "#" followed by one or more digits
|
| 97 |
+
return match ? match[1] : null;
|
| 98 |
+
}
|