// Stand-in for https://etrade.gov.et in the e2e stack. ETradeService's base // URL is hardcoded (apps/edr-freight-api/src/modules/companies/services/etrade.service.ts), // not env-configurable, so this is reached by aliasing this container AS // "etrade.gov.et" on the compose network (see docker-compose.e2e.yaml) rather // than by pointing an env var here. HTTPS because the real service is HTTPS // — the cert itself only needs to exist, never be trusted, since // ETradeService's httpsAgent sets rejectUnauthorized:false. The compose // service's command generates a throwaway self-signed cert into // TLS_CERT_PATH/TLS_KEY_PATH before starting this — nothing shaped like a // key/cert is committed here. // // A TIN resolves to the same canned company whatever its digits, EXCEPT for // the two failure shapes the onboarding specs need — chosen by the TIN's // leading digit so a spec picks its outcome by picking its number, with no // per-spec stubbing and no state in this process: // // 1xxxxxxxxx (default) registration + one business licence → "Verified with eTrade" // 9xxxxxxxxx registration, but `Businesses: []` → the API's resolveCompanyData // returns businessInfo: null, // so /fetch-etrade-info 400s // with "couldn't find a // business license for this // TIN". This is the real // co-operative / foreign- // investor case: the TIN is // registered, the trade // licence is not. // 8xxxxxxxxx 404 on the registration lookup → getCompanyInfoByTin throws, // same 400 to the portal by a // different route (eTrade knows // nothing about this TIN at all). // // Both failures reach the portal as a 400, which ETradeInfo renders as its // `notFound` branch: a red dead end for an ordinary company, and the blue // "that's expected" alert for one that types its registration. const https = require("node:https"); const fs = require("node:fs"); const PORT = process.env.PORT || 443; const options = { key: fs.readFileSync(process.env.TLS_KEY_PATH || "/tmp/etrade-mock/key.pem"), cert: fs.readFileSync( process.env.TLS_CERT_PATH || "/tmp/etrade-mock/cert.pem", ), }; /** No trade licence on file for this TIN (a co-operative, a foreign investor). */ const TIN_WITHOUT_LICENCE = "9"; /** eTrade holds no registration whatsoever for this TIN. */ const TIN_UNKNOWN = "8"; function companyInfo(tin) { return { Tin: tin, LegalCondtion: "Private Limited Company", RegNo: "REG-E2E-0001", RegDate: "2020-01-01", // Embeds the (per-run-unique) TIN rather than a static name — specs // that look a company up by name (e.g. onboarding.cy.ts) need this to // stay unique across repeated e2e runs against the same warm DB, same // as it would be if the customer had typed a real company name. BusinessName: `E2E Mock Trading PLC ${tin}`, BusinessNameAmh: "ኢቱኢ ሞክ ትሬዲንግ", PaidUpCapital: 100000, AssociateShortInfos: [], Businesses: [ { MainGuid: "e2e-guid-0001", OwnerTIN: tin, DateRegistered: "2020-01-01", TradeNameAmh: "ኢቱኢ", TradesName: "E2E Mock Trading", LicenceNumber: "LIC-E2E-0001", RenewalDate: "2026-01-01", RenewedFrom: "2025-01-01", RenewedTo: "2027-01-01", BusinessLicensingGroupMain: null, SubGroups: null, }, ], }; } function businessInfo(tin) { return { MainGuid: "e2e-guid-0001", OwnerTIN: tin, DateRegistered: "2020-01-01", TradeName: "E2E Mock Trading", LicenceNumber: "LIC-E2E-0001", Status: 1, StatusDescription: "Active", Capital: 100000, AssociateShortInfos: [ { Position: "Manager", ManagerName: "አበበ በቀለ", ManagerNameEng: "Abebe Bekele", Photo: null, MobilePhone: "+251911223344", RegularPhone: null, }, ], AddressInfo: { Region: "ADDIS ABABA", Zone: "Zone 1", Woreda: "Woreda 1", Kebele: "Kebele 1", HouseNo: "123", MobilePhone: "+251911223344", RegularPhone: "", }, RenewedTo: "2027-01-01", RenewedToDateString: "2027-01-01", RenewalDate: "2026-01-01", RenewedFrom: "2025-01-01", CancellationDate: null, }; } const server = https.createServer(options, (req, res) => { const url = new URL(req.url, `https://${req.headers.host}`); const regMatch = url.pathname.match( /^\/api\/Registration\/GetRegistrationInfoByTin\/([^/]+)\/en$/, ); if (req.method === "GET" && regMatch) { const tin = regMatch[1]; if (tin.startsWith(TIN_UNKNOWN)) { res.writeHead(404).end(); return; } const info = companyInfo(tin); // Registered, but holding no trade licence. The API reads `Businesses` // rather than the HTTP status to decide this, so an empty array is the // honest shape — not an error. if (tin.startsWith(TIN_WITHOUT_LICENCE)) info.Businesses = []; res.writeHead(200, { "content-type": "application/json" }); res.end(JSON.stringify(info)); return; } if ( req.method === "GET" && url.pathname === "/api/BusinessMain/GetBusinessByLicenseNo" ) { const tin = url.searchParams.get("Tin") || ""; res.writeHead(200, { "content-type": "application/json" }); res.end(JSON.stringify(businessInfo(tin))); return; } res.writeHead(404).end(); }); server.listen(PORT, () => { console.log(`etrade-mock listening on ${PORT}`); });