685 lines
21 KiB
TypeScript
685 lines
21 KiB
TypeScript
import {
|
|
Inject,
|
|
Post,
|
|
Put,
|
|
Get,
|
|
Body,
|
|
Param,
|
|
Del,
|
|
Query,
|
|
Controller,
|
|
} from '@midwayjs/core';
|
|
import { ProductService } from '../service/product.service';
|
|
import { errorResponse, successResponse } from '../utils/response.util';
|
|
import { CreateProductDTO, QueryProductDTO, UpdateProductDTO, BatchUpdateProductDTO, BatchDeleteProductDTO } from '../dto/product.dto';
|
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
|
import { BooleanRes, ProductListRes, ProductRes, ProductsRes } from '../dto/reponse.dto';
|
|
import { ContentType, Files } from '@midwayjs/core';
|
|
import { Context } from '@midwayjs/koa';
|
|
|
|
@Controller('/product')
|
|
export class ProductController {
|
|
@Inject()
|
|
productService: ProductService;
|
|
|
|
@Inject()
|
|
ctx: Context;
|
|
|
|
@ApiOkResponse({
|
|
description: '通过name搜索产品',
|
|
type: ProductsRes,
|
|
})
|
|
@Get('/search')
|
|
async searchProducts(@Query('name') name: string) {
|
|
try {
|
|
// 调用服务获取产品数据
|
|
const products = await this.productService.findProductsByName(name);
|
|
return successResponse(products);
|
|
} catch (error) {
|
|
return errorResponse(error.message || '获取数据失败');
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({
|
|
type: ProductRes,
|
|
})
|
|
@Get('/sku/:sku')
|
|
async productBySku(@Param('sku') sku: string) {
|
|
try {
|
|
// 调用服务获取产品数据
|
|
const product = await this.productService.findProductBySku(sku);
|
|
return successResponse(product);
|
|
} catch (error) {
|
|
return errorResponse(error.message || '获取数据失败');
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({
|
|
description: '成功返回产品列表',
|
|
type: ProductListRes,
|
|
})
|
|
@Get('/list')
|
|
async getProductList(
|
|
@Query() query: QueryProductDTO
|
|
): Promise<ProductListRes> {
|
|
const { current = 1, pageSize = 10, name, brandId, sortField, sortOrder } = query;
|
|
try {
|
|
const data = await this.productService.getProductList(
|
|
{ current, pageSize },
|
|
name,
|
|
brandId,
|
|
sortField,
|
|
sortOrder
|
|
);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
console.log(error);
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: ProductRes })
|
|
@Post('/')
|
|
async createProduct(@Body() productData: CreateProductDTO) {
|
|
try {
|
|
const data = await this.productService.createProduct(productData);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 导出所有产品 CSV
|
|
@ApiOkResponse()
|
|
@Get('/export')
|
|
@ContentType('text/csv')
|
|
async exportProductsCSV() {
|
|
try {
|
|
const csv = await this.productService.exportProductsCSV();
|
|
// 设置下载文件名(附件形式)
|
|
const date = new Date();
|
|
const pad = (n: number) => String(n).padStart(2, '0');
|
|
const name = `products-${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}.csv`;
|
|
this.ctx.set('Content-Disposition', `attachment; filename=${name}`);
|
|
return csv;
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 导入产品(CSV 文件)
|
|
@ApiOkResponse()
|
|
@Post('/import')
|
|
async importProductsCSV(@Files() files: any) {
|
|
try {
|
|
// 条件判断:确保存在文件
|
|
const file = files?.[0];
|
|
if (!file) return errorResponse('未接收到上传文件');
|
|
|
|
const result = await this.productService.importProductsCSV(file);
|
|
return successResponse(result);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: ProductRes })
|
|
@Put('/:id')
|
|
async updateProduct(@Param('id') id: number, @Body() productData: UpdateProductDTO) {
|
|
try {
|
|
const data = await this.productService.updateProduct(id, productData);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: BooleanRes })
|
|
@Put('/batch-update')
|
|
async batchUpdateProduct(@Body() batchUpdateProductDTO: BatchUpdateProductDTO) {
|
|
try {
|
|
await this.productService.batchUpdateProduct(batchUpdateProductDTO);
|
|
return successResponse(true);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: BooleanRes })
|
|
@Post('/batch-delete')
|
|
async batchDeleteProduct(@Body() body: BatchDeleteProductDTO) {
|
|
try {
|
|
const result = await this.productService.batchDeleteProduct(body.ids);
|
|
if (result.failed > 0) {
|
|
return errorResponse(`成功删除 ${result.success} 个,失败 ${result.failed} 个。首个错误: ${result.errors[0]}`);
|
|
}
|
|
return successResponse(true);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: ProductRes })
|
|
@Put('updateNameCn/:id/:nameCn')
|
|
async updatenameCn(@Param('id') id: number, @Param('nameCn') nameCn: string) {
|
|
try {
|
|
const data = await this.productService.updatenameCn(id, nameCn);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 根据站点SKU查询产品
|
|
@ApiOkResponse({ type: ProductRes })
|
|
@Get('/site-sku/:siteSku')
|
|
async getProductBySiteSku(@Param('siteSku') siteSku: string) {
|
|
try {
|
|
const product = await this.productService.findProductBySiteSku(siteSku);
|
|
return successResponse(product);
|
|
} catch (error) {
|
|
return errorResponse(error.message || '获取数据失败');
|
|
}
|
|
}
|
|
|
|
// 获取产品的站点SKU绑定
|
|
@ApiOkResponse()
|
|
@Get('/:id/site-skus')
|
|
async getProductSiteSkus(@Param('id') id: number) {
|
|
try {
|
|
const data = await this.productService.getProductSiteSkus(id);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 覆盖式绑定产品的站点SKU列表
|
|
@ApiOkResponse()
|
|
@Post('/:id/site-skus')
|
|
async bindProductSiteSkus(@Param('id') id: number, @Body() body: { codes: string[] }) {
|
|
try {
|
|
const data = await this.productService.bindSiteSkus(id, body?.codes || []);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: ProductRes })
|
|
@Get('/:id')
|
|
async getProductById(@Param('id') id: number) {
|
|
try {
|
|
const product = await this.productService.getProductById(id);
|
|
return successResponse(product);
|
|
} catch (error) {
|
|
return errorResponse(error.message || '获取数据失败');
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: BooleanRes })
|
|
@Del('/:id')
|
|
async deleteProduct(@Param('id') id: number) {
|
|
try {
|
|
const data = await this.productService.deleteProduct(id);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 获取产品的库存组成
|
|
@ApiOkResponse()
|
|
@Get('/:id/components')
|
|
async getProductComponents(@Param('id') id: number) {
|
|
try {
|
|
const data = await this.productService.getProductComponents(id);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
|
|
// 根据 SKU 自动绑定组成(匹配所有相同 SKU 的库存)
|
|
@ApiOkResponse()
|
|
@Post('/:id/components/auto')
|
|
async autoBindComponents(@Param('id') id: number) {
|
|
try {
|
|
const data = await this.productService.autoBindComponentsBySku(id);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 通用属性接口:分页列表
|
|
@ApiOkResponse()
|
|
@Get('/attribute')
|
|
async getAttributeList(
|
|
@Query('dictName') dictName: string,
|
|
@Query('current') current = 1,
|
|
@Query('pageSize') pageSize = 10,
|
|
@Query('name') name?: string
|
|
) {
|
|
try {
|
|
const data = await this.productService.getAttributeList(
|
|
dictName,
|
|
{ current, pageSize },
|
|
name
|
|
);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 通用属性接口:全部列表
|
|
@ApiOkResponse()
|
|
@Get('/attributeAll')
|
|
async getAttributeAll(@Query('dictName') dictName: string) {
|
|
try {
|
|
const data = await this.productService.getAttributeAll(dictName);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 通用属性接口:创建
|
|
@ApiOkResponse()
|
|
@Post('/attribute')
|
|
async createAttribute(
|
|
@Query('dictName') dictName: string,
|
|
@Body() body: { title: string; name: string }
|
|
) {
|
|
try {
|
|
// 调用 getOrCreateAttribute 方法,如果不存在则创建,如果存在则返回
|
|
const data = await this.productService.getOrCreateAttribute(dictName, body.title, body.name);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 通用属性接口:更新
|
|
@ApiOkResponse()
|
|
@Put('/attribute/:id')
|
|
async updateAttribute(
|
|
@Param('id') id: number,
|
|
@Query('dictName') dictName: string,
|
|
@Body() body: { title?: string; name?: string }
|
|
) {
|
|
try {
|
|
if (body?.name) {
|
|
const hasItem = await this.productService.hasAttribute(
|
|
dictName,
|
|
body.name,
|
|
id
|
|
);
|
|
if (hasItem) return errorResponse('字典项已存在');
|
|
}
|
|
const data = await this.productService.updateAttribute(id, body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 通用属性接口:删除
|
|
@ApiOkResponse({ type: BooleanRes })
|
|
@Del('/attribute/:id')
|
|
async deleteAttribute(@Param('id') id: number) {
|
|
try {
|
|
await this.productService.deleteAttribute(id);
|
|
return successResponse(true);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 兼容旧接口:品牌
|
|
@ApiOkResponse()
|
|
@Get('/brandAll')
|
|
async compatBrandAll() {
|
|
try {
|
|
const data = await this.productService.getAttributeAll('brand'); // 返回所有品牌字典项
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Get('/brands')
|
|
async compatBrands(@Query('current') current = 1, @Query('pageSize') pageSize = 10, @Query('name') name?: string) {
|
|
try {
|
|
const data = await this.productService.getAttributeList('brand', { current, pageSize }, name); // 分页品牌列表
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Post('/brand')
|
|
async compatCreateBrand(@Body() body: { title: string; name: string; image?: string; shortName?: string }) {
|
|
try {
|
|
const has = await this.productService.hasAttribute('brand', body.name); // 唯一性校验
|
|
if (has) return errorResponse('品牌已存在');
|
|
const data = await this.productService.createAttribute('brand', body); // 创建品牌字典项
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Put('/brand/:id')
|
|
async compatUpdateBrand(@Param('id') id: number, @Body() body: { title?: string; name?: string; image?: string; shortName?: string }) {
|
|
try {
|
|
if (body?.name) {
|
|
const has = await this.productService.hasAttribute('brand', body.name, id); // 唯一性校验(排除自身)
|
|
if (has) return errorResponse('品牌已存在');
|
|
}
|
|
const data = await this.productService.updateAttribute(id, body); // 更新品牌字典项
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: BooleanRes })
|
|
@Del('/brand/:id')
|
|
async compatDeleteBrand(@Param('id') id: number) {
|
|
try {
|
|
await this.productService.deleteAttribute(id); // 删除品牌字典项
|
|
return successResponse(true);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 兼容旧接口:口味
|
|
@ApiOkResponse()
|
|
@Get('/flavorsAll')
|
|
async compatFlavorsAll() {
|
|
try {
|
|
const data = await this.productService.getAttributeAll('flavor');
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Get('/flavors')
|
|
async compatFlavors(@Query('current') current = 1, @Query('pageSize') pageSize = 10, @Query('name') name?: string) {
|
|
try {
|
|
const data = await this.productService.getAttributeList('flavor', { current, pageSize }, name);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Post('/flavors')
|
|
async compatCreateFlavors(@Body() body: { title: string; name: string; image?: string; shortName?: string }) {
|
|
try {
|
|
const has = await this.productService.hasAttribute('flavor', body.name);
|
|
if (has) return errorResponse('口味已存在');
|
|
const data = await this.productService.createAttribute('flavor', body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Put('/flavors/:id')
|
|
async compatUpdateFlavors(@Param('id') id: number, @Body() body: { title?: string; name?: string; image?: string; shortName?: string }) {
|
|
try {
|
|
if (body?.name) {
|
|
const has = await this.productService.hasAttribute('flavor', body.name, id);
|
|
if (has) return errorResponse('口味已存在');
|
|
}
|
|
const data = await this.productService.updateAttribute(id, body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: BooleanRes })
|
|
@Del('/flavors/:id')
|
|
async compatDeleteFlavors(@Param('id') id: number) {
|
|
try {
|
|
await this.productService.deleteAttribute(id);
|
|
return successResponse(true);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 兼容旧接口:规格
|
|
@ApiOkResponse()
|
|
@Get('/strengthAll')
|
|
async compatStrengthAll() {
|
|
try {
|
|
const data = await this.productService.getAttributeAll('strength');
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Get('/strength')
|
|
async compatStrength(@Query('current') current = 1, @Query('pageSize') pageSize = 10, @Query('name') name?: string) {
|
|
try {
|
|
const data = await this.productService.getAttributeList('strength', { current, pageSize }, name);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Post('/strength')
|
|
async compatCreateStrength(@Body() body: { title: string; name: string; image?: string; shortName?: string }) {
|
|
try {
|
|
const has = await this.productService.hasAttribute('strength', body.name);
|
|
if (has) return errorResponse('规格已存在');
|
|
const data = await this.productService.createAttribute('strength', body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Put('/strength/:id')
|
|
async compatUpdateStrength(@Param('id') id: number, @Body() body: { title?: string; name?: string; image?: string; shortName?: string }) {
|
|
try {
|
|
if (body?.name) {
|
|
const has = await this.productService.hasAttribute('strength', body.name, id);
|
|
if (has) return errorResponse('规格已存在');
|
|
}
|
|
const data = await this.productService.updateAttribute(id, body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: BooleanRes })
|
|
@Del('/strength/:id')
|
|
async compatDeleteStrength(@Param('id') id: number) {
|
|
try {
|
|
await this.productService.deleteAttribute(id);
|
|
return successResponse(true);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 兼容旧接口:尺寸
|
|
@ApiOkResponse()
|
|
@Get('/sizeAll')
|
|
async compatSizeAll() {
|
|
try {
|
|
const data = await this.productService.getAttributeAll('size');
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Get('/size')
|
|
async compatSize(@Query('current') current = 1, @Query('pageSize') pageSize = 10, @Query('name') name?: string) {
|
|
try {
|
|
const data = await this.productService.getAttributeList('size', { current, pageSize }, name);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Post('/size')
|
|
async compatCreateSize(@Body() body: { title: string; name: string; image?: string; shortName?: string }) {
|
|
try {
|
|
const has = await this.productService.hasAttribute('size', body.name);
|
|
if (has) return errorResponse('尺寸已存在');
|
|
const data = await this.productService.createAttribute('size', body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse()
|
|
@Put('/size/:id')
|
|
async compatUpdateSize(@Param('id') id: number, @Body() body: { title?: string; name?: string; image?: string; shortName?: string }) {
|
|
try {
|
|
if (body?.name) {
|
|
const has = await this.productService.hasAttribute('size', body.name, id);
|
|
if (has) return errorResponse('尺寸已存在');
|
|
}
|
|
const data = await this.productService.updateAttribute(id, body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
@ApiOkResponse({ type: BooleanRes })
|
|
@Del('/size/:id')
|
|
async compatDeleteSize(@Param('id') id: number) {
|
|
try {
|
|
await this.productService.deleteAttribute(id);
|
|
return successResponse(true);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 获取所有分类
|
|
@ApiOkResponse({ description: '获取所有分类' })
|
|
@Get('/categories/all')
|
|
async getCategoriesAll() {
|
|
try {
|
|
const data = await this.productService.getCategoriesAll();
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 获取分类下的属性配置
|
|
@ApiOkResponse({ description: '获取分类下的属性配置' })
|
|
@Get('/category/:id/attributes')
|
|
async getCategoryAttributes(@Param('id') id: number) {
|
|
try {
|
|
const data = await this.productService.getCategoryAttributes(id);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 创建分类
|
|
@ApiOkResponse({ description: '创建分类' })
|
|
@Post('/category')
|
|
async createCategory(@Body() body: any) {
|
|
try {
|
|
const data = await this.productService.createCategory(body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 更新分类
|
|
@ApiOkResponse({ description: '更新分类' })
|
|
@Put('/category/:id')
|
|
async updateCategory(@Param('id') id: number, @Body() body: any) {
|
|
try {
|
|
const data = await this.productService.updateCategory(id, body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 删除分类
|
|
@ApiOkResponse({ description: '删除分类' })
|
|
@Del('/category/:id')
|
|
async deleteCategory(@Param('id') id: number) {
|
|
try {
|
|
await this.productService.deleteCategory(id);
|
|
return successResponse(true);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 创建分类属性
|
|
@ApiOkResponse({ description: '创建分类属性' })
|
|
@Post('/category/attribute')
|
|
async createCategoryAttribute(@Body() body: { categoryId: number; dictId: number }) {
|
|
try {
|
|
const data = await this.productService.createCategoryAttribute(body);
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 删除分类属性
|
|
@ApiOkResponse({ description: '删除分类属性' })
|
|
@Del('/category/attribute/:id')
|
|
async deleteCategoryAttribute(@Param('id') id: number) {
|
|
try {
|
|
await this.productService.deleteCategoryAttribute(id);
|
|
return successResponse(true);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
|
|
// 同步库存 SKU 到产品单品
|
|
@ApiOkResponse({ description: '同步库存 SKU 到产品单品' })
|
|
@Post('/sync-stock')
|
|
async syncStockToProduct() {
|
|
try {
|
|
const data = await this.productService.syncStockToProduct();
|
|
return successResponse(data);
|
|
} catch (error) {
|
|
return errorResponse(error?.message || error);
|
|
}
|
|
}
|
|
}
|