diff --git a/package-lock.json b/package-lock.json index d03b700..698714a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "axios": "^0.26.0", "bcrypt": "^5.0.1", "class-transformer": "^0.5.1", - "class-validator": "^0.13.2", + "class-validator": "^0.14.0", "dotenv": "^16.0.0", "multer": "^1.4.4", "mysql2": "^2.3.3", @@ -1547,24 +1547,6 @@ "@nestjs/common": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@nestjs/mapped-types": { - "version": "1.0.1", - "license": "MIT", - "peerDependencies": { - "@nestjs/common": "^7.0.8 || ^8.0.0", - "class-transformer": "^0.2.0 || ^0.3.0 || ^0.4.0 || ^0.5.0", - "class-validator": "^0.11.1 || ^0.12.0 || ^0.13.0", - "reflect-metadata": "^0.1.12" - }, - "peerDependenciesMeta": { - "class-transformer": { - "optional": true - }, - "class-validator": { - "optional": true - } - } - }, "node_modules/@nestjs/passport": { "version": "8.2.2", "license": "MIT", @@ -1745,6 +1727,36 @@ } } }, + "node_modules/@nestjs/swagger/node_modules/@nestjs/mapped-types": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-1.0.1.tgz", + "integrity": "sha512-NFvofzSinp00j5rzUd4tf+xi9od6383iY0JP7o0Bnu1fuItAUkWBgc4EKuIQ3D+c2QI3i9pG1kDWAeY27EMGtg==", + "peerDependencies": { + "@nestjs/common": "^7.0.8 || ^8.0.0", + "class-transformer": "^0.2.0 || ^0.3.0 || ^0.4.0 || ^0.5.0", + "class-validator": "^0.11.1 || ^0.12.0 || ^0.13.0", + "reflect-metadata": "^0.1.12" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/swagger/node_modules/class-validator": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", + "integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==", + "optional": true, + "peer": true, + "dependencies": { + "libphonenumber-js": "^1.9.43", + "validator": "^13.7.0" + } + }, "node_modules/@nestjs/testing": { "version": "8.4.7", "dev": true, @@ -2176,6 +2188,11 @@ "@types/superagent": "*" } }, + "node_modules/@types/validator": { + "version": "13.7.12", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.12.tgz", + "integrity": "sha512-YVtyAPqpefU+Mm/qqnOANW6IkqKpCSrarcyV269C8MA8Ux0dbkEuQwM/4CjL47kVEM2LgBef/ETfkH+c6+moFA==" + }, "node_modules/@types/yargs": { "version": "16.0.4", "dev": true, @@ -3362,10 +3379,12 @@ "license": "MIT" }, "node_modules/class-validator": { - "version": "0.13.2", - "license": "MIT", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", + "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", "dependencies": { - "libphonenumber-js": "^1.9.43", + "@types/validator": "^13.7.10", + "libphonenumber-js": "^1.10.14", "validator": "^13.7.0" } }, @@ -6468,8 +6487,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.10.13", - "license": "MIT" + "version": "1.10.21", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.21.tgz", + "integrity": "sha512-/udZhx49av2r2gZR/+xXSrwcR8smX/sDNrVpOFrvW+CA26TfYTVZfwb3MIDvmwAYMLs7pXuJjZX0VxxGpqPhsA==" }, "node_modules/lines-and-columns": { "version": "1.2.4", @@ -10323,10 +10343,6 @@ "jsonwebtoken": "8.5.1" } }, - "@nestjs/mapped-types": { - "version": "1.0.1", - "requires": {} - }, "@nestjs/passport": { "version": "8.2.2", "requires": {} @@ -10433,6 +10449,25 @@ "@nestjs/mapped-types": "1.0.1", "lodash": "4.17.21", "path-to-regexp": "3.2.0" + }, + "dependencies": { + "@nestjs/mapped-types": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-1.0.1.tgz", + "integrity": "sha512-NFvofzSinp00j5rzUd4tf+xi9od6383iY0JP7o0Bnu1fuItAUkWBgc4EKuIQ3D+c2QI3i9pG1kDWAeY27EMGtg==", + "requires": {} + }, + "class-validator": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", + "integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==", + "optional": true, + "peer": true, + "requires": { + "libphonenumber-js": "^1.9.43", + "validator": "^13.7.0" + } + } } }, "@nestjs/testing": { @@ -10765,6 +10800,11 @@ "@types/superagent": "*" } }, + "@types/validator": { + "version": "13.7.12", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.12.tgz", + "integrity": "sha512-YVtyAPqpefU+Mm/qqnOANW6IkqKpCSrarcyV269C8MA8Ux0dbkEuQwM/4CjL47kVEM2LgBef/ETfkH+c6+moFA==" + }, "@types/yargs": { "version": "16.0.4", "dev": true, @@ -11493,9 +11533,12 @@ "version": "0.5.1" }, "class-validator": { - "version": "0.13.2", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", + "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", "requires": { - "libphonenumber-js": "^1.9.43", + "@types/validator": "^13.7.10", + "libphonenumber-js": "^1.10.14", "validator": "^13.7.0" } }, @@ -13511,7 +13554,9 @@ } }, "libphonenumber-js": { - "version": "1.10.13" + "version": "1.10.21", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.21.tgz", + "integrity": "sha512-/udZhx49av2r2gZR/+xXSrwcR8smX/sDNrVpOFrvW+CA26TfYTVZfwb3MIDvmwAYMLs7pXuJjZX0VxxGpqPhsA==" }, "lines-and-columns": { "version": "1.2.4", diff --git a/package.json b/package.json index 10476cb..7f57dde 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "axios": "^0.26.0", "bcrypt": "^5.0.1", "class-transformer": "^0.5.1", - "class-validator": "^0.13.2", + "class-validator": "^0.14.0", "dotenv": "^16.0.0", "multer": "^1.4.4", "mysql2": "^2.3.3", diff --git a/src/user/manage/manage-user.service.ts b/src/user/manage/manage-user.service.ts index 163e06b..757b0b3 100644 --- a/src/user/manage/manage-user.service.ts +++ b/src/user/manage/manage-user.service.ts @@ -14,9 +14,10 @@ import { USER_JOB_REPOSITORY } from 'src/core/repository/user-job/user-job.modul import { Role, UserEntity } from 'src/core/repository/user/user.entity'; import { USER_REPOSITORY } from 'src/core/repository/user/user.module'; import { ApiResponse } from 'src/utils/apiresponse.dto'; -import { Between, In, Repository } from 'typeorm'; +import { Between, DeepPartial, In, Repository } from 'typeorm'; import { ChangeSalesPasswordDto, + DeleteUserAssignRequest, DeleteUserRequest, UpdateUserRequestDto, } from '../user.dto'; @@ -346,22 +347,29 @@ export class ManageUserService { }, }); - if (request.delegatedSalesId === request.salesId) { - throw new BadRequestException( - 'Sales ID yang dihapus sama dengan yang didelegasi', - ); - } - + //jika sales yang akan dihapus tidak ada, maka request tidak valid if (sales === null) { throw new NotFoundException( 'Sales with id ' + request.salesId + ' not found', ); } - //delegate all customer to new sales - const delegatedSales = await this.userRepository.findOne({ + //jika sales yang di assign ada sales yang akan dihapus, maka request tidak valid + if ( + request.reassignList.filter( + (reassignItem: DeleteUserAssignRequest) => + reassignItem.agentId === request.salesId, + ).length > 0 + ) { + throw new BadRequestException( + 'Sales ID yang dihapus sama dengan yang didelegasi', + ); + } + + //ambil data sales yang di delegasikan + const delegatedSales = await this.userRepository.find({ where: { - id: request.delegatedSalesId, + id: In(request.reassignList.map((value) => value.agentId)), }, }); @@ -375,7 +383,7 @@ export class ManageUserService { const customers = await this.customerAgentRepository.find({ where: { agent: { - id: In([sales.id, delegatedSales.id]), + id: In([sales.id, ...delegatedSales.map((value) => value.id)]), }, }, relations: { @@ -384,30 +392,37 @@ export class ManageUserService { }, }); - const salesCustomer: CustomerAgent[] = customers.filter( - (value) => value.agent.id === sales.id, - ); - const delegatedSalesCustomers: CustomerAgent[] = customers.filter( - (value) => value.agent.id === delegatedSales.id, - ); + const newSalesCustomer: DeepPartial[] = []; - for (const customer of salesCustomer) { - //jika delegated sales nya sudah handle si customer itu + for (const assignItem of request.reassignList) { + //jika customer tersebut sudah di assign ke sales yang baru, maka lewati if ( - delegatedSalesCustomers.find( - (value) => value.customer.id === customer.customer.id, - ) !== undefined + customers.find((customer) => { + customer.agent.id === assignItem.agentId && + customer.customer.id === assignItem.customerId; + }) !== undefined ) { - await this.customerAgentRepository.delete(customer.id); - } else { - customer.agent = delegatedSales; - delegatedSalesCustomers.push(customer); + continue; } + + const newSales = customers.find( + (customer) => customer.agent.id === assignItem.agentId, + )?.agent; + const newCustomer = customers.find( + (customer) => customer.agent.id === assignItem.agentId, + )?.customer; + + //simpan ke array dulu, dijadikan satu agar tidak terlalu banyak koneksi ke db + newSalesCustomer.push({ + agent: newSales, + customer: newCustomer, + }); } - await this.customerAgentRepository.save(delegatedSalesCustomers); + //simpan customer dan sales baru ke db + await this.customerAgentRepository.save(newSalesCustomer); - //hapus job + //hapus sales tersebut dari job const userJob = await this.userJobRepository.find({ where: { agent: { @@ -423,17 +438,13 @@ export class ManageUserService { await this.userJobRepository.delete(userJob.map((e) => e.id)); } - sales.movedTo = request.delegatedSalesId; - - await this.userRepository.save(sales); - await this.userRepository.softDelete(sales.id); return >{ success: true, - data: await this.userRepository.findOne({ + data: await this.userRepository.find({ where: { - id: delegatedSales.id, + id: In([...request.reassignList.map((value) => value.agentId)]), }, relations: { customer: { @@ -444,8 +455,7 @@ export class ManageUserService { message: 'Sukses menghapus sales ' + sales.full_name + - ' dan mendelegasikan semua customer ke sales ' + - delegatedSales.full_name, + ' dan mendelegasikan semua customer ke sales ke sales yang sesuai', }; } diff --git a/src/user/user.dto.ts b/src/user/user.dto.ts index 56623ff..9fea1c7 100644 --- a/src/user/user.dto.ts +++ b/src/user/user.dto.ts @@ -58,5 +58,13 @@ export class DeleteUserRequest { salesId: number; @IsNotEmpty() - delegatedSalesId: number; + reassignList: DeleteUserAssignRequest[]; +} + +export class DeleteUserAssignRequest { + @IsNotEmpty() + agentId: number; + + @IsNotEmpty() + customerId: number; }