From e4fc195b8d6e5ff69d79481e67fc6c8730e2af8f Mon Sep 17 00:00:00 2001 From: tikkhun Date: Mon, 1 Dec 2025 10:59:49 +0800 Subject: [PATCH] =?UTF-8?q?refactor(=E5=AE=9E=E4=BD=93=E5=92=8C=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1):=20=E7=BB=9F=E4=B8=80=E5=B0=86productSku=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BAsku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构实体类和服务层代码,将productSku字段统一更名为sku以保持命名一致性 修改涉及库存、订单、采购等多个模块的查询和更新逻辑 同时将产品类型默认值从simple改为single,并优化相关条件判断 --- output.log | 24 +++++++ src/dto/stock.dto.ts | 8 +-- src/entity/product.entity.ts | 10 +-- src/entity/product_stock_component.entity.ts | 2 +- src/entity/purchase_order_item.entity.ts | 2 +- src/entity/stock.entity.ts | 2 +- src/entity/stock_record.entity.ts | 2 +- src/entity/transfer_item.entity.ts | 2 +- src/service/logistics.service.ts | 4 +- src/service/order.service.ts | 2 +- src/service/product.service.ts | 54 +++++++------- src/service/statistics.service.ts | 74 ++++++++++---------- src/service/stock.service.ts | 70 +++++++++--------- 13 files changed, 142 insertions(+), 114 deletions(-) create mode 100644 output.log diff --git a/output.log b/output.log new file mode 100644 index 0000000..db350f0 --- /dev/null +++ b/output.log @@ -0,0 +1,24 @@ + +> my-midway-project@1.0.0 dev +> cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app.js + + +[10:37:17 AM] Starting compilation in watch mode... + + + + + + +[10:37:19 AM] Found 0 errors. Watching for file changes. + +2025-12-01 10:37:20.106 INFO 58678 [SyncProductJob] start job SyncProductJob +2025-12-01 10:37:20.106 INFO 58678 [SyncShipmentJob] start job SyncShipmentJob +2025-12-01 10:37:20.109 INFO 58678 [SyncProductJob] complete job SyncProductJob + +Node.js server started in 732 ms + +➜ Local: http://127.0.0.1:7001/ +➜ Network: http://192.168.5.100:7001/  + +2025-12-01 10:37:20.110 INFO 58678 [SyncShipmentJob] complete job SyncShipmentJob diff --git a/src/dto/stock.dto.ts b/src/dto/stock.dto.ts index 84b2d4e..c6b83c1 100644 --- a/src/dto/stock.dto.ts +++ b/src/dto/stock.dto.ts @@ -24,13 +24,13 @@ export class QueryStockDTO { @ApiProperty() @Rule(RuleType.string()) - productSku: string; + sku: string; @ApiProperty({ description: '按库存点ID排序', required: false }) @Rule(RuleType.number().allow(null)) sortPointId?: number; - @ApiProperty({ description: '排序对象,格式如 { productName: "asc", productSku: "desc" }', required: false }) + @ApiProperty({ description: '排序对象,格式如 { productName: "asc", sku: "desc" }', required: false }) @Rule(RuleType.object().allow(null)) order?: Record; } @@ -58,7 +58,7 @@ export class QueryStockRecordDTO { @ApiProperty() @Rule(RuleType.string()) - productSku: string; + sku: string; @ApiProperty() @Rule(RuleType.string()) @@ -132,7 +132,7 @@ export class UpdateStockDTO { @ApiProperty() @Rule(RuleType.string()) - productSku: string; + sku: string; @ApiProperty() @Rule(RuleType.number()) diff --git a/src/entity/product.entity.ts b/src/entity/product.entity.ts index 06629b5..b8fed9c 100644 --- a/src/entity/product.entity.ts +++ b/src/entity/product.entity.ts @@ -23,6 +23,11 @@ export class Product { @PrimaryGeneratedColumn() id: number; + // 类型 主要用来区分混装和单品 单品死 + @ApiProperty({ description: '类型' }) + @Column({ length: 16, default: 'single' }) + type: string; + @ApiProperty({ example: 'ZYN 6MG WINTERGREEN', description: '产品名称', @@ -49,10 +54,7 @@ export class Product { @ApiProperty({ description: '价格', example: 99.99 }) @Column({ type: 'decimal', precision: 10, scale: 2, default: 0 }) price: number; - // 类型 主要用来区分混装和单品 单品死 - @ApiProperty({ description: '类型' }) - @Column({ length: 16, default: 'simple' }) - type: string; + // 促销价格 @ApiProperty({ description: '促销价格', example: 99.99 }) @Column({ type: 'decimal', precision: 10, scale: 2, default: 0 }) diff --git a/src/entity/product_stock_component.entity.ts b/src/entity/product_stock_component.entity.ts index 3985e88..6e0cbb3 100644 --- a/src/entity/product_stock_component.entity.ts +++ b/src/entity/product_stock_component.entity.ts @@ -14,7 +14,7 @@ export class ProductStockComponent { @ApiProperty({ description: '组件所关联的 SKU', type: 'string' }) @Column({ type: 'varchar', length: 64 }) - productSku: string; + sku: string; @ApiProperty({ type: Number, description: '组成数量' }) @Column({ type: 'int', default: 1 }) diff --git a/src/entity/purchase_order_item.entity.ts b/src/entity/purchase_order_item.entity.ts index 5144ccd..3a84dbf 100644 --- a/src/entity/purchase_order_item.entity.ts +++ b/src/entity/purchase_order_item.entity.ts @@ -10,7 +10,7 @@ export class PurchaseOrderItem { @ApiProperty({ type: String }) @Column() - productSku: string; + sku: string; @ApiProperty({ type: String }) @Column() diff --git a/src/entity/stock.entity.ts b/src/entity/stock.entity.ts index 233cda7..3977830 100644 --- a/src/entity/stock.entity.ts +++ b/src/entity/stock.entity.ts @@ -20,7 +20,7 @@ export class Stock { @ApiProperty({ type: String }) @Column() - productSku: string; + sku: string; @ApiProperty({ type: Number }) @Column() diff --git a/src/entity/stock_record.entity.ts b/src/entity/stock_record.entity.ts index 0d48882..bd6cf81 100644 --- a/src/entity/stock_record.entity.ts +++ b/src/entity/stock_record.entity.ts @@ -20,7 +20,7 @@ export class StockRecord { @ApiProperty({ type: String }) @Column() - productSku: string; + sku: string; @ApiProperty({ type: StockRecordOperationType }) @Column({ type: 'enum', enum: StockRecordOperationType }) diff --git a/src/entity/transfer_item.entity.ts b/src/entity/transfer_item.entity.ts index 312f6dd..45654a1 100644 --- a/src/entity/transfer_item.entity.ts +++ b/src/entity/transfer_item.entity.ts @@ -9,7 +9,7 @@ export class TransferItem { @ApiProperty({ type: String }) @Column() - productSku: string; + sku: string; @ApiProperty({ type: String }) @Column() diff --git a/src/service/logistics.service.ts b/src/service/logistics.service.ts index 0297fd3..a4f2b9d 100644 --- a/src/service/logistics.service.ts +++ b/src/service/logistics.service.ts @@ -527,14 +527,14 @@ export class LogisticsService { const stock = await stockRepo.findOne({ where: { stockPointId: orderShipments[0].stockPointId, - productSku: item.sku, + sku: item.sku, }, }); stock.quantity += item.quantity; await stockRepo.save(stock); await stockRecordRepo.save({ stockPointId: orderShipments[0].stockPointId, - productSku: item.sku, + sku: item.sku, operationType: StockRecordOperationType.IN, quantityChange: item.quantity, operatorId: userId, diff --git a/src/service/order.service.ts b/src/service/order.service.ts index 6bf3aa8..0ad083c 100644 --- a/src/service/order.service.ts +++ b/src/service/order.service.ts @@ -217,7 +217,7 @@ export class OrderService { for (const item of items) { const updateStock = new UpdateStockDTO(); updateStock.stockPointId = stockPointId; - updateStock.productSku = item.sku; + updateStock.sku = item.sku; updateStock.quantityChange = item.quantity; updateStock.operationType = StockRecordOperationType.OUT; updateStock.operatorId = 1; diff --git a/src/service/product.service.ts b/src/service/product.service.ts index 4367ab8..49fb015 100644 --- a/src/service/product.service.ts +++ b/src/service/product.service.ts @@ -177,17 +177,19 @@ export class ProductService { const [items, total] = await qb.getManyAndCount(); // 中文注释:根据类型填充组成信息 - for (const p of items) { - if (p.type === 'simple') { + for (const product of items) { + if (product.type === 'single') { // 中文注释:单品不持久化组成,这里仅返回一个基于 SKU 的虚拟组成 - const comp = new ProductStockComponent(); - comp.productId = p.id; - comp.productSku = p.sku; - comp.quantity = 1; - p.components = [comp]; + const component = new ProductStockComponent(); + component.productId = product.id; + component.sku = product.sku; + component.quantity = 1; + product.components = [component]; } else { // 中文注释:混装商品返回持久化的 SKU 组成 - p.components = await this.productStockComponentModel.find({ where: { productId: p.id } }); + product.components = await this.productStockComponentModel.find({ + where: { productId: product.id }, + }); } } @@ -273,7 +275,7 @@ export class ProductService { product.description = description; product.attributes = resolvedAttributes; // 条件判断(中文注释:设置商品类型,默认 simple) - product.type = (createProductDTO.type as any) || 'simple'; + product.type = (createProductDTO.type as any) || 'single'; // 生成或设置 SKU(中文注释:基于属性字典项的 name 生成) if (sku) { @@ -387,10 +389,10 @@ export class ProductService { let components: ProductStockComponent[] = []; // 条件判断(中文注释:单品 simple 不持久化组成,按 SKU 动态返回单条组成) - if (product.type === 'simple') { + if (product.type === 'single') { const comp = new ProductStockComponent(); comp.productId = productId; - comp.productSku = product.sku; + comp.sku = product.sku; comp.quantity = 1; components = [comp]; } else { @@ -399,14 +401,14 @@ export class ProductService { } // 中文注释:获取所有组件的 SKU 列表 - const skus = components.map(c => c.productSku); + const skus = components.map(c => c.sku); if (skus.length === 0) { return components; } // 中文注释:查询这些 SKU 的库存信息 const stocks = await this.stockModel.find({ - where: { productSku: In(skus) }, + where: { sku: In(skus) }, }); // 中文注释:获取所有相关的库存点 ID @@ -419,12 +421,12 @@ export class ProductService { // 中文注释:将库存信息按 SKU 分组 const stockMap = stocks.reduce((map, stock) => { - if (!map[stock.productSku]) { - map[stock.productSku] = []; + if (!map[stock.sku]) { + map[stock.sku] = []; } const stockPoint = stockPointMap[stock.stockPointId]; if (stockPoint) { - map[stock.productSku].push({ + map[stock.sku].push({ name: stockPoint.name, quantity: stock.quantity, }); @@ -436,7 +438,7 @@ export class ProductService { const componentsWithStock = components.map(comp => { return { ...comp, - stock: stockMap[comp.productSku] || [], + stock: stockMap[comp.sku] || [], }; }); @@ -452,7 +454,7 @@ export class ProductService { const product = await this.productModel.findOne({ where: { id: productId } }); if (!product) throw new Error(`产品 ID ${productId} 不存在`); // 条件判断(中文注释:单品 simple 不允许手动设置组成) - if (product.type === 'simple') { + if (product.type === 'single') { throw new Error('单品无需设置组成'); } @@ -472,7 +474,7 @@ export class ProductService { } const comp = new ProductStockComponent(); comp.productId = productId; - comp.productSku = i.sku; + comp.sku = i.sku; comp.quantity = i.quantity; created.push(await this.productStockComponentModel.save(comp)); } @@ -486,19 +488,19 @@ export class ProductService { if (!product) throw new Error(`产品 ID ${productId} 不存在`); // 中文注释:按 SKU 自动绑定 // 条件判断:simple 类型不持久化组成,直接返回单条基于 SKU 的组成 - if (product.type === 'simple') { + if (product.type === 'single') { const comp = new ProductStockComponent(); comp.productId = productId; - comp.productSku = product.sku; + comp.sku = product.sku; comp.quantity = 1; // 默认数量 1 return [comp]; } // bundle 类型:若不存在则持久化一条基于 SKU 的组成 - const exist = await this.productStockComponentModel.findOne({ where: { productId, productSku: product.sku } }); + const exist = await this.productStockComponentModel.findOne({ where: { productId, sku: product.sku } }); if (!exist) { const comp = new ProductStockComponent(); comp.productId = productId; - comp.productSku = product.sku; + comp.sku = product.sku; comp.quantity = 1; await this.productStockComponentModel.save(comp); } @@ -525,13 +527,13 @@ export class ProductService { if (!product) { throw new Error(`产品 ID ${id} 不存在`); } - const productSku = product.sku; + const sku = product.sku; // 查询 wp_product 表中是否存在与该 SKU 关联的产品 const wpProduct = await this.wpProductModel .createQueryBuilder('wp_product') .where('JSON_CONTAINS(wp_product.constitution, :sku)', { - sku: JSON.stringify({ sku: productSku }), + sku: JSON.stringify({ sku: sku }), }) .getOne(); if (wpProduct) { @@ -541,7 +543,7 @@ export class ProductService { const variation = await this.variationModel .createQueryBuilder('variation') .where('JSON_CONTAINS(variation.constitution, :sku)', { - sku: JSON.stringify({ sku: productSku }), + sku: JSON.stringify({ sku: sku }), }) .getOne(); diff --git a/src/service/statistics.service.ts b/src/service/statistics.service.ts index b7ce60d..f7a026c 100644 --- a/src/service/statistics.service.ts +++ b/src/service/statistics.service.ts @@ -656,10 +656,10 @@ export class StatisticsService { const offset = (current - 1) * pageSize; const countSql = ` WITH product_list AS ( - SELECT DISTINCT s.productSku + SELECT DISTINCT s.sku FROM stock s LEFT JOIN stock_point sp ON s.stockPointId = sp.id - LEFT JOIN product p ON s.productSku = p.sku + LEFT JOIN product p ON s.sku = p.sku WHERE sp.ignore = FALSE ${countnameFilter} ) @@ -674,27 +674,27 @@ export class StatisticsService { const sql = ` WITH stock_summary AS ( SELECT - s.productSku, + s.sku, JSON_ARRAYAGG(JSON_OBJECT('id', sp.id, 'quantity', s.quantity)) AS stockDetails, SUM(s.quantity) AS totalStock, SUM(CASE WHEN sp.inCanada THEN s.quantity ELSE 0 END) AS caTotalStock FROM stock s JOIN stock_point sp ON s.stockPointId = sp.id WHERE sp.ignore = FALSE - GROUP BY s.productSku + GROUP BY s.sku ), transfer_stock AS ( SELECT - ti.productSku, + ti.sku, SUM(ti.quantity) AS transitStock FROM transfer_item ti JOIN transfer t ON ti.transferId = t.id WHERE t.isCancel = FALSE AND t.isArrived = FALSE - GROUP BY ti.productSku + GROUP BY ti.sku ), 30_sales_summary AS ( SELECT - os.sku AS productSku, + os.sku AS sku, SUM(os.quantity) AS totalSales FROM order_sale os JOIN \`order\` o ON os.orderId = o.id @@ -704,7 +704,7 @@ export class StatisticsService { ), 15_sales_summary AS ( SELECT - os.sku AS productSku, + os.sku AS sku, 2 * SUM(os.quantity) AS totalSales FROM order_sale os JOIN \`order\` o ON os.orderId = o.id @@ -714,36 +714,36 @@ export class StatisticsService { ), sales_max_summary AS ( SELECT - s30.productSku AS productSku, + s30.sku AS sku, COALESCE(s30.totalSales, 0) AS totalSales_30, COALESCE(s15.totalSales, 0) AS totalSales_15, GREATEST(COALESCE(s30.totalSales, 0), COALESCE(s15.totalSales, 0)) AS maxSales FROM 30_sales_summary s30 LEFT JOIN 15_sales_summary s15 - ON s30.productSku = s15.productSku + ON s30.sku = s15.sku UNION ALL SELECT - s15.productSku AS productSku, + s15.sku AS sku, 0 AS totalSales_30, COALESCE(s15.totalSales, 0) AS totalSales_15, COALESCE(s15.totalSales, 0) AS maxSales FROM 15_sales_summary s15 LEFT JOIN 30_sales_summary s30 - ON s30.productSku = s15.productSku - WHERE s30.productSku IS NULL + ON s30.sku = s15.sku + WHERE s30.sku IS NULL ), product_name_summary AS ( SELECT - p.sku AS productSku, + p.sku AS sku, COALESCE(MAX(os.name), MAX(p.name)) AS productName FROM product p LEFT JOIN order_sale os ON p.sku = os.sku GROUP BY p.sku ) SELECT - ss.productSku, + ss.sku, ss.stockDetails, COALESCE(ts.transitStock, 0) AS transitStock, (COALESCE(ss.totalStock, 0) + COALESCE(ts.transitStock, 0)) AS totalStock, @@ -761,9 +761,9 @@ export class StatisticsService { sales.maxSales * 4 AS restockQuantity, pns.productName FROM stock_summary ss - LEFT JOIN transfer_stock ts ON ss.productSku = ts.productSku - LEFT JOIN sales_max_summary sales ON ss.productSku = sales.productSku - LEFT JOIN product_name_summary pns ON ss.productSku = pns.productSku + LEFT JOIN transfer_stock ts ON ss.sku = ts.sku + LEFT JOIN sales_max_summary sales ON ss.sku = sales.sku + LEFT JOIN product_name_summary pns ON ss.sku = pns.sku WHERE 1 = 1 ${nameFilter} ORDER BY caAvailableDays @@ -791,10 +791,10 @@ export class StatisticsService { const offset = (current - 1) * pageSize; const countSql = ` WITH product_list AS ( - SELECT DISTINCT s.productSku + SELECT DISTINCT s.sku FROM stock s LEFT JOIN stock_point sp ON s.stockPointId = sp.id - LEFT JOIN product p ON s.productSku = p.sku + LEFT JOIN product p ON s.sku = p.sku WHERE sp.ignore = FALSE ${countnameFilter} ) @@ -810,36 +810,36 @@ export class StatisticsService { const sql = ` WITH stock_summary AS ( SELECT - s.productSku, + s.sku, SUM(s.quantity) AS totalStock FROM stock s JOIN stock_point sp ON s.stockPointId = sp.id WHERE sp.ignore = FALSE - GROUP BY s.productSku + GROUP BY s.sku ), transfer_stock AS ( SELECT - ti.productSku, + ti.sku, SUM(ti.quantity) AS transitStock FROM transfer_item ti JOIN transfer t ON ti.transferId = t.id WHERE t.isCancel = FALSE AND t.isArrived = FALSE - GROUP BY ti.productSku + GROUP BY ti.sku ), b_sales_data_raw As ( SELECT - sr.productSku, + sr.sku, DATE_FORMAT(sr.createdAt, '%Y-%m') AS month, SUM(sr.quantityChange) AS sales FROM stock_record sr JOIN stock_point sp ON sr.stockPointId = sp.id WHERE sp.isB AND sr.createdAt >= DATE_FORMAT(NOW() - INTERVAL 2 MONTH, '%Y-%m-01') - GROUP BY sr.productSku, month + GROUP BY sr.sku, month ), sales_data_raw AS ( SELECT - os.sku AS productSku, + os.sku AS sku, DATE_FORMAT(o.date_paid, '%Y-%m') AS month, SUM(CASE WHEN DAY(o.date_paid) <= 10 THEN os.quantity ELSE 0 END) AS early_sales, SUM(CASE WHEN DAY(o.date_paid) > 10 AND DAY(o.date_paid) <= 20 THEN os.quantity ELSE 0 END) AS mid_sales, @@ -852,7 +852,7 @@ export class StatisticsService { ), monthly_sales_summary AS ( SELECT - sdr.productSku, + sdr.sku, JSON_ARRAYAGG( JSON_OBJECT( 'month', sdr.month, @@ -863,12 +863,12 @@ export class StatisticsService { ) ) AS sales_data FROM sales_data_raw sdr - LEFT JOIN b_sales_data_raw b ON sdr.productSku = b.productSku AND sdr.month = b.month - GROUP BY sdr.productSku + LEFT JOIN b_sales_data_raw b ON sdr.sku = b.sku AND sdr.month = b.month + GROUP BY sdr.sku ), sales_summary AS ( SELECT - os.sku AS productSku, + os.sku AS sku, SUM(CASE WHEN o.date_paid >= CURDATE() - INTERVAL 30 DAY THEN os.quantity ELSE 0 END) AS last_30_days_sales, SUM(CASE WHEN o.date_paid >= CURDATE() - INTERVAL 15 DAY THEN os.quantity ELSE 0 END) AS last_15_days_sales, SUM(CASE WHEN DATE_FORMAT(o.date_paid, '%Y-%m') = DATE_FORMAT(CURDATE() - INTERVAL 1 MONTH, '%Y-%m') THEN os.quantity ELSE 0 END) AS last_month_sales @@ -880,14 +880,14 @@ export class StatisticsService { ), product_name_summary AS ( SELECT - p.sku AS productSku, + p.sku AS sku, COALESCE(MAX(os.name), MAX(p.name)) AS productName FROM product p LEFT JOIN order_sale os ON p.sku = os.sku GROUP BY p.sku ) SELECT - ss.productSku, + ss.sku, (COALESCE(ss.totalStock, 0) + COALESCE(ts.transitStock, 0)) AS totalStock, ms.sales_data AS monthlySalesData, pns.productName, @@ -900,10 +900,10 @@ export class StatisticsService { ELSE NULL END AS stock_ratio FROM stock_summary ss - LEFT JOIN transfer_stock ts ON ss.productSku = ts.productSku - LEFT JOIN monthly_sales_summary ms ON ss.productSku = ms.productSku - LEFT JOIN product_name_summary pns ON ss.productSku = pns.productSku - LEFT JOIN sales_summary ssum ON ss.productSku = ssum.productSku + LEFT JOIN transfer_stock ts ON ss.sku = ts.sku + LEFT JOIN monthly_sales_summary ms ON ss.sku = ms.sku + LEFT JOIN product_name_summary pns ON ss.sku = pns.sku + LEFT JOIN sales_summary ssum ON ss.sku = ssum.sku WHERE 1 = 1 ${nameFilter} ORDER BY diff --git a/src/service/stock.service.ts b/src/service/stock.service.ts index db9bf31..a0b899c 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,'productSku', poi.productSku, 'quantity', poi.quantity, 'price', poi.price)) AS items", + "JSON_ARRAYAGG(JSON_OBJECT('id', poi.id, 'productName', poi.productName,'sku', poi.sku, 'quantity', poi.quantity, 'price', poi.price)) AS items", ]) .from(PurchaseOrderItem, 'poi') .groupBy('poi.purchaseOrderId'), @@ -191,7 +191,7 @@ export class StockService { async hasStockBySku(sku: string): Promise { const count = await this.stockModel .createQueryBuilder('stock') - .where('stock.productSku = :sku', { sku }) + .where('stock.sku = :sku', { sku }) .andWhere('stock.quantity > 0') .getCount(); return count > 0; @@ -217,7 +217,7 @@ export class StockService { for (const item of items) { const updateStock = new UpdateStockDTO(); updateStock.stockPointId = purchaseOrder.stockPointId; - updateStock.productSku = item.productSku; + updateStock.sku = item.sku; updateStock.quantityChange = item.quantity; updateStock.operationType = StockRecordOperationType.IN; updateStock.operatorId = userId; @@ -240,7 +240,7 @@ export class StockService { // 获取库存列表 async getStocks(query: QueryStockDTO) { - const { current = 1, pageSize = 10, productName, productSku } = query; + const { current = 1, pageSize = 10, productName, sku } = query; const nameKeywords = productName ? productName.split(' ').filter(Boolean) : []; @@ -249,31 +249,31 @@ export class StockService { .createQueryBuilder('stock') .select([ // 'stock.id as id', - 'stock.productSku as productSku', + 'stock.sku as sku', 'product.name as productName', 'product.nameCn as productNameCn', 'JSON_ARRAYAGG(JSON_OBJECT("id", stock.stockPointId, "quantity", stock.quantity)) as stockPoint', 'MIN(stock.updatedAt) as updatedAt', 'MAX(stock.createdAt) as createdAt', ]) - .leftJoin(Product, 'product', 'product.sku = stock.productSku') - .groupBy('stock.productSku') + .leftJoin(Product, 'product', 'product.sku = stock.sku') + .groupBy('stock.sku') .addGroupBy('product.name') .addGroupBy('product.nameCn'); let totalQueryBuilder = this.stockModel .createQueryBuilder('stock') - .select('COUNT(DISTINCT stock.productSku)', 'count') - .leftJoin(Product, 'product', 'product.sku = stock.productSku'); - if (productSku) { - queryBuilder.andWhere('stock.productSku = :productSku', { productSku }); - totalQueryBuilder.andWhere('stock.productSku = :productSku', { productSku }); + .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.productSku + WHERE p.sku = stock.sku AND p.name LIKE :name${index} )`, { [`name${index}`]: `%${name}%` } @@ -281,7 +281,7 @@ export class StockService { totalQueryBuilder.andWhere( `EXISTS ( SELECT 1 FROM product p - WHERE p.sku = stock.productSku + WHERE p.sku = stock.sku AND p.name LIKE :name${index} )`, { [`name${index}`]: `%${name}%` } @@ -291,7 +291,7 @@ export class StockService { if (query.order) { const sortFieldMap: Record = { productName: 'product.name', - productSku: 'stock.productSku', + sku: 'stock.sku', updatedAt: 'updatedAt', createdAt: 'createdAt', }; @@ -335,15 +335,15 @@ export class StockService { const transfer = await this.transferModel .createQueryBuilder('t') - .select(['ti.productSku as productSku', 'SUM(ti.quantity) as quantity']) + .select(['ti.sku as sku', 'SUM(ti.quantity) as quantity']) .leftJoin(TransferItem, 'ti', 'ti.transferId = t.id') .where('!t.isArrived and !t.isCancel and !t.isLost') - .groupBy('ti.productSku') + .groupBy('ti.sku') .getRawMany(); for (const item of items) { item.inTransitQuantity = - transfer.find(t => t.productSku === item.productSku)?.quantity || 0; + transfer.find(t => t.sku === item.sku)?.quantity || 0; } return { @@ -361,10 +361,10 @@ export class StockService { const stocks = await this.stockModel .createQueryBuilder('stock') - .select('stock.productSku', 'productSku') + .select('stock.sku', 'sku') .addSelect('SUM(stock.quantity)', 'totalQuantity') - .where('stock.productSku IN (:...skus)', { skus }) - .groupBy('stock.productSku') + .where('stock.sku IN (:...skus)', { skus }) + .groupBy('stock.sku') .getRawMany(); return stocks; @@ -374,7 +374,7 @@ export class StockService { async updateStock(data: UpdateStockDTO) { const { stockPointId, - productSku, + sku, quantityChange, operationType, operatorId, @@ -383,13 +383,13 @@ export class StockService { const stock = await this.stockModel.findOneBy({ stockPointId, - productSku, + sku, }); if (!stock) { // 如果库存不存在,则直接新增 const newStock = this.stockModel.create({ stockPointId, - productSku, + sku, quantity: operationType === 'in' ? quantityChange : -quantityChange, }); await this.stockModel.save(newStock); @@ -406,7 +406,7 @@ export class StockService { // 记录库存变更日志 const stockRecord = this.stockRecordModel.create({ stockPointId, - productSku, + sku, operationType, quantityChange, operatorId, @@ -421,7 +421,7 @@ export class StockService { current = 1, pageSize = 10, stockPointId, - productSku, + sku, productName, operationType, startDate, @@ -430,14 +430,14 @@ export class StockService { const where: any = {}; if (stockPointId) where.stockPointId = stockPointId; - if (productSku) where.productSku = productSku; + if (sku) where.sku = sku; if (operationType) where.operationType = operationType; if (startDate) where.createdAt = MoreThan(startDate); if (endDate) where.createdAt = LessThan(endDate); if (startDate && endDate) where.createdAt = Between(startDate, endDate); const queryBuilder = this.stockRecordModel .createQueryBuilder('stock_record') - .leftJoin(Product, 'product', 'product.sku = stock_record.productSku') + .leftJoin(Product, 'product', 'product.sku = stock_record.sku') .leftJoin(User, 'user', 'stock_record.operatorId = user.id') .leftJoin(StockPoint, 'sp', 'sp.id = stock_record.stockPointId') .select([ @@ -470,7 +470,7 @@ export class StockService { // for (const item of items) { // const stock = await this.stockModel.findOneBy({ // stockPointId: sourceStockPointId, - // productSku: item.productSku, + // sku: item.sku, // }); // if (!stock || stock.quantity < item.quantity) // throw new Error(`${item.productName} 库存不足`); @@ -496,7 +496,7 @@ export class StockService { item.transferId = transfer.id; const updateStock = new UpdateStockDTO(); updateStock.stockPointId = sourceStockPointId; - updateStock.productSku = item.productSku; + updateStock.sku = item.sku; updateStock.quantityChange = item.quantity; updateStock.operationType = StockRecordOperationType.OUT; updateStock.operatorId = userId; @@ -530,7 +530,7 @@ export class StockService { qb .select([ 'ti.transferId AS transferId', - "JSON_ARRAYAGG(JSON_OBJECT('id', ti.id, 'productName', ti.productName,'productSku', ti.productSku, 'quantity', ti.quantity)) AS items", + "JSON_ARRAYAGG(JSON_OBJECT('id', ti.id, 'productName', ti.productName,'sku', ti.sku, 'quantity', ti.quantity)) AS items", ]) .from(TransferItem, 'ti') .groupBy('ti.transferId'), @@ -561,7 +561,7 @@ export class StockService { for (const item of items) { const updateStock = new UpdateStockDTO(); updateStock.stockPointId = transfer.sourceStockPointId; - updateStock.productSku = item.productSku; + updateStock.sku = item.sku; updateStock.quantityChange = item.quantity; updateStock.operationType = StockRecordOperationType.IN; updateStock.operatorId = userId; @@ -584,7 +584,7 @@ export class StockService { for (const item of items) { const updateStock = new UpdateStockDTO(); updateStock.stockPointId = transfer.destStockPointId; - updateStock.productSku = item.productSku; + updateStock.sku = item.sku; updateStock.quantityChange = item.quantity; updateStock.operationType = StockRecordOperationType.IN; updateStock.operatorId = userId; @@ -619,7 +619,7 @@ export class StockService { item.transferId = transfer.id; const updateStock = new UpdateStockDTO(); updateStock.stockPointId = sourceStockPointId; - updateStock.productSku = item.productSku; + updateStock.sku = item.sku; updateStock.quantityChange = item.quantity; updateStock.operationType = StockRecordOperationType.IN; updateStock.operatorId = userId; @@ -632,7 +632,7 @@ export class StockService { item.transferId = transfer.id; const updateStock = new UpdateStockDTO(); updateStock.stockPointId = sourceStockPointId; - updateStock.productSku = item.productSku; + updateStock.sku = item.sku; updateStock.quantityChange = item.quantity; updateStock.operationType = StockRecordOperationType.OUT; updateStock.operatorId = userId;