Skip to main content

LLD: Fetch Transformer Detail API

1. Overview

Returns the full detail of a single transformer centre (TC) for a given month. Used to populate the TC Detail view on the AI Audit page — including billing health breakdown, revenue parameters, meter readings, and GPS coordinates (fields excluded from the list API).


2. Endpoint

RouteMethod
GET /audit/transformers/:idGET

Single route for all user types. Behaviour is determined from request.user.userType:

  • AE — auto-scoped to their section (validates TC belongs to section)
  • Admin (CIO / SUPER_ADMIN) — can query any TC

3. Request

3.1 Headers

HeaderRequiredDescription
AuthorizationYesBearer <sessionToken>

3.2 Path Parameters

ParamTypeRequiredDescription
idstringYesThe id field of the transformer document

3.3 Query Parameters

ParamTypeRequiredDefaultDescription
monthstringNoCurrent month (YYYY-MM)Month to fetch TC detail for

4. Response

4.1 Success (200)

{
"success": true,
"message": "Transformer detail fetched successfully",
"data": {
"transformer": {
"id": "tc-uuid-001",
"number": "TC856896541556325623",
"name": "TC856896541556325623...",
"month": "2026-01",
"tcCapacity": 100,
"meterConstant": 1,
"readingDay": 15,
"readingMR": "MR-001",
"totalInstallationSanctionedLoad": 450,
"gpsCoordinates": {
"latitude": 12.8765,
"longitude": 74.8421
},
"reading": {
"initialValue": 1000,
"finalValue": 4010
},
"installationCount": 753,
"untaggedInstallationCount": 5,
"tcConsumption": 3010,
"installationConsumption": 1650,
"lossPercentage": 20,
"previousMonthLossPercentage": 15,
"previousToPreviousMonthLossPercentage": 25,
"auditStatus": "AUDITED",
"auditedByAI": true,
"remark": null,
"overloaded": true,
"billingCount": {
"unbilled": 10,
"mnr": 5,
"vacant": 3,
"zeroConsumption": 8,
"doorlock": 2,
"abnormal": 1,
"subnormal": 4,
"billCancellation": 0
},
"revenueParams": {
"arr": 500000,
"atc": 450000,
"demand": 480000,
"collection": 460000,
"billingEfficiency": 96,
"collectionEfficiency": 92
},
"location": {
"sectionCode": "SEC-001",
"sectionName": "Section 1",
"subDivisionCode": "SD-001",
"subDivisionName": "Sub Division 1",
"divisionCode": "DIV-001",
"divisionName": "Division 1",
"circleCode": "CIR-001",
"circleName": "Circle 1",
"zoneCode": "ZN-001",
"zoneName": "Zone 1"
}
}
}
}

4.2 Not Found (404)

{
"success": false,
"message": "Transformer not found"
}

4.3 Forbidden (403)

When AE requests a TC outside their section:

{
"success": false,
"message": "TC does not belong to your assigned section"
}

5. Business Logic

5.1 Default Month

IF month not provided:
month = current date formatted as "YYYY-MM"

5.2 Fetch Transformer

const transformer = await transformerModel
.findOne({ id: tcId, month }, { _id: 0, __v: 0, createdAt: 0, updatedAt: 0 })
.lean();

if (!transformer) {
return 404"Transformer not found";
}

5.3 AE Section Validation

Verify the TC belongs to the user's section after fetching the transformer:

IF userType === "AE":
1. Fetch user doc from `users` collection using request.user.userId
2. Extract user.location.sectionCode
3. Verify transformer.location.sectionCode === user.location.sectionCode
4. If mismatch → 403 Forbidden

For Admin users: no section validation.

5.4 Projection

Return all fields except internal Mongoose fields:

const projection = {
_id: 0,
__v: 0,
createdAt: 0,
updatedAt: 0,
activatedOn: 0,
deletedOn: 0,
auditedOn: 0,
};

Fields returned:

  • Identity: id, number, name, month
  • TC properties: tcCapacity, meterConstant, readingDay, readingMR, totalInstallationSanctionedLoad
  • GPS: gpsCoordinates (latitude, longitude) — Note: DB stores GeoJSON format ({ type: "Point", coordinates: [longitude, latitude] }). The API transforms this to { latitude, longitude } in the response.
  • Meter readings: reading (initialValue, finalValue)
  • Counts: installationCount, untaggedInstallationCount
  • Audit data: tcConsumption, installationConsumption, lossPercentage, previousMonthLossPercentage, previousToPreviousMonthLossPercentage
  • Status: auditStatus, auditedByAI, remark, overloaded
  • Billing breakdown: billingCount (all 8 categories)
  • Revenue: revenueParams (all 6 fields)
  • Location: all 10 fields

6. Validation Schema (AJV)

6.1 Path Parameters Schema

{
type: "object",
properties: {
id: {
type: "string",
transform: ["trim"],
}
},
required: ["id"]
}

6.2 Query String Schema

{
type: "object",
properties: {
month: {
type: "string",
pattern: "^\\d{4}-(0[1-9]|1[0-2])$",
errorMessage: { pattern: "month must be in YYYY-MM format" }
}
},
additionalProperties: false
}

6.3 Response Serialization

{
"2xx": responseSerializer("2xx", {
type: "object",
properties: {
transformer: {
type: "object",
properties: {
id: { type: "string" },
number: { type: "string" },
name: { type: "string" },
month: { type: "string" },
tcCapacity: { type: ["number", "null"] },
meterConstant: { type: ["number", "null"] },
readingDay: { type: ["number", "null"] },
readingMR: { type: ["string", "null"] },
totalInstallationSanctionedLoad: { type: ["number", "null"] },
gpsCoordinates: {
type: "object",
properties: {
latitude: { type: ["number", "null"] },
longitude: { type: ["number", "null"] }
}
},
reading: {
type: "object",
properties: {
initialValue: { type: ["number", "null"] },
finalValue: { type: ["number", "null"] }
}
},
installationCount: { type: ["number", "null"] },
untaggedInstallationCount: { type: ["number", "null"] },
tcConsumption: { type: ["number", "null"] },
installationConsumption: { type: ["number", "null"] },
lossPercentage: { type: ["number", "null"] },
previousMonthLossPercentage: { type: ["number", "null"] },
previousToPreviousMonthLossPercentage: { type: ["number", "null"] },
auditStatus: { type: ["string", "null"] },
auditedByAI: { type: "boolean" },
remark: { type: ["string", "null"] },
overloaded: { type: "boolean" },
billingCount: {
type: "object",
properties: {
unbilled: { type: "number" },
mnr: { type: "number" },
vacant: { type: "number" },
zeroConsumption: { type: "number" },
doorlock: { type: "number" },
abnormal: { type: "number" },
subnormal: { type: "number" },
billCancellation: { type: "number" }
}
},
revenueParams: {
type: "object",
properties: {
arr: { type: ["number", "null"] },
atc: { type: ["number", "null"] },
demand: { type: ["number", "null"] },
collection: { type: ["number", "null"] },
billingEfficiency: { type: ["number", "null"] },
collectionEfficiency: { type: ["number", "null"] }
}
},
location: {
type: "object",
properties: {
sectionCode: { type: "string" },
sectionName: { type: "string" },
subDivisionCode: { type: "string" },
subDivisionName: { type: "string" },
divisionCode: { type: "string" },
divisionName: { type: "string" },
circleCode: { type: "string" },
circleName: { type: "string" },
zoneCode: { type: "string" },
zoneName: { type: "string" }
}
}
}
}
}
}),
"4xx": responseSerializer("4xx"),
"5xx": responseSerializer("5xx")
}

7. Route Config

{
routeId: "fetchTransformerDetail",
authentication: {
// No excludeFrom — requires full auth
},
authorization: {
resource: "transformer",
action: "view",
id: "idNotApplicable"
}
}

8. File Structure

api/src/entities/audit/
audit.route.v1.js — Route definitions
controller/
fetchAuditSummary.js — Existing
fetchTransformers.js — Existing
fetchInstallations.js — Existing
fetchTransformerDetail.js — Handler, schema, config exports
helpers/
resolveLocationFilter.js — Existing (reused for AE section lookup)

9. Error Handling

ScenarioStatusError Type
Invalid month format400ValidationError (AJV)
Invalid/expired session401UnauthorizedError
AE accessing TC outside their section403ForbiddenError
TC not found for given id + month404NotFoundError
AE user doc not found500DatabaseError
DB connection failure500DatabaseError

10. Performance Notes

  • Single findOne query — no pagination, no count. This is the simplest handler in the audit module.
  • Index used: { id: 1, month: 1 } — not a defined index. If querying by id + month is slow, add a compound index { id: 1, month: 1 }.
  • AE users require one extra DB call (user lookup via resolveLocationFilter) — same as other audit APIs.
  • No aggregation needed — all fields are pre-computed and stored on the transformer document.