Skip to content

Commit b9ac70a

Browse files
Unsubscribe from Ongoing Merchant Monitoring (#2799)
* feat: unsubscribe from ongoing merchant monitoring * feat: finished patch business by id endpoint * feat: pr comments fixes
1 parent 1502528 commit b9ac70a

File tree

6 files changed

+278
-21
lines changed

6 files changed

+278
-21
lines changed

services/workflows-service/src/business/business.controller.external.ts

100644100755
Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { ApiNestedQuery } from '@/common/decorators/api-nested-query.decorator';
22
import * as common from '@nestjs/common';
33
import { Param } from '@nestjs/common';
44
import * as swagger from '@nestjs/swagger';
5+
import { ApiBearerAuth, ApiExcludeEndpoint } from '@nestjs/swagger';
56
import { plainToClass } from 'class-transformer';
67
import type { Request } from 'express';
78
import * as errors from '../errors';
8-
// import * as nestAccessControl from 'nest-access-control';
99
import { BusinessFindManyArgs } from './dtos/business-find-many-args';
1010
import { BusinessWhereUniqueInput } from './dtos/business-where-unique-input';
1111
import { BusinessModel } from './business.model';
@@ -23,13 +23,19 @@ import { UseCustomerAuthGuard } from '@/common/decorators/use-customer-auth-guar
2323
import { ProjectIds } from '@/common/decorators/project-ids.decorator';
2424
import type { TProjectId, TProjectIds } from '@/types';
2525
import { CurrentProject } from '@/common/decorators/current-project.decorator';
26+
import { BusinessPatchDto } from '@/business/dtos/business.patch.dto';
27+
import { BusinessDto } from '@/business/dtos/business.dto';
28+
import { PrismaService } from '@/prisma/prisma.service';
29+
import { ARRAY_MERGE_OPTION } from '@ballerine/workflow-core';
2630

31+
@ApiBearerAuth()
2732
@swagger.ApiTags('Businesses')
2833
@common.Controller('external/businesses')
2934
export class BusinessControllerExternal {
3035
constructor(
31-
protected readonly service: BusinessService,
32-
protected readonly workflowService: WorkflowService, // @nestAccessControl.InjectRolesBuilder() // protected readonly rolesBuilder: nestAccessControl.RolesBuilder,
36+
protected readonly prismaService: PrismaService,
37+
protected readonly businessService: BusinessService,
38+
protected readonly workflowService: WorkflowService,
3339
) {}
3440

3541
@common.Post()
@@ -40,7 +46,7 @@ export class BusinessControllerExternal {
4046
@common.Body() data: BusinessCreateDto,
4147
@CurrentProject() currentProjectId: TProjectId,
4248
): Promise<Pick<BusinessModel, 'id' | 'companyName'>> {
43-
return this.service.create({
49+
return this.businessService.create({
4450
data: {
4551
...data,
4652
legalForm: 'name',
@@ -67,15 +73,15 @@ export class BusinessControllerExternal {
6773
): Promise<BusinessModel[]> {
6874
const args = plainToClass(BusinessFindManyArgs, request.query);
6975

70-
return this.service.list(args, projectIds);
76+
return this.businessService.list(args, projectIds);
7177
}
7278

7379
@UseKeyAuthOrSessionGuard()
7480
@common.Get('/business-information')
7581
async getCompanyInfo(@common.Query() query: BusinessInformation) {
7682
const { jurisdictionCode, vendor, registrationNumber } = query;
7783

78-
return this.service.fetchCompanyInformation({
84+
return this.businessService.fetchCompanyInformation({
7985
registrationNumber,
8086
jurisdictionCode,
8187
vendor,
@@ -92,9 +98,7 @@ export class BusinessControllerExternal {
9298
@ProjectIds() projectIds: TProjectIds,
9399
): Promise<BusinessModel | null> {
94100
try {
95-
const business = await this.service.getById(params.id, {}, projectIds);
96-
97-
return business;
101+
return await this.businessService.getById(params.id, {}, projectIds);
98102
} catch (err) {
99103
if (isRecordNotFoundError(err)) {
100104
throw new errors.NotFoundException(`No resource was found for ${JSON.stringify(params)}`);
@@ -105,13 +109,14 @@ export class BusinessControllerExternal {
105109
}
106110

107111
@common.Put(':id')
112+
@ApiExcludeEndpoint()
108113
@UseCustomerAuthGuard()
109114
async update(
110115
@common.Param('id') businessId: string,
111116
@common.Body() data: BusinessUpdateDto,
112117
@CurrentProject() currentProjectId: TProjectId,
113118
) {
114-
return this.service.updateById(businessId, {
119+
return this.businessService.updateById(businessId, {
115120
data: {
116121
companyName: data.companyName,
117122
address: data.address,
@@ -127,6 +132,75 @@ export class BusinessControllerExternal {
127132
});
128133
}
129134

135+
@common.Patch(':id')
136+
@UseCustomerAuthGuard()
137+
@swagger.ApiForbiddenResponse()
138+
@swagger.ApiOkResponse({ type: BusinessDto })
139+
@swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
140+
async patch(
141+
@common.Param('id') businessId: string,
142+
@common.Body() data: BusinessPatchDto,
143+
@CurrentProject() currentProjectId: TProjectId,
144+
) {
145+
const {
146+
documents,
147+
shareholderStructure,
148+
additionalInfo,
149+
bankInformation,
150+
address,
151+
metadata,
152+
...restOfData
153+
} = data;
154+
155+
return await this.prismaService.$transaction(async transaction => {
156+
try {
157+
// Validating the business exists
158+
await this.businessService.getById(businessId, { select: { metadata: true } }, [
159+
currentProjectId,
160+
]);
161+
162+
if (metadata) {
163+
const stringifiedMetadata = JSON.stringify(metadata);
164+
165+
await transaction.$executeRaw`
166+
UPDATE "Business"
167+
SET "metadata" = jsonb_deep_merge_with_options(
168+
COALESCE("metadata", '{}'::jsonb),
169+
${stringifiedMetadata}::jsonb,
170+
${ARRAY_MERGE_OPTION.BY_INDEX}
171+
)
172+
WHERE "id" = ${businessId} AND "projectId" = ${currentProjectId};
173+
`;
174+
}
175+
176+
return this.businessService.updateById(
177+
businessId,
178+
{
179+
data: {
180+
...restOfData,
181+
documents: documents ? JSON.stringify(documents) : undefined,
182+
additionalInfo: additionalInfo ? JSON.stringify(additionalInfo) : undefined,
183+
bankInformation: bankInformation ? JSON.stringify(bankInformation) : undefined,
184+
address: address ? JSON.stringify(address) : undefined,
185+
shareholderStructure:
186+
shareholderStructure && shareholderStructure.length
187+
? JSON.stringify(shareholderStructure)
188+
: undefined,
189+
projectId: currentProjectId,
190+
},
191+
},
192+
transaction,
193+
);
194+
} catch (error) {
195+
if (isRecordNotFoundError(error)) {
196+
throw new errors.NotFoundException(`No business was found for id "${businessId}"`);
197+
}
198+
199+
throw error;
200+
}
201+
});
202+
}
203+
130204
// curl -v http://localhost:3000/api/v1/external/businesses/:businessId/workflows
131205
@common.Get('/:businessId/workflows')
132206
@swagger.ApiOkResponse({ type: [WorkflowDefinitionModel] })

services/workflows-service/src/business/business.repository.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import { ValidationError } from '@/errors';
1111
@Injectable()
1212
export class BusinessRepository {
1313
constructor(
14-
protected readonly prisma: PrismaService,
14+
protected readonly prismaService: PrismaService,
1515
protected readonly scopeService: ProjectScopeService,
1616
) {}
1717

1818
async create<T extends Prisma.BusinessCreateArgs>(
1919
args: Prisma.SelectSubset<T, Prisma.BusinessCreateArgs>,
20-
transaction: PrismaClient | PrismaTransaction = this.prisma,
20+
transaction: PrismaClient | PrismaTransaction = this.prismaService,
2121
) {
2222
const result = BusinessCreateInputSchema.safeParse(args.data);
2323

@@ -35,15 +35,17 @@ export class BusinessRepository {
3535
args: Prisma.SelectSubset<T, Prisma.BusinessFindManyArgs>,
3636
projectIds: TProjectIds,
3737
) {
38-
return await this.prisma.business.findMany(this.scopeService.scopeFindMany(args, projectIds));
38+
return await this.prismaService.business.findMany(
39+
this.scopeService.scopeFindMany(args, projectIds),
40+
);
3941
}
4042

4143
async findById<T extends Omit<Prisma.BusinessFindFirstOrThrowArgs, 'where'>>(
4244
id: string,
4345
args: Prisma.SelectSubset<T, Omit<Prisma.BusinessFindFirstOrThrowArgs, 'where'>>,
4446
projectIds: TProjectIds,
4547
) {
46-
return await this.prisma.business.findFirstOrThrow(
48+
return await this.prismaService.business.findFirstOrThrow(
4749
this.scopeService.scopeFindFirst(
4850
{
4951
where: { id },
@@ -58,7 +60,7 @@ export class BusinessRepository {
5860
id: string,
5961
args: Prisma.SelectSubset<T, Omit<Prisma.BusinessFindUniqueOrThrowArgs, 'where'>>,
6062
) {
61-
return await this.prisma.business.findUniqueOrThrow({
63+
return await this.prismaService.business.findUniqueOrThrow({
6264
where: { id },
6365
...args,
6466
});
@@ -69,7 +71,7 @@ export class BusinessRepository {
6971
projectIds: TProjectIds,
7072
args?: Prisma.SelectSubset<T, Omit<Prisma.BusinessFindFirstArgs, 'where'>>,
7173
) {
72-
return await this.prisma.business.findFirst(
74+
return await this.prismaService.business.findFirst(
7375
this.scopeService.scopeFindFirst(
7476
{
7577
where: { correlationId: id },
@@ -82,7 +84,7 @@ export class BusinessRepository {
8284

8385
async getCorrelationIdById(id: string, projectIds: TProjectIds): Promise<string | null> {
8486
return (
85-
await this.prisma.business.findFirstOrThrow(
87+
await this.prismaService.business.findFirstOrThrow(
8688
this.scopeService.scopeFindFirst(
8789
{
8890
where: { id },
@@ -97,7 +99,7 @@ export class BusinessRepository {
9799
async updateById<T extends Omit<Prisma.BusinessUpdateArgs, 'where'>>(
98100
id: string,
99101
args: Prisma.SelectSubset<T, Omit<Prisma.BusinessUpdateArgs, 'where'>>,
100-
transaction: PrismaClient | PrismaTransaction = this.prisma,
102+
transaction: PrismaClient | PrismaTransaction = this.prismaService,
101103
): Promise<BusinessModel> {
102104
return await transaction.business.update({
103105
where: { id },

services/workflows-service/src/business/business.service.ts

100644100755
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,12 @@ export class BusinessService {
5858
return await this.repository.findByCorrelationId(correlationId, projectids, args);
5959
}
6060

61-
async updateById(id: string, args: Parameters<BusinessRepository['updateById']>[1]) {
62-
return await this.repository.updateById(id, args);
61+
async updateById(
62+
id: string,
63+
args: Parameters<BusinessRepository['updateById']>[1],
64+
transaction?: PrismaTransaction,
65+
) {
66+
return await this.repository.updateById(id, args, transaction);
6367
}
6468

6569
async fetchCompanyInformation({
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { IsDate, IsString } from 'class-validator';
2+
import { ApiProperty } from '@nestjs/swagger';
3+
import { BusinessPatchDto } from './business.patch.dto';
4+
import { Type } from 'class-transformer';
5+
6+
export class BusinessDto extends BusinessPatchDto {
7+
@ApiProperty({ type: String, required: true })
8+
@IsString()
9+
id!: string;
10+
11+
@ApiProperty({
12+
required: true,
13+
})
14+
@IsDate()
15+
@Type(() => Date)
16+
createdAt!: Date;
17+
18+
@ApiProperty({
19+
required: true,
20+
})
21+
@IsDate()
22+
@Type(() => Date)
23+
updatedAt!: Date;
24+
25+
@ApiProperty({ type: String, required: true })
26+
@IsString()
27+
projectId!: string;
28+
}

0 commit comments

Comments
 (0)