pha-hermes 1.0.5 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.5",
2
+ "version": "1.2.0",
3
3
  "main": "dist/index.js",
4
4
  "typings": "dist/index.d.ts",
5
5
  "files": [
@@ -24,10 +24,13 @@
24
24
  }
25
25
  },
26
26
  "prettier": {
27
- "printWidth": 80,
28
- "semi": true,
29
27
  "singleQuote": true,
30
- "trailingComma": "es5"
28
+ "trailingComma": "none",
29
+ "printWidth": 100,
30
+ "semi": false,
31
+ "arrowParens": "avoid",
32
+ "bracketSpacing": true,
33
+ "tabWidth": 4
31
34
  },
32
35
  "name": "pha-hermes",
33
36
  "author": "Pierre Seguin",
@@ -52,6 +55,7 @@
52
55
  "size-limit": "^11.1.6",
53
56
  "tsdx": "^0.14.1",
54
57
  "tslib": "^2.8.1",
55
- "typescript": "^3.9.10"
58
+ "typescript": "^3.9.10",
59
+ "vitest": "^3.0.5"
56
60
  }
57
61
  }
@@ -2,7 +2,9 @@ import axios, { AxiosInstance } from 'axios'
2
2
  import { SFAuthenticator } from './auth/auth'
3
3
  import { SFTimesheetClient } from './timesheet/timesheetClient'
4
4
  import { SFPractitionerClient } from './practitioner/practitionerClient'
5
- import { Role, Workorder } from '../models'
5
+ import { Role } from '../models'
6
+ import { SFWorkorderClient } from './workorder/workorderClient'
7
+
6
8
  export const SF_API_VERSION: string = 'v57.0'
7
9
 
8
10
  export class SFApiClient {
@@ -11,6 +13,7 @@ export class SFApiClient {
11
13
  private authenticator: SFAuthenticator
12
14
  private baseUrl: string
13
15
  timesheetClient: SFTimesheetClient
16
+ workorderClient: SFWorkorderClient
14
17
  practitionerClient: SFPractitionerClient
15
18
 
16
19
  constructor(baseUrl?: string) {
@@ -19,6 +22,7 @@ export class SFApiClient {
19
22
  baseUrl ?? 'https://do0000000d247eaa--phealth.sandbox.my.salesforce.com'
20
23
  this.authenticator = new SFAuthenticator(this.axiosInstance, this.baseUrl)
21
24
  this.timesheetClient = new SFTimesheetClient(this.axiosInstance)
25
+ this.workorderClient = new SFWorkorderClient(this.axiosInstance)
22
26
  this.practitionerClient = new SFPractitionerClient(this.axiosInstance)
23
27
  }
24
28
 
@@ -34,32 +38,6 @@ export class SFApiClient {
34
38
  return this.instance
35
39
  }
36
40
 
37
- async fetchWorkOrders(assignedStaffId?: string): Promise<Workorder[]> {
38
- try {
39
- const url = `/services/data/${SF_API_VERSION}/query`
40
- const query = assignedStaffId
41
- ? `SELECT Id, HospitalID__c, HospitalName__c, ProfessionalDesignation__c FROM WorkOrder__c WHERE Personnel__c = '${assignedStaffId}'`
42
- : `SELECT Id, HospitalID__c, HospitalName__c, ProfessionalDesignation__c FROM WorkOrder__c`
43
- return await this.axiosInstance
44
- .get(url, {
45
- params: { q: query }
46
- })
47
- .then(({ data: { records } }) =>
48
- records.map(
49
- (record): Workorder => ({
50
- id: record.Id,
51
- establishmentId: record.HospitalID__c,
52
- establishmentName: record.HospitalName__c,
53
- role: record.ProfessionalDesignation__c
54
- })
55
- )
56
- )
57
- } catch (error) {
58
- console.error('Error fetching work orders: ', error.message)
59
- throw error
60
- }
61
- }
62
-
63
41
  async fetchRoles(): Promise<Role[]> {
64
42
  try {
65
43
  const url = `/services/data/${SF_API_VERSION}/query`
@@ -72,7 +50,12 @@ export class SFApiClient {
72
50
  params: { q: query }
73
51
  })
74
52
  .then(({ data: { records } }) =>
75
- records.map((record): Role => ({ label: record.Label, value: record.Value }))
53
+ records.map(
54
+ (record): Role => ({
55
+ label: record.Label,
56
+ value: record.Value
57
+ })
58
+ )
76
59
  )
77
60
  } catch (error) {
78
61
  console.error('Error fetching roles: ', error.message)
@@ -1,48 +1,48 @@
1
- import axios, { AxiosInstance } from 'axios'
2
- import FormData from 'form-data'
3
-
4
- export class SFAuthenticator {
5
- axiosTokenInstance: AxiosInstance = axios.create()
6
- authenticatedAxiosInstance: AxiosInstance
7
- token: string | undefined = undefined
8
- private refreshToken: string | undefined = undefined
9
-
10
- constructor(authenticatedAxiosInstance: AxiosInstance, baseUrl?: string) {
11
- this.axiosTokenInstance.defaults.baseURL =
12
- baseUrl ?? 'https://do0000000d247eaa--phealth.sandbox.my.salesforce.com'
13
- this.authenticatedAxiosInstance = authenticatedAxiosInstance
14
- }
15
-
16
- async initializeAuth(clientId: string, clientSecret: string) {
17
- const token = await this.postToken(clientId, clientSecret)
18
- this.authenticatedAxiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`
19
- }
20
-
21
- async postToken(clientId?: string, clientSecret?: string): Promise<string> {
22
- const tokenFormRequestBody = new FormData()
23
- if (this.refreshToken) {
24
- tokenFormRequestBody.append('refresh_token', this.refreshToken)
25
- tokenFormRequestBody.append('grant_type', 'refresh_token')
26
- } else if (clientId && clientSecret) {
27
- tokenFormRequestBody.append('client_id', clientId)
28
- tokenFormRequestBody.append('client_secret', clientSecret)
29
- tokenFormRequestBody.append('grant_type', 'client_credentials')
30
- } else {
31
- throw new Error(
32
- 'Authentication failed, either the RefreshToken, or ClientId and ClientSecret need to be provided'
33
- )
34
- }
35
-
36
- const response = await this.axiosTokenInstance.post(
37
- '/services/oauth2/token',
38
- tokenFormRequestBody,
39
- {
40
- headers: tokenFormRequestBody.getHeaders()
41
- }
42
- )
43
-
44
- this.token = response?.data?.['access_token']
45
- if (!this.token) throw new Error('Authentication failed, could not get the access token')
46
- return this.token
47
- }
48
- }
1
+ import axios, { AxiosInstance } from 'axios'
2
+ import FormData from 'form-data'
3
+
4
+ export class SFAuthenticator {
5
+ axiosTokenInstance: AxiosInstance = axios.create()
6
+ authenticatedAxiosInstance: AxiosInstance
7
+ token: string | undefined = undefined
8
+ private refreshToken: string | undefined = undefined
9
+
10
+ constructor(authenticatedAxiosInstance: AxiosInstance, baseUrl?: string) {
11
+ this.axiosTokenInstance.defaults.baseURL =
12
+ baseUrl ?? 'https://do0000000d247eaa--phealth.sandbox.my.salesforce.com'
13
+ this.authenticatedAxiosInstance = authenticatedAxiosInstance
14
+ }
15
+
16
+ async initializeAuth(clientId: string, clientSecret: string) {
17
+ const token = await this.postToken(clientId, clientSecret)
18
+ this.authenticatedAxiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`
19
+ }
20
+
21
+ async postToken(clientId?: string, clientSecret?: string): Promise<string> {
22
+ const tokenFormRequestBody = new FormData()
23
+ if (this.refreshToken) {
24
+ tokenFormRequestBody.append('refresh_token', this.refreshToken)
25
+ tokenFormRequestBody.append('grant_type', 'refresh_token')
26
+ } else if (clientId && clientSecret) {
27
+ tokenFormRequestBody.append('client_id', clientId)
28
+ tokenFormRequestBody.append('client_secret', clientSecret)
29
+ tokenFormRequestBody.append('grant_type', 'client_credentials')
30
+ } else {
31
+ throw new Error(
32
+ 'Authentication failed, either the RefreshToken, or ClientId and ClientSecret need to be provided'
33
+ )
34
+ }
35
+
36
+ const response = await this.axiosTokenInstance.post(
37
+ '/services/oauth2/token',
38
+ tokenFormRequestBody,
39
+ {
40
+ headers: tokenFormRequestBody.getHeaders()
41
+ }
42
+ )
43
+
44
+ this.token = response?.data?.['access_token']
45
+ if (!this.token) throw new Error('Authentication failed, could not get the access token')
46
+ return this.token
47
+ }
48
+ }
@@ -13,7 +13,7 @@ export class SFTimesheetClient {
13
13
  try {
14
14
  const url = `/services/data/${SF_API_VERSION}/sobjects/TimeSheetHour__c/${timesheetHourId}`
15
15
  const response = await this.axiosInstance.patch(url, {
16
- Date__c: timesheet.date,
16
+ Date__c: timesheet.date,
17
17
  Callback__c: timesheet.callbackHours,
18
18
  HoursEBAdjusted__c: timesheet.regularHours,
19
19
  Misc__c: timesheet.miscHours,
@@ -41,7 +41,10 @@ export class SFTimesheetClient {
41
41
  async getTimesheetId(workorderId: string): Promise<string> {
42
42
  // First we find the correct timesheet id
43
43
  const url = `/services/data/${SF_API_VERSION}/query`
44
- const query = `SELECT Id FROM Timesheet__c WHERE WorkOrder__c = '${workorderId}' LIMIT 1`
44
+ const query = `SELECT Id
45
+ FROM Timesheet__c
46
+ WHERE WorkOrder__c = '${workorderId}'
47
+ LIMIT 1`
45
48
  const {
46
49
  data: { records }
47
50
  } = await this.axiosInstance.get(url, {
@@ -50,11 +53,42 @@ export class SFTimesheetClient {
50
53
  return records[0].Id
51
54
  }
52
55
 
56
+ async getTimesheetsForPractitioner(personnelID: string) {
57
+ const url = `/services/data/${SF_API_VERSION}/query`
58
+
59
+ const query = `SELECT FIELDS(STANDARD), WorkOrder__c
60
+ FROM TimeSheet__c
61
+ WHERE WorkOrder__c IN (SELECT Id
62
+ FROM WorkOrder__c
63
+ WHERE Personnel__c = '${personnelID}')`
64
+
65
+ const data = await this.axiosInstance.get(url, { params: { q: query } })
66
+
67
+ return data.data.records
68
+ }
69
+
70
+ async getTimesheetsIdAndDateForPractitioner(personnelID: string) {
71
+ const url = `/services/data/${SF_API_VERSION}/query`
72
+
73
+ const query = `SELECT Id, LastModifiedDate
74
+ FROM TimeSheet__c
75
+ WHERE WorkOrder__c IN (SELECT Id
76
+ FROM WorkOrder__c
77
+ WHERE Personnel__c = '${personnelID}')`
78
+
79
+ const data = await this.axiosInstance.get(url, { params: { q: query } })
80
+
81
+ return data.data.records.map(({Id, LastModifiedDate}) => ({Id, LastModifiedDate}))
82
+ }
83
+
84
+
53
85
  async getTimesheetHoursIds(workorderId: string): Promise<string[]> {
54
86
  const timesheetId = await this.getTimesheetId(workorderId)
55
87
  // First we find the correct timesheet hours id
56
88
  const url = `/services/data/${SF_API_VERSION}/query`
57
- const query = `SELECT Id FROM TimesheetHour__c WHERE Timesheet__c = '${timesheetId}'`
89
+ const query = `SELECT Id
90
+ FROM TimesheetHour__c
91
+ WHERE Timesheet__c = '${timesheetId}'`
58
92
  const {
59
93
  data: { records }
60
94
  } = await this.axiosInstance.get(url, {
@@ -0,0 +1,43 @@
1
+ import { AxiosInstance } from 'axios'
2
+ import { SF_API_VERSION } from '../apiClient'
3
+ import { Workorder } from '../../models'
4
+
5
+ export class SFWorkorderClient {
6
+ private axiosInstance: AxiosInstance
7
+
8
+ constructor(axiosInstance: AxiosInstance) {
9
+ this.axiosInstance = axiosInstance
10
+ }
11
+
12
+
13
+ async getWorkordersForPractitioner(assignedStaffId?: string): Promise<Workorder[]> {
14
+ try {
15
+ const url = `/services/data/${SF_API_VERSION}/query`
16
+ const query = assignedStaffId
17
+ ? `SELECT Id, HospitalID__c, HospitalName__c, ProfessionalDesignation__c, Personnel__c, startdate__c, EndDate__c, CreatedDate, LastModifiedDate FROM WorkOrder__c WHERE Personnel__c = '${assignedStaffId}'`
18
+ : `SELECT Id, HospitalID__c, HospitalName__c, ProfessionalDesignation__c, Personnel__c, startdate__c, EndDate__c, CreatedDate, LastModifiedDate FROM WorkOrder__c`
19
+ return await this.axiosInstance
20
+ .get(url, {
21
+ params: { q: query }
22
+ })
23
+ .then(({ data: { records } }) =>
24
+ records.map(
25
+ (record): Workorder => ({
26
+ id: record.Id,
27
+ establishmentId: record.HospitalID__c,
28
+ establishmentName: record.HospitalName__c,
29
+ role: record.ProfessionalDesignation__c,
30
+ assignedStaffId: record.Personnel__c,
31
+ startDate: new Date(record.startdate__c),
32
+ endDate: new Date(record.EndDate__c),
33
+ createdAt: new Date(record.CreatedDate),
34
+ updatedAt: new Date(record.LastModifiedDate)
35
+ })
36
+ )
37
+ )
38
+ } catch (error) {
39
+ console.error('Error fetching work orders: ', error.message)
40
+ throw error
41
+ }
42
+ }
43
+ }
@@ -8,6 +8,11 @@ export interface Workorder {
8
8
  establishmentName: string
9
9
  establishmentId: string
10
10
  role: string
11
+ assignedStaffId: string
12
+ startDate: Date
13
+ endDate: Date
14
+ createdAt: Date
15
+ updatedAt: Date
11
16
  }
12
17
 
13
18
  export * from './timesheet'
@@ -4,4 +4,4 @@ export interface Practitioner {
4
4
  lastName: string
5
5
  email: string
6
6
  staffId: string
7
- }
7
+ }
@@ -1,21 +1,21 @@
1
- export interface TimesheetDayEntry {
2
- date?: Date
3
- callbackHours?: number
4
- regularHours?: number
5
- miscHours?: number
6
- overtime1Hours?: number
7
- overtime2Hours?: number
8
- onCallHours?: number
9
- misc1HoursA?: number
10
- misc1HoursB?: number
11
- misc2Hours?: number
12
- misc3Hours?: number
13
- misc4Hours?: number
14
- stat1Hours?: number
15
- stat2Hours?: number
16
- // "EmployeeTimeCardEntry__c": null, // unknown entry in salesforce
17
- inChargeHours?: number
18
- // "Shift_Differential__c": number, // unknown entry in salesforce
19
- shiftTravelPerDiemHours?: number
20
- // "Weekend_Differential__c": number // unknown entry in salesforce
21
- }
1
+ export interface TimesheetDayEntry {
2
+ date?: Date
3
+ callbackHours?: number
4
+ regularHours?: number
5
+ miscHours?: number
6
+ overtime1Hours?: number
7
+ overtime2Hours?: number
8
+ onCallHours?: number
9
+ misc1HoursA?: number
10
+ misc1HoursB?: number
11
+ misc2Hours?: number
12
+ misc3Hours?: number
13
+ misc4Hours?: number
14
+ stat1Hours?: number
15
+ stat2Hours?: number
16
+ // "EmployeeTimeCardEntry__c": null, // unknown entry in salesforce
17
+ inChargeHours?: number
18
+ // "Shift_Differential__c": number, // unknown entry in salesforce
19
+ shiftTravelPerDiemHours?: number
20
+ // "Weekend_Differential__c": number // unknown entry in salesforce
21
+ }