Add store-item Excel export/import for bulk price and stock updates.

Dashboard can download grouped product variants and re-upload to update price and stock. Also expose Content-Disposition for downloads and keep related product/customer API docs in sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-19 01:02:43 +03:30
co-authored by Cursor
parent 4a5780e74d
commit 7277817b6e
17 changed files with 1553 additions and 52 deletions
+53 -1
View File
@@ -1,4 +1,21 @@
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query, UseGuards } from '@nestjs/common';
import {
BadRequestException,
Body,
Controller,
Delete,
Get,
Param,
Patch,
Post,
Put,
Query,
StreamableFile,
UploadedFile,
UseGuards,
UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { memoryStorage } from 'multer';
import { AuthUser } from '../auth/auth.types';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { RequireBusinessPermission } from '../auth/decorators/require-business-permission.decorator';
@@ -14,6 +31,7 @@ import {
UpdateStoreItemVariantDto,
} from './dto/store-items.dto';
import { StoreItemsService } from './store-items.service';
import { storeItemsExcelFilename } from './store-items-excel';
@Controller('businesses/:businessId/store-items')
@UseGuards(JwtAuthGuard, BusinessPermissionGuard)
@@ -30,6 +48,40 @@ export class StoreItemsController {
return this.service.list(businessId, query, user);
}
@Get('export')
@RequireBusinessPermission('products.read')
async exportExcel(
@Param('businessId') businessId: string,
@CurrentUser() user: AuthUser,
) {
const buffer = await this.service.exportExcel(businessId, user);
const filename = storeItemsExcelFilename();
return new StreamableFile(buffer, {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
disposition: `attachment; filename="${filename}"; filename*=UTF-8''${encodeURIComponent(filename)}`,
length: buffer.length,
});
}
@Post('import')
@RequireBusinessPermission('products.update')
@UseInterceptors(
FileInterceptor('file', {
storage: memoryStorage(),
limits: { fileSize: 8 * 1024 * 1024 },
}),
)
importExcel(
@Param('businessId') businessId: string,
@UploadedFile() file: Express.Multer.File,
@CurrentUser() user: AuthUser,
) {
if (!file) {
throw new BadRequestException('Excel file is required.');
}
return this.service.importExcel(businessId, file, user);
}
@Get('by-product/:productId')
@RequireBusinessPermission('products.read')
getByProduct(