washday-sdk 1.6.61 → 1.6.62
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/dist/api/attendance/post.js +35 -2
- package/dist/index.js +1 -0
- package/package.json +1 -1
- package/src/api/attendance/post.ts +62 -14
- package/src/index.ts +1 -0
- package/src/interfaces/Attendance.ts +36 -1
- package/test/attendance.metadata.test.ts +83 -0
|
@@ -8,13 +8,46 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
const ATTENDANCE_API = 'api/attendance';
|
|
11
|
+
const ATTENDANCE_SOURCES = ["web_pos", "pos_v2", "unknown"];
|
|
12
|
+
const stringValue = (value) => (typeof value === "string" && value.trim() ? value.trim() : undefined);
|
|
13
|
+
const numberValue = (value) => (typeof value === "number" && Number.isFinite(value) ? value : undefined);
|
|
14
|
+
const sourceValue = (value) => (ATTENDANCE_SOURCES.includes(value) ? value : undefined);
|
|
15
|
+
const buildSafeAttendanceMetadata = (metadata) => {
|
|
16
|
+
if (!metadata)
|
|
17
|
+
return undefined;
|
|
18
|
+
const safeMetadata = {
|
|
19
|
+
source: sourceValue(metadata.source),
|
|
20
|
+
platform: stringValue(metadata.platform),
|
|
21
|
+
appVersion: stringValue(metadata.appVersion),
|
|
22
|
+
deviceId: stringValue(metadata.deviceId),
|
|
23
|
+
language: stringValue(metadata.language),
|
|
24
|
+
timezone: stringValue(metadata.timezone),
|
|
25
|
+
screenWidth: numberValue(metadata.screenWidth),
|
|
26
|
+
screenHeight: numberValue(metadata.screenHeight),
|
|
27
|
+
};
|
|
28
|
+
const filteredEntries = Object.entries(safeMetadata).filter(([, value]) => value !== undefined);
|
|
29
|
+
return filteredEntries.length
|
|
30
|
+
? Object.fromEntries(filteredEntries)
|
|
31
|
+
: undefined;
|
|
32
|
+
};
|
|
33
|
+
const buildAttendancePayload = (data) => {
|
|
34
|
+
const metadata = buildSafeAttendanceMetadata(data.metadata);
|
|
35
|
+
const payload = Object.assign({}, data);
|
|
36
|
+
if (metadata) {
|
|
37
|
+
payload.metadata = metadata;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
delete payload.metadata;
|
|
41
|
+
}
|
|
42
|
+
return payload;
|
|
43
|
+
};
|
|
11
44
|
export const clockIn = function (data) {
|
|
12
45
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13
46
|
try {
|
|
14
47
|
const config = {
|
|
15
48
|
headers: { Authorization: `Bearer ${this.apiToken}` }
|
|
16
49
|
};
|
|
17
|
-
return yield this.axiosInstance.post(`${ATTENDANCE_API}/clock-in`, data, config);
|
|
50
|
+
return yield this.axiosInstance.post(`${ATTENDANCE_API}/clock-in`, buildAttendancePayload(data), config);
|
|
18
51
|
}
|
|
19
52
|
catch (error) {
|
|
20
53
|
console.error('Error clock-in:', error);
|
|
@@ -28,7 +61,7 @@ export const clockOut = function (data) {
|
|
|
28
61
|
const config = {
|
|
29
62
|
headers: { Authorization: `Bearer ${this.apiToken}` }
|
|
30
63
|
};
|
|
31
|
-
return yield this.axiosInstance.post(`${ATTENDANCE_API}/clock-out`, data, config);
|
|
64
|
+
return yield this.axiosInstance.post(`${ATTENDANCE_API}/clock-out`, buildAttendancePayload(data), config);
|
|
32
65
|
}
|
|
33
66
|
catch (error) {
|
|
34
67
|
console.error('Error clock-out:', error);
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,36 +1,84 @@
|
|
|
1
1
|
import { WashdayClientInstance } from "../../interfaces/Api";
|
|
2
|
-
import
|
|
2
|
+
import type {
|
|
3
|
+
AttendanceClientMetadata,
|
|
4
|
+
AttendanceSource,
|
|
5
|
+
ClockInRequest,
|
|
6
|
+
ClockOutRequest,
|
|
7
|
+
} from "../../interfaces/Attendance";
|
|
3
8
|
|
|
4
9
|
const ATTENDANCE_API = 'api/attendance';
|
|
10
|
+
const ATTENDANCE_SOURCES: AttendanceSource[] = ["web_pos", "pos_v2", "unknown"];
|
|
5
11
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
const stringValue = (value: unknown): string | undefined => (
|
|
13
|
+
typeof value === "string" && value.trim() ? value.trim() : undefined
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const numberValue = (value: unknown): number | undefined => (
|
|
17
|
+
typeof value === "number" && Number.isFinite(value) ? value : undefined
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const sourceValue = (value: unknown): AttendanceSource | undefined => (
|
|
21
|
+
ATTENDANCE_SOURCES.includes(value as AttendanceSource) ? value as AttendanceSource : undefined
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const buildSafeAttendanceMetadata = (
|
|
25
|
+
metadata?: AttendanceClientMetadata & Record<string, unknown>
|
|
26
|
+
): AttendanceClientMetadata | undefined => {
|
|
27
|
+
if (!metadata) return undefined;
|
|
28
|
+
|
|
29
|
+
const safeMetadata: AttendanceClientMetadata = {
|
|
30
|
+
source: sourceValue(metadata.source),
|
|
31
|
+
platform: stringValue(metadata.platform),
|
|
32
|
+
appVersion: stringValue(metadata.appVersion),
|
|
33
|
+
deviceId: stringValue(metadata.deviceId),
|
|
34
|
+
language: stringValue(metadata.language),
|
|
35
|
+
timezone: stringValue(metadata.timezone),
|
|
36
|
+
screenWidth: numberValue(metadata.screenWidth),
|
|
37
|
+
screenHeight: numberValue(metadata.screenHeight),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const filteredEntries = Object.entries(safeMetadata).filter(
|
|
41
|
+
([, value]) => value !== undefined
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return filteredEntries.length
|
|
45
|
+
? Object.fromEntries(filteredEntries) as AttendanceClientMetadata
|
|
46
|
+
: undefined;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const buildAttendancePayload = <T extends ClockInRequest | ClockOutRequest>(data: T): T => {
|
|
50
|
+
const metadata = buildSafeAttendanceMetadata(data.metadata as any);
|
|
51
|
+
const payload = { ...data } as T;
|
|
52
|
+
|
|
53
|
+
if (metadata) {
|
|
54
|
+
payload.metadata = metadata;
|
|
55
|
+
} else {
|
|
56
|
+
delete payload.metadata;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return payload;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const clockIn = async function (this: WashdayClientInstance, data: ClockInRequest): Promise<any> {
|
|
11
63
|
try {
|
|
12
64
|
const config = {
|
|
13
65
|
headers: { Authorization: `Bearer ${this.apiToken}` }
|
|
14
66
|
};
|
|
15
|
-
return await this.axiosInstance.post(`${ATTENDANCE_API}/clock-in`, data, config);
|
|
67
|
+
return await this.axiosInstance.post(`${ATTENDANCE_API}/clock-in`, buildAttendancePayload(data), config);
|
|
16
68
|
} catch (error) {
|
|
17
69
|
console.error('Error clock-in:', error);
|
|
18
70
|
throw error;
|
|
19
71
|
}
|
|
20
72
|
};
|
|
21
73
|
|
|
22
|
-
export const clockOut = async function (this: WashdayClientInstance, data: {
|
|
23
|
-
userId?: string;
|
|
24
|
-
storeId?: string; // ✅ AÑADIDO - requerido por backend
|
|
25
|
-
notes?: string;
|
|
26
|
-
}): Promise<any> {
|
|
74
|
+
export const clockOut = async function (this: WashdayClientInstance, data: ClockOutRequest): Promise<any> {
|
|
27
75
|
try {
|
|
28
76
|
const config = {
|
|
29
77
|
headers: { Authorization: `Bearer ${this.apiToken}` }
|
|
30
78
|
};
|
|
31
|
-
return await this.axiosInstance.post(`${ATTENDANCE_API}/clock-out`, data, config);
|
|
79
|
+
return await this.axiosInstance.post(`${ATTENDANCE_API}/clock-out`, buildAttendancePayload(data), config);
|
|
32
80
|
} catch (error) {
|
|
33
81
|
console.error('Error clock-out:', error);
|
|
34
82
|
throw error;
|
|
35
83
|
}
|
|
36
|
-
};
|
|
84
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './interfaces/Auth';
|
|
|
7
7
|
export * from './interfaces/Customer';
|
|
8
8
|
export * from './interfaces/DomainUrls';
|
|
9
9
|
export * from './interfaces/GoogleMaps';
|
|
10
|
+
export * from './interfaces/Attendance';
|
|
10
11
|
export type { StartMPOAuthFlowRequest } from './api/integrations/post';
|
|
11
12
|
export type {
|
|
12
13
|
CreateCFDISubscriptionCheckoutSessionRequest,
|
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
import { IUser } from "./User";
|
|
2
2
|
import { IStore } from "./Store";
|
|
3
3
|
|
|
4
|
+
export type AttendanceSource = "web_pos" | "pos_v2" | "unknown";
|
|
5
|
+
|
|
6
|
+
export interface AttendanceClientMetadata {
|
|
7
|
+
platform?: string;
|
|
8
|
+
appVersion?: string;
|
|
9
|
+
deviceId?: string;
|
|
10
|
+
source?: AttendanceSource;
|
|
11
|
+
language?: string;
|
|
12
|
+
timezone?: string;
|
|
13
|
+
screenWidth?: number;
|
|
14
|
+
screenHeight?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface AttendanceServerMetadata extends AttendanceClientMetadata {
|
|
18
|
+
ipAddress?: string;
|
|
19
|
+
cfConnectingIp?: string;
|
|
20
|
+
xForwardedFor?: string;
|
|
21
|
+
userAgent?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ClockInRequest {
|
|
25
|
+
storeId: string;
|
|
26
|
+
userId?: string;
|
|
27
|
+
notes?: string;
|
|
28
|
+
metadata?: AttendanceClientMetadata;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ClockOutRequest {
|
|
32
|
+
userId?: string;
|
|
33
|
+
storeId?: string;
|
|
34
|
+
notes?: string;
|
|
35
|
+
metadata?: AttendanceClientMetadata;
|
|
36
|
+
}
|
|
37
|
+
|
|
4
38
|
export interface IAttendanceRecord {
|
|
5
39
|
_id?: string;
|
|
6
40
|
employee: IUser | string;
|
|
@@ -8,6 +42,7 @@ export interface IAttendanceRecord {
|
|
|
8
42
|
type: 'IN' | 'OUT';
|
|
9
43
|
timestamp: Date;
|
|
10
44
|
ipAddress?: string;
|
|
45
|
+
metadata?: AttendanceServerMetadata;
|
|
11
46
|
notes?: string;
|
|
12
47
|
editedBy?: IUser | string;
|
|
13
48
|
editedAt?: Date;
|
|
@@ -42,4 +77,4 @@ export interface IAttendanceReport {
|
|
|
42
77
|
startDate: Date;
|
|
43
78
|
endDate: Date;
|
|
44
79
|
};
|
|
45
|
-
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { clockIn, clockOut } from "../src/api/attendance/post";
|
|
2
|
+
|
|
3
|
+
describe("attendance metadata requests", () => {
|
|
4
|
+
it("forwards client-safe clock-in metadata and strips IP fields", async () => {
|
|
5
|
+
const post = jest.fn().mockResolvedValue({ data: { data: {} } });
|
|
6
|
+
const client = {
|
|
7
|
+
apiToken: "token-123",
|
|
8
|
+
axiosInstance: { post },
|
|
9
|
+
} as any;
|
|
10
|
+
|
|
11
|
+
await clockIn.call(client, {
|
|
12
|
+
storeId: "store-1",
|
|
13
|
+
userId: "user-1",
|
|
14
|
+
metadata: {
|
|
15
|
+
source: "web_pos",
|
|
16
|
+
platform: "MacIntel",
|
|
17
|
+
language: "es-MX",
|
|
18
|
+
timezone: "America/Mexico_City",
|
|
19
|
+
screenWidth: 1440,
|
|
20
|
+
screenHeight: 900,
|
|
21
|
+
ipAddress: "1.1.1.1",
|
|
22
|
+
cfConnectingIp: "1.1.1.2",
|
|
23
|
+
xForwardedFor: "1.1.1.3",
|
|
24
|
+
},
|
|
25
|
+
} as any);
|
|
26
|
+
|
|
27
|
+
expect(post).toHaveBeenCalledWith(
|
|
28
|
+
"api/attendance/clock-in",
|
|
29
|
+
{
|
|
30
|
+
storeId: "store-1",
|
|
31
|
+
userId: "user-1",
|
|
32
|
+
metadata: {
|
|
33
|
+
source: "web_pos",
|
|
34
|
+
platform: "MacIntel",
|
|
35
|
+
language: "es-MX",
|
|
36
|
+
timezone: "America/Mexico_City",
|
|
37
|
+
screenWidth: 1440,
|
|
38
|
+
screenHeight: 900,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
headers: { Authorization: "Bearer token-123" },
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("forwards client-safe clock-out metadata and strips IP fields", async () => {
|
|
48
|
+
const post = jest.fn().mockResolvedValue({ data: { data: {} } });
|
|
49
|
+
const client = {
|
|
50
|
+
apiToken: "token-123",
|
|
51
|
+
axiosInstance: { post },
|
|
52
|
+
} as any;
|
|
53
|
+
|
|
54
|
+
await clockOut.call(client, {
|
|
55
|
+
storeId: "store-1",
|
|
56
|
+
userId: "user-1",
|
|
57
|
+
metadata: {
|
|
58
|
+
source: "pos_v2",
|
|
59
|
+
platform: "ios",
|
|
60
|
+
appVersion: "2.5.0",
|
|
61
|
+
deviceId: "device-1",
|
|
62
|
+
ipAddress: "1.1.1.1",
|
|
63
|
+
},
|
|
64
|
+
} as any);
|
|
65
|
+
|
|
66
|
+
expect(post).toHaveBeenCalledWith(
|
|
67
|
+
"api/attendance/clock-out",
|
|
68
|
+
{
|
|
69
|
+
storeId: "store-1",
|
|
70
|
+
userId: "user-1",
|
|
71
|
+
metadata: {
|
|
72
|
+
source: "pos_v2",
|
|
73
|
+
platform: "ios",
|
|
74
|
+
appVersion: "2.5.0",
|
|
75
|
+
deviceId: "device-1",
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
headers: { Authorization: "Bearer token-123" },
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
});
|