From f20f4727f6162bf29c7716169f3708597d6d4ca1 Mon Sep 17 00:00:00 2001 From: tikkhun Date: Mon, 1 Dec 2025 23:53:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(area):=20=E9=87=8D=E6=9E=84=E5=8C=BA?= =?UTF-8?q?=E5=9F=9F=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BD=BF=E7=94=A8i18n-iso-?= =?UTF-8?q?countries=E7=AE=A1=E7=90=86=E5=9B=BD=E5=AE=B6=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: 统一将productName字段重命名为name chore: 添加i18n-iso-countries依赖 style: 优化字典名称格式化逻辑 --- package-lock.json | 19 ++++ package.json | 1 + src/controller/area.controller.ts | 66 ++++++----- src/controller/product.controller.ts | 4 +- src/db/seeds/area.seeder.ts | 19 ++-- src/db/seeds/dict.seeder.ts | 5 +- src/dto/area.dto.ts | 43 ++----- src/dto/stock.dto.ts | 6 +- src/entity/area.entity.ts | 40 ++----- src/entity/purchase_order_item.entity.ts | 2 +- src/entity/transfer_item.entity.ts | 2 +- src/service/area.service.ts | 136 ++++++++++------------- src/service/dict.service.ts | 5 +- src/service/product.service.ts | 2 +- src/service/stock.service.ts | 60 +++++----- 15 files changed, 186 insertions(+), 224 deletions(-) diff --git a/package-lock.json b/package-lock.json index 58971a5..529b58c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "class-transformer": "^0.5.1", "csv-parse": "^6.1.0", "dayjs": "^1.11.13", + "i18n-iso-countries": "^7.14.0", "mysql2": "^3.15.3", "nodemailer": "^7.0.5", "npm-check-updates": "^19.1.2", @@ -2044,6 +2045,12 @@ "wrappy": "1" } }, + "node_modules/diacritics": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", + "integrity": "sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==", + "license": "MIT" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2691,6 +2698,18 @@ "node": ">= 0.8" } }, + "node_modules/i18n-iso-countries": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.14.0.tgz", + "integrity": "sha512-nXHJZYtNrfsi1UQbyRqm3Gou431elgLjKl//CYlnBGt5aTWdRPH1PiS2T/p/n8Q8LnqYqzQJik3Q7mkwvLokeg==", + "license": "MIT", + "dependencies": { + "diacritics": "1.3.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/iconv-lite": { "version": "0.7.0", "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.0.tgz", diff --git a/package.json b/package.json index 8ce8aac..1f27fdc 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "class-transformer": "^0.5.1", "csv-parse": "^6.1.0", "dayjs": "^1.11.13", + "i18n-iso-countries": "^7.14.0", "mysql2": "^3.15.3", "nodemailer": "^7.0.5", "npm-check-updates": "^19.1.2", diff --git a/src/controller/area.controller.ts b/src/controller/area.controller.ts index ebfa390..88304e5 100644 --- a/src/controller/area.controller.ts +++ b/src/controller/area.controller.ts @@ -1,15 +1,5 @@ -import { Inject } from '@midwayjs/core'; -import { - Body, - Controller, - Del, - Get, - Param, - Post, - Put, - Query, -} from '@midwayjs/decorator'; +import { Body, Context, Controller, Del, Get, Inject, Param, Post, Put, Query } from '@midwayjs/core'; import { ApiBearerAuth, ApiBody, @@ -22,14 +12,39 @@ import { AreaService } from '../service/area.service'; import { CreateAreaDTO, QueryAreaDTO, UpdateAreaDTO } from '../dto/area.dto'; import { errorResponse, successResponse } from '../utils/response.util'; import { Area } from '../entity/area.entity'; +import * as countries from 'i18n-iso-countries'; @ApiBearerAuth() @ApiTags('Area') -@Controller('/api/area') +@Controller('/area') export class AreaController { + @Inject() + ctx: Context; + @Inject() areaService: AreaService; + @ApiOperation({ summary: '获取国家列表' }) + @ApiOkResponse({ description: '国家列表' }) + @Get('/countries') + async getCountries() { + try { + // 注册中文语言包 + countries.registerLocale(require('i18n-iso-countries/langs/zh.json')); + // 获取所有国家的中文名称 + const countryNames = countries.getNames('zh', { select: 'official' }); + // 格式化为 { code, name } 的数组 + const countryList = Object.keys(countryNames).map(code => ({ + code, + name: countryNames[code], + })); + return successResponse(countryList, '查询成功'); + } catch (error) { + console.log(error); + return errorResponse(error?.message || error); + } + } + @ApiOperation({ summary: '创建区域' }) @ApiBody({ type: CreateAreaDTO }) @ApiOkResponse({ type: Area, description: '成功创建的区域' }) @@ -39,7 +54,8 @@ export class AreaController { const newArea = await this.areaService.createArea(area); return successResponse(newArea, '创建成功'); } catch (error) { - return errorResponse(error.message); + console.log(error); + return errorResponse(error?.message || error); } } @@ -52,7 +68,8 @@ export class AreaController { const updatedArea = await this.areaService.updateArea(id, area); return successResponse(updatedArea, '更新成功'); } catch (error) { - return errorResponse(error.message); + console.log(error); + return errorResponse(error?.message || error); } } @@ -64,7 +81,8 @@ export class AreaController { await this.areaService.deleteArea(id); return successResponse(null, '删除成功'); } catch (error) { - return errorResponse(error.message); + console.log(error); + return errorResponse(error?.message || error); } } @@ -77,19 +95,8 @@ export class AreaController { const { list, total } = await this.areaService.getAreaList(query); return successResponse({ list, total }, '查询成功'); } catch (error) { - return errorResponse(error.message); - } - } - - @ApiOperation({ summary: '获取所有区域' }) - @ApiOkResponse({ type: [Area], description: '所有区域列表' }) - @Get('/all') - async getAllAreas() { - try { - const areas = await this.areaService.getAllAreas(); - return successResponse(areas, '查询成功'); - } catch (error) { - return errorResponse(error.message); + console.log(error); + return errorResponse(error?.message || error); } } @@ -104,7 +111,8 @@ export class AreaController { } return successResponse(area, '查询成功'); } catch (error) { - return errorResponse(error.message); + console.log(error); + return errorResponse(error?.message || error); } } } diff --git a/src/controller/product.controller.ts b/src/controller/product.controller.ts index 50f0e4f..e593cea 100644 --- a/src/controller/product.controller.ts +++ b/src/controller/product.controller.ts @@ -134,9 +134,9 @@ export class ProductController { @ApiOkResponse({ type: ProductRes }) @Put('updateNameCn/:id/:nameCn') - async updateProductNameCn(@Param('id') id: number, @Param('nameCn') nameCn: string) { + async updatenameCn(@Param('id') id: number, @Param('nameCn') nameCn: string) { try { - const data = this.productService.updateProductNameCn(id, nameCn); + const data = this.productService.updatenameCn(id, nameCn); return successResponse(data); } catch (error) { return errorResponse(error?.message || error); diff --git a/src/db/seeds/area.seeder.ts b/src/db/seeds/area.seeder.ts index 5aadff9..eed3091 100644 --- a/src/db/seeds/area.seeder.ts +++ b/src/db/seeds/area.seeder.ts @@ -8,18 +8,21 @@ export default class AreaSeeder implements Seeder { dataSource: DataSource, factoryManager: SeederFactoryManager ): Promise { - const repository = dataSource.getRepository(Area); + const areaRepository = dataSource.getRepository(Area); const areas = [ - { name: '加拿大' }, - { name: '澳大利亚' }, - { name: '欧洲' }, + { name: 'Australia' }, + { name: 'Canada' }, + { name: 'United States' }, + { name: 'Germany' }, + { name: 'Poland' }, ]; - for (const area of areas) { - const existing = await repository.findOne({ where: { name: area.name } }); - if (!existing) { - await repository.insert(area); + for (const areaData of areas) { + const existingArea = await areaRepository.findOne({ where: { name: areaData.name } }); + if (!existingArea) { + const newArea = areaRepository.create(areaData); + await areaRepository.save(newArea); } } } diff --git a/src/db/seeds/dict.seeder.ts b/src/db/seeds/dict.seeder.ts index 7deb17c..37ec8ee 100644 --- a/src/db/seeds/dict.seeder.ts +++ b/src/db/seeds/dict.seeder.ts @@ -10,8 +10,9 @@ export default class DictSeeder implements Seeder { * @returns 格式化后的名称 */ private formatName(name: string): string { - // 将空格、下划线、点统一转换成中划线,并转为小写 - return String(name).replace(/[_\s.]+/g, '-').toLowerCase(); + // return String(name).replace(/[\_\s.]+/g, '-').toLowerCase(); + // 只替换空格和下划线 + return String(name).replace(/[\_\s]+/g, '-').toLowerCase(); } public async run( diff --git a/src/dto/area.dto.ts b/src/dto/area.dto.ts index 9bb8b82..9004e30 100644 --- a/src/dto/area.dto.ts +++ b/src/dto/area.dto.ts @@ -2,47 +2,28 @@ import { ApiProperty } from '@midwayjs/swagger'; import { Rule, RuleType } from '@midwayjs/validate'; -// 创建区域的数据传输对象 export class CreateAreaDTO { - @ApiProperty({ type: 'string', description: '区域名称', example: '欧洲' }) + @ApiProperty({ description: '编码' }) @Rule(RuleType.string().required()) - name: string; - - @ApiProperty({ type: 'number', description: '纬度', example: 48.8566, required: false }) - @Rule(RuleType.number().min(-90).max(90).allow(null)) - latitude?: number; - - @ApiProperty({ type: 'number', description: '经度', example: 2.3522, required: false }) - @Rule(RuleType.number().min(-180).max(180).allow(null)) - longitude?: number; + code: string; } -// 更新区域的数据传输对象 export class UpdateAreaDTO { - @ApiProperty({ type: 'string', description: '区域名称', example: '欧洲' }) + @ApiProperty({ description: '编码', required: false }) @Rule(RuleType.string()) - name?: string; - - @ApiProperty({ type: 'number', description: '纬度', example: 48.8566, required: false }) - @Rule(RuleType.number().min(-90).max(90).allow(null)) - latitude?: number; - - @ApiProperty({ type: 'number', description: '经度', example: 2.3522, required: false }) - @Rule(RuleType.number().min(-180).max(180).allow(null)) - longitude?: number; + code?: string; } -// 查询区域的数据传输对象 export class QueryAreaDTO { - @ApiProperty({ type: 'number', description: '当前页码', example: 1 }) - @Rule(RuleType.number().min(1).default(1)) - currentPage: number; + @ApiProperty({ description: '当前页', required: false, default: 1 }) + @Rule(RuleType.number().integer().min(1).default(1)) + currentPage?: number; - @ApiProperty({ type: 'number', description: '每页数量', example: 10 }) - @Rule(RuleType.number().min(1).max(100).default(10)) - pageSize: number; + @ApiProperty({ description: '每页数量', required: false, default: 10 }) + @Rule(RuleType.number().integer().min(1).default(10)) + pageSize?: number; - @ApiProperty({ type: 'string', description: '区域名称', example: '欧洲' }) + @ApiProperty({ description: '关键词(名称或编码)', required: false }) @Rule(RuleType.string()) - name?: string; + keyword?: string; } diff --git a/src/dto/stock.dto.ts b/src/dto/stock.dto.ts index c6b83c1..9585d6d 100644 --- a/src/dto/stock.dto.ts +++ b/src/dto/stock.dto.ts @@ -20,7 +20,7 @@ export class QueryStockDTO { @ApiProperty() @Rule(RuleType.string()) - productName: string; + name: string; @ApiProperty() @Rule(RuleType.string()) @@ -62,7 +62,7 @@ export class QueryStockRecordDTO { @ApiProperty() @Rule(RuleType.string()) - productName: string; + name: string; @ApiProperty() @Rule(RuleType.string()) @@ -96,7 +96,7 @@ export class QueryPurchaseOrderDTO { export class StockDTO extends Stock { @ApiProperty() @Rule(RuleType.string()) - productName: string; + name: string; @ApiProperty({ type: 'object', diff --git a/src/entity/area.entity.ts b/src/entity/area.entity.ts index 7afaf34..e66de47 100644 --- a/src/entity/area.entity.ts +++ b/src/entity/area.entity.ts @@ -1,43 +1,17 @@ + import { ApiProperty } from '@midwayjs/swagger'; -import { - Column, - CreateDateColumn, - Entity, - PrimaryGeneratedColumn, - UpdateDateColumn, -} from 'typeorm'; +import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; @Entity('area') export class Area { - @ApiProperty({ type: 'number' }) @PrimaryGeneratedColumn() id: number; - @ApiProperty({ type: 'string', description: '区域名称' }) - @Column({ unique: true }) + @ApiProperty({ description: '名称' }) + @Column() name: string; - @ApiProperty({ type: 'number', description: '纬度', required: false }) - @Column({ type: 'decimal', precision: 10, scale: 6, nullable: true }) - latitude?: number; - - @ApiProperty({ type: 'number', description: '经度', required: false }) - @Column({ type: 'decimal', precision: 10, scale: 6, nullable: true }) - longitude?: number; - - @ApiProperty({ - example: '2022-12-12 11:11:11', - description: '创建时间', - required: true, - }) - @CreateDateColumn() - createdAt: Date; - - @ApiProperty({ - example: '2022-12-12 11:11:11', - description: '更新时间', - required: true, - }) - @UpdateDateColumn() - updatedAt: Date; + @ApiProperty({ description: '编码' }) + @Column({ unique: true }) + code: string; } diff --git a/src/entity/purchase_order_item.entity.ts b/src/entity/purchase_order_item.entity.ts index 3a84dbf..4d4b52b 100644 --- a/src/entity/purchase_order_item.entity.ts +++ b/src/entity/purchase_order_item.entity.ts @@ -14,7 +14,7 @@ export class PurchaseOrderItem { @ApiProperty({ type: String }) @Column() - productName: string; + name: string; @ApiProperty({ type: Number }) @Column() diff --git a/src/entity/transfer_item.entity.ts b/src/entity/transfer_item.entity.ts index 45654a1..6c72f54 100644 --- a/src/entity/transfer_item.entity.ts +++ b/src/entity/transfer_item.entity.ts @@ -13,7 +13,7 @@ export class TransferItem { @ApiProperty({ type: String }) @Column() - productName: string; + name: string; @ApiProperty({ type: Number }) @Column() diff --git a/src/service/area.service.ts b/src/service/area.service.ts index fbe2eac..1ac8bf5 100644 --- a/src/service/area.service.ts +++ b/src/service/area.service.ts @@ -1,102 +1,80 @@ import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; -import { Repository } from 'typeorm'; +import { Like, Repository } from 'typeorm'; import { Area } from '../entity/area.entity'; import { CreateAreaDTO, QueryAreaDTO, UpdateAreaDTO } from '../dto/area.dto'; +import * as countries from 'i18n-iso-countries'; @Provide() export class AreaService { @InjectEntityModel(Area) - areaModel: Repository; + areaRepository: Repository; - /** - * 创建区域 - * @param params 创建参数 - */ - async createArea(params: CreateAreaDTO) { - // 检查区域名称是否已存在 - const existing = await this.areaModel.findOne({ where: { name: params.name } }); - if (existing) { - throw new Error('区域名称已存在'); - } - const area = new Area(); - area.name = params.name; - if (params.latitude !== undefined) { - area.latitude = params.latitude; - } - if (params.longitude !== undefined) { - area.longitude = params.longitude; - } - return await this.areaModel.save(area); + constructor() { + // 在服务初始化时注册中文语言包 + countries.registerLocale(require('i18n-iso-countries/langs/zh.json')); } - /** - * 更新区域 - * @param id 区域ID - * @param params 更新参数 - */ - async updateArea(id: number, params: UpdateAreaDTO) { - const area = await this.areaModel.findOneBy({ id }); - if (!area) { - throw new Error('区域不存在'); - } - if (params.name) { - // 检查新的区域名称是否已存在 - const existing = await this.areaModel.findOne({ where: { name: params.name } }); - if (existing && existing.id !== id) { - throw new Error('区域名称已存在'); - } - area.name = params.name; - } - if (params.latitude !== undefined) { - area.latitude = params.latitude; - } - if (params.longitude !== undefined) { - area.longitude = params.longitude; - } - return await this.areaModel.save(area); - } - - /** - * 删除区域 - * @param id 区域ID - */ - async deleteArea(id: number) { - const result = await this.areaModel.delete(id); - return result.affected > 0; - } - - /** - * 获取区域列表(分页) - * @param query 查询参数 - */ async getAreaList(query: QueryAreaDTO) { - const { currentPage, pageSize, name } = query; - const [list, total] = await this.areaModel.findAndCount({ - where: name ? { name } : {}, + const { currentPage = 1, pageSize = 10, keyword = '' } = query; + const [list, total] = await this.areaRepository.findAndCount({ + where: [{ name: Like(`%${keyword}%`) }, { code: Like(`%${keyword}%`) }], skip: (currentPage - 1) * pageSize, take: pageSize, - order: { - id: 'DESC', - }, }); - return { list, total }; } - /** - * 获取所有区域 - */ - async getAllAreas() { - return await this.areaModel.find(); + async getAreaById(id: number) { + return this.areaRepository.findOne({ where: { id } }); } - /** - * 根据ID获取区域详情 - * @param id 区域ID - */ - async getAreaById(id: number) { - return await this.areaModel.findOneBy({ id }); + async createArea(createAreaDTO: CreateAreaDTO) { + // 根据 code 获取国家中文名称 + const name = countries.getName(createAreaDTO.code, 'zh', { + select: 'official', + }); + + // 如果找不到对应的国家,则抛出错误 + if (!name) { + throw new Error(`无效的国家代码: ${createAreaDTO.code}`); + } + + const area = new Area(); + area.name = name; + area.code = createAreaDTO.code; + return this.areaRepository.save(area); + } + + async updateArea(id: number, updateAreaDTO: UpdateAreaDTO) { + const area = await this.getAreaById(id); + if (!area) { + return null; + } + + // 如果 code 发生变化,则更新 name + if (updateAreaDTO.code && updateAreaDTO.code !== area.code) { + const name = countries.getName(updateAreaDTO.code, 'zh', { + select: 'official', + }); + + if (!name) { + throw new Error(`无效的国家代码: ${updateAreaDTO.code}`); + } + area.name = name; + area.code = updateAreaDTO.code; + } + + return this.areaRepository.save(area); + } + + async deleteArea(id: number) { + const area = await this.getAreaById(id); + if (!area) { + return false; + } + await this.areaRepository.remove(area); + return true; } } diff --git a/src/service/dict.service.ts b/src/service/dict.service.ts index f18316a..1169287 100644 --- a/src/service/dict.service.ts +++ b/src/service/dict.service.ts @@ -9,7 +9,7 @@ import * as xlsx from 'xlsx'; @Provide() export class DictService { - + @InjectEntityModel(Dict) dictModel: Repository; @@ -18,7 +18,8 @@ export class DictService { // 格式化名称为 kebab-case private formatName(name: string): string { - return String(name).replace(/[_\s.]+/g, '-').toLowerCase(); + // 只替换空格和下划线 + return String(name).replace(/[_\s]+/g, '-').toLowerCase(); } // 生成并返回字典的XLSX模板 diff --git a/src/service/product.service.ts b/src/service/product.service.ts index 49fb015..1074650 100644 --- a/src/service/product.service.ts +++ b/src/service/product.service.ts @@ -509,7 +509,7 @@ export class ProductService { // 重复定义的 getProductList 已合并到前面的实现(中文注释:移除重复) - async updateProductNameCn(id: number, nameCn: string): Promise { + async updatenameCn(id: number, nameCn: string): Promise { // 确认产品是否存在 const product = await this.productModel.findOneBy({ id }); if (!product) { diff --git a/src/service/stock.service.ts b/src/service/stock.service.ts index a0b899c..44d688f 100644 --- a/src/service/stock.service.ts +++ b/src/service/stock.service.ts @@ -167,7 +167,7 @@ export class StockService { qb .select([ 'poi.purchaseOrderId AS purchaseOrderId', - "JSON_ARRAYAGG(JSON_OBJECT('id', poi.id, 'productName', poi.productName,'sku', poi.sku, 'quantity', poi.quantity, 'price', poi.price)) AS items", + "JSON_ARRAYAGG(JSON_OBJECT('id', poi.id, 'name', poi.name,'sku', poi.sku, 'quantity', poi.quantity, 'price', poi.price)) AS items", ]) .from(PurchaseOrderItem, 'poi') .groupBy('poi.purchaseOrderId'), @@ -240,9 +240,9 @@ export class StockService { // 获取库存列表 async getStocks(query: QueryStockDTO) { - const { current = 1, pageSize = 10, productName, sku } = query; - const nameKeywords = productName - ? productName.split(' ').filter(Boolean) + const { current = 1, pageSize = 10, name, sku } = query; + const nameKeywords = name + ? name.split(' ').filter(Boolean) : []; let queryBuilder = this.stockModel @@ -250,8 +250,8 @@ export class StockService { .select([ // 'stock.id as id', 'stock.sku as sku', - 'product.name as productName', - 'product.nameCn as productNameCn', + 'product.name as name', + 'product.nameCn as nameCn', 'JSON_ARRAYAGG(JSON_OBJECT("id", stock.stockPointId, "quantity", stock.quantity)) as stockPoint', 'MIN(stock.updatedAt) as updatedAt', 'MAX(stock.createdAt) as createdAt', @@ -264,33 +264,29 @@ export class StockService { .createQueryBuilder('stock') .select('COUNT(DISTINCT stock.sku)', 'count') .leftJoin(Product, 'product', 'product.sku = stock.sku'); - if (sku) { - queryBuilder.andWhere('stock.sku = :sku', { sku }); - totalQueryBuilder.andWhere('stock.sku = :sku', { sku }); - } - if (nameKeywords.length) { - nameKeywords.forEach((name, index) => { - queryBuilder.andWhere( - `EXISTS ( - SELECT 1 FROM product p - WHERE p.sku = stock.sku - AND p.name LIKE :name${index} - )`, - { [`name${index}`]: `%${name}%` } - ); - totalQueryBuilder.andWhere( - `EXISTS ( - SELECT 1 FROM product p - WHERE p.sku = stock.sku - AND p.name LIKE :name${index} - )`, - { [`name${index}`]: `%${name}%` } - ); + if (sku || nameKeywords.length) { + const conditions = []; + if (sku) { + conditions.push(`stock.sku LIKE :sku`); + } + if (nameKeywords.length) { + nameKeywords.forEach((name, index) => { + conditions.push(`product.name LIKE :name${index}`); + }); + } + const whereClause = conditions.join(' OR '); + queryBuilder.andWhere(`(${whereClause})`, { + sku: `%${sku}%`, + ...nameKeywords.reduce((acc, name, index) => ({ ...acc, [`name${index}`]: `%${name}%` }), {}), + }); + totalQueryBuilder.andWhere(`(${whereClause})`, { + sku: `%${sku}%`, + ...nameKeywords.reduce((acc, name, index) => ({ ...acc, [`name${index}`]: `%${name}%` }), {}), }); } if (query.order) { const sortFieldMap: Record = { - productName: 'product.name', + name: 'product.name', sku: 'stock.sku', updatedAt: 'updatedAt', createdAt: 'createdAt', @@ -422,7 +418,7 @@ export class StockService { pageSize = 10, stockPointId, sku, - productName, + name, operationType, startDate, endDate, @@ -447,9 +443,9 @@ export class StockService { 'sp.name as stockPointName', ]) .where(where); - if (productName) + if (name) queryBuilder.andWhere('product.name LIKE :name', { - name: `%${productName}%`, + name: `%${name}%`, }); const items = await queryBuilder .orderBy('stock_record.createdAt', 'DESC')