@vulog/aima-business 1.2.39
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/index.cjs +668 -0
- package/dist/index.d.cts +346 -0
- package/dist/index.d.mts +346 -0
- package/dist/index.mjs +609 -0
- package/package.json +42 -0
- package/src/addBusinessCredit.ts +31 -0
- package/src/addStripePayment.ts +18 -0
- package/src/addTripNote.test.ts +67 -0
- package/src/addTripNote.ts +30 -0
- package/src/addUserToBusiness.test.ts +74 -0
- package/src/addUserToBusiness.ts +49 -0
- package/src/archiveBusinessProfile.ts +28 -0
- package/src/bulkAddBusinessUsers.ts +27 -0
- package/src/businessDelegatedAdmin.test.ts +68 -0
- package/src/businessDelegatedAdmin.ts +32 -0
- package/src/businessOwner.test.ts +68 -0
- package/src/businessOwner.ts +32 -0
- package/src/chargeBusinessProduct.ts +31 -0
- package/src/createBusiness.test.ts +54 -0
- package/src/createBusiness.ts +23 -0
- package/src/createBusinessCostCenter.test.ts +61 -0
- package/src/createBusinessCostCenter.ts +34 -0
- package/src/deactivateBusinessProfile.ts +22 -0
- package/src/deleteBusinessCostCenter.test.ts +45 -0
- package/src/deleteBusinessCostCenter.ts +23 -0
- package/src/deleteInvitationRequest.test.ts +45 -0
- package/src/deleteInvitationRequest.ts +13 -0
- package/src/getBillingGroups.ts +9 -0
- package/src/getBusinessById.test.ts +47 -0
- package/src/getBusinessById.ts +15 -0
- package/src/getBusinessContacts.ts +17 -0
- package/src/getBusinessCostCenterById.ts +27 -0
- package/src/getBusinessCostCenters.ts +18 -0
- package/src/getBusinessInviteLink.ts +17 -0
- package/src/getBusinessInvoiceProducts.ts +24 -0
- package/src/getBusinessInvoiceTrips.ts +20 -0
- package/src/getBusinessInvoices.test.ts +92 -0
- package/src/getBusinessInvoices.ts +43 -0
- package/src/getBusinessPaymentDetails.ts +20 -0
- package/src/getBusinessProducts.ts +9 -0
- package/src/getBusinessTripById.ts +15 -0
- package/src/getBusinessUserById.ts +26 -0
- package/src/getBusinessUserGlobalById.ts +15 -0
- package/src/getBusinessUsers.test.ts +70 -0
- package/src/getBusinessUsers.ts +43 -0
- package/src/getBusinessWallet.test.ts +46 -0
- package/src/getBusinessWallet.ts +17 -0
- package/src/getBusinesses.test.ts +133 -0
- package/src/getBusinesses.ts +36 -0
- package/src/getEntityBalance.ts +17 -0
- package/src/getEntityProducts.ts +15 -0
- package/src/getEntityTrips.ts +13 -0
- package/src/getEntityTripsCost.ts +17 -0
- package/src/getInvitationRequest.test.ts +46 -0
- package/src/getInvitationRequest.ts +17 -0
- package/src/getInvoicePdf.test.ts +62 -0
- package/src/getInvoicePdf.ts +16 -0
- package/src/getInvoiceRefundNote.ts +17 -0
- package/src/getInvoiceRefundableAmount.ts +20 -0
- package/src/getOngoingTripNotes.ts +17 -0
- package/src/getOngoingTrips.test.ts +43 -0
- package/src/getOngoingTrips.ts +9 -0
- package/src/getStripePublishableKey.ts +9 -0
- package/src/getStripeSetup.ts +17 -0
- package/src/index.ts +58 -0
- package/src/inviteBusinessUser.ts +31 -0
- package/src/listBusinessUsersGlobal.test.ts +65 -0
- package/src/listBusinessUsersGlobal.ts +26 -0
- package/src/redeemBusinessPromoCode.ts +18 -0
- package/src/refundInvoice.test.ts +72 -0
- package/src/refundInvoice.ts +33 -0
- package/src/refundInvoiceAmount.ts +20 -0
- package/src/searchBusinessUsersByName.ts +27 -0
- package/src/searchBusinessUsersGlobal.ts +18 -0
- package/src/sendBusinessIban.ts +29 -0
- package/src/setInvoiceExternalPayment.ts +33 -0
- package/src/types.ts +163 -0
- package/src/updateBusiness.test.ts +65 -0
- package/src/updateBusiness.ts +35 -0
- package/src/updateBusinessCostCenter.ts +41 -0
- package/src/updateBusinessProfileStatus.ts +22 -0
- package/src/updateBusinessUserProfile.ts +51 -0
- package/src/updateInvoiceStatus.test.ts +54 -0
- package/src/updateInvoiceStatus.ts +19 -0
- package/tsconfig.json +9 -0
- package/tsdown.config.ts +8 -0
- package/vitest.config.ts +1 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export type AddBusinessCreditBody = {
|
|
5
|
+
amount: number;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const bodySchema = z.object({
|
|
9
|
+
amount: z.number().min(0),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const addBusinessCredit = async (
|
|
13
|
+
client: Client,
|
|
14
|
+
businessId: string,
|
|
15
|
+
body: AddBusinessCreditBody
|
|
16
|
+
): Promise<void> => {
|
|
17
|
+
const parsedId = z.string().trim().min(1).uuid().safeParse(businessId);
|
|
18
|
+
if (!parsedId.success) {
|
|
19
|
+
throw new TypeError('Invalid args', { cause: parsedId.error.issues });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const result = bodySchema.safeParse(body);
|
|
23
|
+
if (!result.success) {
|
|
24
|
+
throw new TypeError('Invalid args', { cause: result.error.issues });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await client.post<void>(
|
|
28
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business/${parsedId.data}/credit`,
|
|
29
|
+
result.data
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { StripeSetup } from './types';
|
|
5
|
+
|
|
6
|
+
/** @deprecated */
|
|
7
|
+
export const addStripePayment = async (client: Client, businessId: string): Promise<StripeSetup> => {
|
|
8
|
+
const result = z.string().trim().min(1).uuid().safeParse(businessId);
|
|
9
|
+
if (!result.success) {
|
|
10
|
+
throw new TypeError('Invalid args', { cause: result.error.issues });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return client
|
|
14
|
+
.post<StripeSetup>(
|
|
15
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/stripe/businesses/${result.data}/add`
|
|
16
|
+
)
|
|
17
|
+
.then(({ data }) => data);
|
|
18
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { addTripNote, AddTripNoteBody } from './addTripNote';
|
|
4
|
+
|
|
5
|
+
describe('addTripNote', () => {
|
|
6
|
+
const postMock = vi.fn();
|
|
7
|
+
const client = {
|
|
8
|
+
post: postMock,
|
|
9
|
+
clientOptions: {
|
|
10
|
+
fleetId: 'FLEET_ID',
|
|
11
|
+
},
|
|
12
|
+
} as unknown as Client;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const TRIP_ID = '018ab2b6-71b2-4c76-90bd-6e8d3f268618';
|
|
19
|
+
|
|
20
|
+
test('should create a trip note with valid params', async () => {
|
|
21
|
+
const body: AddTripNoteBody = { content: 'Customer requested early return' };
|
|
22
|
+
const mockResponse = { id: 'note-uuid', content: 'Customer requested early return' };
|
|
23
|
+
postMock.mockResolvedValueOnce({ data: mockResponse });
|
|
24
|
+
|
|
25
|
+
const result = await addTripNote(client, TRIP_ID, body);
|
|
26
|
+
|
|
27
|
+
expect(result).toEqual(mockResponse);
|
|
28
|
+
expect(postMock).toHaveBeenCalledWith(
|
|
29
|
+
`/boapi/proxy/business/fleets/FLEET_ID/trip/${TRIP_ID}/notes`,
|
|
30
|
+
body
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should throw TypeError for invalid tripId', async () => {
|
|
35
|
+
const body: AddTripNoteBody = { content: 'Some note' };
|
|
36
|
+
await expect(addTripNote(client, 'not-a-uuid', body)).rejects.toThrow(TypeError);
|
|
37
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should throw TypeError for empty tripId', async () => {
|
|
41
|
+
const body: AddTripNoteBody = { content: 'Some note' };
|
|
42
|
+
await expect(addTripNote(client, '', body)).rejects.toThrow(TypeError);
|
|
43
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('should throw TypeError for empty content', async () => {
|
|
47
|
+
const body: AddTripNoteBody = { content: '' };
|
|
48
|
+
await expect(addTripNote(client, TRIP_ID, body)).rejects.toThrow(TypeError);
|
|
49
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('should throw TypeError for whitespace-only content', async () => {
|
|
53
|
+
const body: AddTripNoteBody = { content: ' ' };
|
|
54
|
+
await expect(addTripNote(client, TRIP_ID, body)).rejects.toThrow(TypeError);
|
|
55
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('error cause includes Zod issues for both invalid tripId and empty content', async () => {
|
|
59
|
+
try {
|
|
60
|
+
await addTripNote(client, 'bad', { content: '' });
|
|
61
|
+
} catch (err) {
|
|
62
|
+
expect(err).toBeInstanceOf(TypeError);
|
|
63
|
+
expect((err as Error).cause).toBeDefined();
|
|
64
|
+
expect(Array.isArray((err as Error).cause)).toBe(true);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { TripNote } from './types';
|
|
5
|
+
|
|
6
|
+
export type AddTripNoteBody = {
|
|
7
|
+
content: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const addTripNoteBodySchema = z.object({
|
|
11
|
+
content: z.string().trim().min(1),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const addTripNote = async (client: Client, tripId: string, body: AddTripNoteBody): Promise<TripNote> => {
|
|
15
|
+
const tripIdResult = z.string().trim().min(1).uuid().safeParse(tripId);
|
|
16
|
+
const bodyResult = addTripNoteBodySchema.safeParse(body);
|
|
17
|
+
|
|
18
|
+
if (!tripIdResult.success || !bodyResult.success) {
|
|
19
|
+
throw new TypeError('Invalid args', {
|
|
20
|
+
cause: [...(tripIdResult.error?.issues ?? []), ...(bodyResult.error?.issues ?? [])],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return client
|
|
25
|
+
.post<TripNote>(
|
|
26
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/trip/${tripIdResult.data}/notes`,
|
|
27
|
+
bodyResult.data
|
|
28
|
+
)
|
|
29
|
+
.then(({ data }) => data);
|
|
30
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { addUserToBusiness } from './addUserToBusiness';
|
|
4
|
+
|
|
5
|
+
describe('addUserToBusiness', () => {
|
|
6
|
+
const postMock = vi.fn();
|
|
7
|
+
const client = {
|
|
8
|
+
post: postMock,
|
|
9
|
+
clientOptions: { fleetId: 'FLEET_ID' },
|
|
10
|
+
} as unknown as Client;
|
|
11
|
+
|
|
12
|
+
const businessId = 'ed539d7d-d815-405b-bc00-71008fb1954c';
|
|
13
|
+
const userId = 'b931b17e-214f-4a73-ad94-77a973435768';
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('should call POST with correct URL and empty body when no data provided', async () => {
|
|
20
|
+
const mockProfile = { id: 'profile-1', status: 'APPROVED' };
|
|
21
|
+
postMock.mockResolvedValueOnce({ data: mockProfile });
|
|
22
|
+
|
|
23
|
+
const result = await addUserToBusiness(client, businessId, userId);
|
|
24
|
+
|
|
25
|
+
expect(postMock).toHaveBeenCalledWith(
|
|
26
|
+
`/boapi/proxy/business/fleets/FLEET_ID/business/${businessId}/user/${userId}`,
|
|
27
|
+
{}
|
|
28
|
+
);
|
|
29
|
+
expect(result).toEqual(mockProfile);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('should pass data as body when provided', async () => {
|
|
33
|
+
const mockProfile = { id: 'profile-1' };
|
|
34
|
+
postMock.mockResolvedValueOnce({ data: mockProfile });
|
|
35
|
+
const data = { emailConsent: true, email: 'test@example.com' };
|
|
36
|
+
|
|
37
|
+
await addUserToBusiness(client, businessId, userId, data);
|
|
38
|
+
|
|
39
|
+
expect(postMock).toHaveBeenCalledWith(
|
|
40
|
+
`/boapi/proxy/business/fleets/FLEET_ID/business/${businessId}/user/${userId}`,
|
|
41
|
+
data
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should throw TypeError for invalid businessId', async () => {
|
|
46
|
+
await expect(addUserToBusiness(client, 'not-a-uuid', userId)).rejects.toThrow(TypeError);
|
|
47
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('should throw TypeError for invalid userId', async () => {
|
|
51
|
+
await expect(addUserToBusiness(client, businessId, 'not-a-uuid')).rejects.toThrow(TypeError);
|
|
52
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('should throw TypeError for empty businessId', async () => {
|
|
56
|
+
await expect(addUserToBusiness(client, '', userId)).rejects.toThrow(TypeError);
|
|
57
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('should throw TypeError for empty userId', async () => {
|
|
61
|
+
await expect(addUserToBusiness(client, businessId, '')).rejects.toThrow(TypeError);
|
|
62
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('error cause includes Zod issues', async () => {
|
|
66
|
+
try {
|
|
67
|
+
await addUserToBusiness(client, 'bad', 'bad');
|
|
68
|
+
} catch (err) {
|
|
69
|
+
expect(err).toBeInstanceOf(TypeError);
|
|
70
|
+
expect((err as Error).cause).toBeDefined();
|
|
71
|
+
expect(Array.isArray((err as Error).cause)).toBe(true);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { BusinessUserProfile } from './types';
|
|
5
|
+
|
|
6
|
+
export type AddUserToBusinessBody = {
|
|
7
|
+
email?: string;
|
|
8
|
+
emailConsent?: boolean;
|
|
9
|
+
requestId?: string;
|
|
10
|
+
costCenterId?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const uuidSchema = z.string().trim().min(1).uuid();
|
|
14
|
+
|
|
15
|
+
const bodySchema = z
|
|
16
|
+
.object({
|
|
17
|
+
email: z.string().trim().email().optional(),
|
|
18
|
+
emailConsent: z.boolean().optional(),
|
|
19
|
+
requestId: z.string().trim().min(1).uuid().optional(),
|
|
20
|
+
costCenterId: z.string().trim().min(1).uuid().optional(),
|
|
21
|
+
})
|
|
22
|
+
.optional();
|
|
23
|
+
|
|
24
|
+
export const addUserToBusiness = async (
|
|
25
|
+
client: Client,
|
|
26
|
+
businessId: string,
|
|
27
|
+
userId: string,
|
|
28
|
+
data?: AddUserToBusinessBody
|
|
29
|
+
): Promise<BusinessUserProfile> => {
|
|
30
|
+
const parsedBusinessId = uuidSchema.safeParse(businessId);
|
|
31
|
+
const parsedUserId = uuidSchema.safeParse(userId);
|
|
32
|
+
if (!parsedBusinessId.success || !parsedUserId.success) {
|
|
33
|
+
throw new TypeError('Invalid args', {
|
|
34
|
+
cause: [...(parsedBusinessId.error?.issues ?? []), ...(parsedUserId.error?.issues ?? [])],
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const result = bodySchema.safeParse(data);
|
|
39
|
+
if (!result.success) {
|
|
40
|
+
throw new TypeError('Invalid args', { cause: result.error.issues });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return client
|
|
44
|
+
.post<BusinessUserProfile>(
|
|
45
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business/${parsedBusinessId.data}/user/${parsedUserId.data}`,
|
|
46
|
+
result.data ?? {}
|
|
47
|
+
)
|
|
48
|
+
.then(({ data: d }) => d);
|
|
49
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
const uuidSchema = z.string().trim().min(1).uuid();
|
|
5
|
+
|
|
6
|
+
export const archiveBusinessProfile = async (
|
|
7
|
+
client: Client,
|
|
8
|
+
businessId: string,
|
|
9
|
+
userId: string,
|
|
10
|
+
profileId: string
|
|
11
|
+
): Promise<void> => {
|
|
12
|
+
const parsedBusinessId = uuidSchema.safeParse(businessId);
|
|
13
|
+
const parsedUserId = uuidSchema.safeParse(userId);
|
|
14
|
+
const parsedProfileId = uuidSchema.safeParse(profileId);
|
|
15
|
+
if (!parsedBusinessId.success || !parsedUserId.success || !parsedProfileId.success) {
|
|
16
|
+
throw new TypeError('Invalid args', {
|
|
17
|
+
cause: [
|
|
18
|
+
...(parsedBusinessId.error?.issues ?? []),
|
|
19
|
+
...(parsedUserId.error?.issues ?? []),
|
|
20
|
+
...(parsedProfileId.error?.issues ?? []),
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
await client.delete<void>(
|
|
26
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business/${parsedBusinessId.data}/user/${parsedUserId.data}/profile/${parsedProfileId.data}`
|
|
27
|
+
);
|
|
28
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export type BulkAddBusinessUsersBody = {
|
|
5
|
+
userIds: string[];
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const bulkAddSchema = z.object({
|
|
9
|
+
businessId: z.string().trim().min(1).uuid(),
|
|
10
|
+
userIds: z.array(z.string().trim().min(1).uuid()).min(1),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const bulkAddBusinessUsers = async (
|
|
14
|
+
client: Client,
|
|
15
|
+
businessId: string,
|
|
16
|
+
body: BulkAddBusinessUsersBody
|
|
17
|
+
): Promise<void> => {
|
|
18
|
+
const result = bulkAddSchema.safeParse({ businessId, userIds: body.userIds });
|
|
19
|
+
if (!result.success) {
|
|
20
|
+
throw new TypeError('Invalid args', { cause: result.error.issues });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
await client.post<void>(
|
|
24
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business/${result.data.businessId}/user/bulk`,
|
|
25
|
+
{ userIds: result.data.userIds }
|
|
26
|
+
);
|
|
27
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { setDelegatedAdmin, removeDelegatedAdmin } from './businessDelegatedAdmin';
|
|
4
|
+
|
|
5
|
+
describe('businessDelegatedAdmin', () => {
|
|
6
|
+
const postMock = vi.fn();
|
|
7
|
+
const deleteMock = vi.fn();
|
|
8
|
+
const client = {
|
|
9
|
+
post: postMock,
|
|
10
|
+
delete: deleteMock,
|
|
11
|
+
clientOptions: { fleetId: 'FLEET_ID' },
|
|
12
|
+
} as unknown as Client;
|
|
13
|
+
|
|
14
|
+
const businessId = 'ed539d7d-d815-405b-bc00-71008fb1954c';
|
|
15
|
+
const userId = 'b931b17e-214f-4a73-ad94-77a973435768';
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('setDelegatedAdmin', () => {
|
|
22
|
+
test('should call POST with correct URL', async () => {
|
|
23
|
+
postMock.mockResolvedValueOnce({ data: undefined });
|
|
24
|
+
|
|
25
|
+
await setDelegatedAdmin(client, businessId, userId);
|
|
26
|
+
|
|
27
|
+
expect(postMock).toHaveBeenCalledWith(
|
|
28
|
+
`/boapi/proxy/business/fleets/FLEET_ID/business/${businessId}/user/${userId}/delegatedAdmin`
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('should throw for invalid businessId', async () => {
|
|
33
|
+
await expect(setDelegatedAdmin(client, 'not-a-uuid', userId)).rejects.toThrow(TypeError);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('should throw for invalid userId', async () => {
|
|
37
|
+
await expect(setDelegatedAdmin(client, businessId, 'not-a-uuid')).rejects.toThrow(TypeError);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should throw for empty businessId', async () => {
|
|
41
|
+
await expect(setDelegatedAdmin(client, '', userId)).rejects.toThrow(TypeError);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('should throw for empty userId', async () => {
|
|
45
|
+
await expect(setDelegatedAdmin(client, businessId, '')).rejects.toThrow(TypeError);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('removeDelegatedAdmin', () => {
|
|
50
|
+
test('should call DELETE with correct URL', async () => {
|
|
51
|
+
deleteMock.mockResolvedValueOnce({ data: undefined });
|
|
52
|
+
|
|
53
|
+
await removeDelegatedAdmin(client, businessId, userId);
|
|
54
|
+
|
|
55
|
+
expect(deleteMock).toHaveBeenCalledWith(
|
|
56
|
+
`/boapi/proxy/business/fleets/FLEET_ID/business/${businessId}/user/${userId}/delegatedAdmin`
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('should throw for invalid businessId', async () => {
|
|
61
|
+
await expect(removeDelegatedAdmin(client, 'not-a-uuid', userId)).rejects.toThrow(TypeError);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('should throw for invalid userId', async () => {
|
|
65
|
+
await expect(removeDelegatedAdmin(client, businessId, 'not-a-uuid')).rejects.toThrow(TypeError);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
const uuidSchema = z.string().trim().min(1).uuid();
|
|
5
|
+
|
|
6
|
+
export const setDelegatedAdmin = async (client: Client, businessId: string, userId: string): Promise<void> => {
|
|
7
|
+
const parsedBusinessId = uuidSchema.safeParse(businessId);
|
|
8
|
+
const parsedUserId = uuidSchema.safeParse(userId);
|
|
9
|
+
if (!parsedBusinessId.success || !parsedUserId.success) {
|
|
10
|
+
throw new TypeError('Invalid args', {
|
|
11
|
+
cause: [...(parsedBusinessId.error?.issues ?? []), ...(parsedUserId.error?.issues ?? [])],
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
await client.post<void>(
|
|
16
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business/${parsedBusinessId.data}/user/${parsedUserId.data}/delegatedAdmin`
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const removeDelegatedAdmin = async (client: Client, businessId: string, userId: string): Promise<void> => {
|
|
21
|
+
const parsedBusinessId = uuidSchema.safeParse(businessId);
|
|
22
|
+
const parsedUserId = uuidSchema.safeParse(userId);
|
|
23
|
+
if (!parsedBusinessId.success || !parsedUserId.success) {
|
|
24
|
+
throw new TypeError('Invalid args', {
|
|
25
|
+
cause: [...(parsedBusinessId.error?.issues ?? []), ...(parsedUserId.error?.issues ?? [])],
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await client.delete<void>(
|
|
30
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business/${parsedBusinessId.data}/user/${parsedUserId.data}/delegatedAdmin`
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { setBusinessOwner, removeBusinessOwner } from './businessOwner';
|
|
4
|
+
|
|
5
|
+
describe('businessOwner', () => {
|
|
6
|
+
const postMock = vi.fn();
|
|
7
|
+
const deleteMock = vi.fn();
|
|
8
|
+
const client = {
|
|
9
|
+
post: postMock,
|
|
10
|
+
delete: deleteMock,
|
|
11
|
+
clientOptions: { fleetId: 'FLEET_ID' },
|
|
12
|
+
} as unknown as Client;
|
|
13
|
+
|
|
14
|
+
const businessId = 'ed539d7d-d815-405b-bc00-71008fb1954c';
|
|
15
|
+
const userId = 'b931b17e-214f-4a73-ad94-77a973435768';
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('setBusinessOwner', () => {
|
|
22
|
+
test('should call POST with correct URL', async () => {
|
|
23
|
+
postMock.mockResolvedValueOnce({ data: undefined });
|
|
24
|
+
|
|
25
|
+
await setBusinessOwner(client, businessId, userId);
|
|
26
|
+
|
|
27
|
+
expect(postMock).toHaveBeenCalledWith(
|
|
28
|
+
`/boapi/proxy/business/fleets/FLEET_ID/business/${businessId}/user/${userId}/owner`
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('should throw for invalid businessId', async () => {
|
|
33
|
+
await expect(setBusinessOwner(client, 'not-a-uuid', userId)).rejects.toThrow(TypeError);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('should throw for invalid userId', async () => {
|
|
37
|
+
await expect(setBusinessOwner(client, businessId, 'not-a-uuid')).rejects.toThrow(TypeError);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should throw for empty businessId', async () => {
|
|
41
|
+
await expect(setBusinessOwner(client, '', userId)).rejects.toThrow(TypeError);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('should throw for empty userId', async () => {
|
|
45
|
+
await expect(setBusinessOwner(client, businessId, '')).rejects.toThrow(TypeError);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('removeBusinessOwner', () => {
|
|
50
|
+
test('should call DELETE with correct URL', async () => {
|
|
51
|
+
deleteMock.mockResolvedValueOnce({ data: undefined });
|
|
52
|
+
|
|
53
|
+
await removeBusinessOwner(client, businessId, userId);
|
|
54
|
+
|
|
55
|
+
expect(deleteMock).toHaveBeenCalledWith(
|
|
56
|
+
`/boapi/proxy/business/fleets/FLEET_ID/business/${businessId}/user/${userId}/owner`
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('should throw for invalid businessId', async () => {
|
|
61
|
+
await expect(removeBusinessOwner(client, 'not-a-uuid', userId)).rejects.toThrow(TypeError);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('should throw for invalid userId', async () => {
|
|
65
|
+
await expect(removeBusinessOwner(client, businessId, 'not-a-uuid')).rejects.toThrow(TypeError);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
const uuidSchema = z.string().trim().min(1).uuid();
|
|
5
|
+
|
|
6
|
+
export const setBusinessOwner = async (client: Client, businessId: string, userId: string): Promise<void> => {
|
|
7
|
+
const parsedBusinessId = uuidSchema.safeParse(businessId);
|
|
8
|
+
const parsedUserId = uuidSchema.safeParse(userId);
|
|
9
|
+
if (!parsedBusinessId.success || !parsedUserId.success) {
|
|
10
|
+
throw new TypeError('Invalid args', {
|
|
11
|
+
cause: [...(parsedBusinessId.error?.issues ?? []), ...(parsedUserId.error?.issues ?? [])],
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
await client.post<void>(
|
|
16
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business/${parsedBusinessId.data}/user/${parsedUserId.data}/owner`
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const removeBusinessOwner = async (client: Client, businessId: string, userId: string): Promise<void> => {
|
|
21
|
+
const parsedBusinessId = uuidSchema.safeParse(businessId);
|
|
22
|
+
const parsedUserId = uuidSchema.safeParse(userId);
|
|
23
|
+
if (!parsedBusinessId.success || !parsedUserId.success) {
|
|
24
|
+
throw new TypeError('Invalid args', {
|
|
25
|
+
cause: [...(parsedBusinessId.error?.issues ?? []), ...(parsedUserId.error?.issues ?? [])],
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await client.delete<void>(
|
|
30
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business/${parsedBusinessId.data}/user/${parsedUserId.data}/owner`
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export type ChargeBusinessProductBody = {
|
|
5
|
+
productId: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const bodySchema = z.object({
|
|
9
|
+
productId: z.string().trim().min(1),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const chargeBusinessProduct = async (
|
|
13
|
+
client: Client,
|
|
14
|
+
businessId: string,
|
|
15
|
+
body: ChargeBusinessProductBody
|
|
16
|
+
): Promise<void> => {
|
|
17
|
+
const parsedId = z.string().trim().min(1).uuid().safeParse(businessId);
|
|
18
|
+
if (!parsedId.success) {
|
|
19
|
+
throw new TypeError('Invalid args', { cause: parsedId.error.issues });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const result = bodySchema.safeParse(body);
|
|
23
|
+
if (!result.success) {
|
|
24
|
+
throw new TypeError('Invalid args', { cause: result.error.issues });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await client.post<void>(
|
|
28
|
+
`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business/${parsedId.data}/product`,
|
|
29
|
+
result.data
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { createBusiness, CreateBusinessBody } from './createBusiness';
|
|
4
|
+
|
|
5
|
+
describe('createBusiness', () => {
|
|
6
|
+
const postMock = vi.fn();
|
|
7
|
+
const client = {
|
|
8
|
+
post: postMock,
|
|
9
|
+
clientOptions: {
|
|
10
|
+
fleetId: 'FLEET_ID',
|
|
11
|
+
},
|
|
12
|
+
} as unknown as Client;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const validBody: CreateBusinessBody = {
|
|
19
|
+
name: 'Acme Corp',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
test('should create a business with valid body', async () => {
|
|
23
|
+
const mockResponse = { id: 'business-uuid', name: 'Acme Corp', status: 'ACTIVE' };
|
|
24
|
+
postMock.mockResolvedValueOnce({ data: mockResponse });
|
|
25
|
+
|
|
26
|
+
const result = await createBusiness(client, validBody);
|
|
27
|
+
|
|
28
|
+
expect(result).toEqual(mockResponse);
|
|
29
|
+
expect(postMock).toHaveBeenCalledWith(
|
|
30
|
+
'/boapi/proxy/business/fleets/FLEET_ID/business',
|
|
31
|
+
validBody
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('should throw for empty name', async () => {
|
|
36
|
+
const body: CreateBusinessBody = { name: '' };
|
|
37
|
+
await expect(createBusiness(client, body)).rejects.toThrow(TypeError);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should throw for whitespace-only name', async () => {
|
|
41
|
+
const body: CreateBusinessBody = { name: ' ' };
|
|
42
|
+
await expect(createBusiness(client, body)).rejects.toThrow(TypeError);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should throw for name exceeding 255 characters', async () => {
|
|
46
|
+
const body: CreateBusinessBody = { name: 'a'.repeat(256) };
|
|
47
|
+
await expect(createBusiness(client, body)).rejects.toThrow(TypeError);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('should throw for missing name', async () => {
|
|
51
|
+
const body = {} as CreateBusinessBody;
|
|
52
|
+
await expect(createBusiness(client, body)).rejects.toThrow(TypeError);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { Business } from './types';
|
|
5
|
+
|
|
6
|
+
export type CreateBusinessBody = {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const createBusinessBodySchema = z.object({
|
|
11
|
+
name: z.string().trim().min(1).max(255),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const createBusiness = async (client: Client, body: CreateBusinessBody): Promise<Business> => {
|
|
15
|
+
const result = createBusinessBodySchema.safeParse(body);
|
|
16
|
+
if (!result.success) {
|
|
17
|
+
throw new TypeError('Invalid args', { cause: result.error.issues });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return client
|
|
21
|
+
.post<Business>(`/boapi/proxy/business/fleets/${client.clientOptions.fleetId}/business`, result.data)
|
|
22
|
+
.then(({ data }) => data);
|
|
23
|
+
};
|