Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions broker/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DEVELOPMENT=1
FHIR_URL_BASE=http://fhir-dstu2-nprogram.azurewebsites.net/

# TimeTap API config
#
TIMETAP_APIKEY=12345678
TIMETAP_SECRETKEY=12345wertyfghjkyt
TIMETAP_BASEURL=https://api.timetap.com/test
4 changes: 4 additions & 0 deletions broker/endpoints/Patient.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const RelatedPerson = require("../models/RelatedPerson");
const {body, param, validationResult, sanitizeBody} = require('express-validator');
const Appointment = require("../models/Appointment");
const uuid = require('uuid');
const tt_service = require('../services/timetapService');

exports.read = [

Expand Down Expand Up @@ -249,6 +250,9 @@ async function createPatient(patient) {
const createdPatient = await axios.post(`/Patient`, resource);
patientID.resourceId = createdPatient.data.id;

// Create the new Patient/Client record in TimeTap
await tt_service.createTimetapClient(createdPatient.data);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be wrapping all this in a try/catch or a Transaction type logic so that if either our FHIR write or the TimeTap write fails, then we can throw an error back to front end without creating random orphaned records?


// Mock Appointment resource
const appointment = {
status: "booked",
Expand Down
97 changes: 97 additions & 0 deletions broker/services/timetapService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
require("dotenv").config({ path: `${__dirname}/../.env` });
const { body, param, validationResult, sanitizeBody } = require("express-validator");
const crypto = require("crypto");

const axios = require("axios");
const timetapAxios = axios.create({
baseURL: process.env.TIMETAP_BASEURL
})

let tt_sessiontoken = "";
if (tt_sessiontoken == "") {
try {
fetchTimetapSessionToken();
} catch (error) {
console.log(error);
}

}

async function fetchTimetapSessionToken() {
// Build our input values
let timestamp = Date.now();
let signature = crypto
.createHash("md5")
.update(process.env.TIMETAP_APIKEY + process.env.TIMETAP_SECRETKEY)
.digest("hex");

// Fetch the new Token
const res = await timetapAxios.get("/sessionToken", {
params: {
apiKey: process.env.TIMETAP_APIKEY,
timestamp: timestamp,
signature: signature,
},
});
tt_sessiontoken = res.data.sessionToken;
}

exports.createTimetapClient = async (patient) => {
// Create the Patient record in Timetap
let phone = "";
let email = "";
for (let i = 0; i < patient.telecom.length; i++) {
if (patient.telecom[i].system === "phone") {
phone = patient.telecom[i].value;
}
if (patient.telecom[i].system === "email") {
email = patient.telecom[i].value;
}
}

const data = {
firstName: patient.name[0].given[0],
lastName: patient.name[0].family,
fullName: `${patient.name[0].given[0]} ${patient.name[0].family}`,
emailAddress: email,
dateOfBirth: patient.birthDate,
sex: patient.gender,
address1: patient.address[0].line[0],
address2: patient.address[0].line[1],
city: patient.address[0].city,
state: patient.address[0].state,
zip: patient.address[0].postalCode,
country: patient.address[0].country,
timeZone: {},
allowWaitListText: true,
homePhone: phone,
cellPhone: phone,
clientIdsClientCanView: [],
fields: [],
locale: "en-US",
tags: [],
};

await timetapAxios
.post("/clients", data, {
headers: {
Authorization: `Bearer ${tt_sessiontoken}`,
},
})
.then((response) => {
// Success!
})
.catch(async (err) => {
// Attempt to refresh our TT token
await refreshTimetapSessionToken(this, [patient]);
});
};

async function refreshTimetapSessionToken(callback, args) {
try {
await fetchTimetapSessionToken();
await callback(...args);
} catch {
// TimeTap token refresh failed
}
}