Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/discount/controllers/coupon.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
UpdateCouponDTO,
ResponseCouponDTO,
CouponQueryDTO,
CouponListDeleteDTO,
CouponListUpdateDTO,
} from '../dto/coupon.dto';
import { AuthGuard } from 'src/auth/auth.guard';
import { RolesGuard } from 'src/auth/roles.guard';
Expand Down Expand Up @@ -115,6 +117,36 @@ export class CouponController {
return { data, total };
}

@HttpCode(HttpStatus.NO_CONTENT)
@Delete('bulk')
@ApiOperation({ summary: 'Bulk delete coupons' })
@ApiResponse({
description: 'Successful bulk deletion of coupons',
status: HttpStatus.NO_CONTENT,
})
async bulkDelete(
@Body() couponListDeleteDTO: CouponListDeleteDTO,
): Promise<void> {
await this.couponService.bulkDelete(couponListDeleteDTO.ids);
}

@HttpCode(HttpStatus.NO_CONTENT)
@Patch('bulk')
@ApiOperation({ summary: 'Bulk update coupons' })
@ApiResponse({
description: 'Successful bulk update of coupons',
status: HttpStatus.NO_CONTENT,
})
async bulkUpdate(
@Body() couponListUpdateDTO: CouponListUpdateDTO,
): Promise<void> {
await this.couponService.bulkUpdate(
couponListUpdateDTO.ids,
couponListUpdateDTO.maxUses,
couponListUpdateDTO.expirationDate,
);
}

@Get(':code')
@ApiOperation({ summary: 'Get coupon by code' })
@ApiResponse({
Expand Down
31 changes: 31 additions & 0 deletions src/discount/controllers/promo.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {
UpdatePromoDTO,
ResponsePromoDTO,
PromoQueryDTO,
PromoListDeleteDTO,
PromoListUpdateDTO,
} from '../dto/promo.dto';
import { PromoService } from '../services/promo.service';
import { UserRole } from 'src/user/entities/user.entity';
Expand Down Expand Up @@ -115,6 +117,35 @@ export class PromoController {
return { data, total };
}

@HttpCode(HttpStatus.NO_CONTENT)
@Delete('bulk')
@ApiOperation({ summary: 'Bulk delete promos' })
@ApiResponse({
description: 'Successful bulk deletion of promos',
status: HttpStatus.NO_CONTENT,
})
async bulkDelete(
@Body() promoListDeleteDTO: PromoListDeleteDTO,
): Promise<void> {
await this.promoService.bulkDelete(promoListDeleteDTO.ids);
}

@HttpCode(HttpStatus.NO_CONTENT)
@Patch('bulk')
@ApiOperation({ summary: 'Bulk update promos' })
@ApiResponse({
description: 'Successful bulk update of promos',
status: HttpStatus.NO_CONTENT,
})
async bulkUpdate(
@Body() promoListUpdateDTO: PromoListUpdateDTO,
): Promise<void> {
await this.promoService.bulkUpdate(
promoListUpdateDTO.ids,
promoListUpdateDTO.expiredAt,
);
}

@Get(':id')
@ApiOperation({ summary: 'Get promo by ID' })
@ApiResponse({
Expand Down
33 changes: 32 additions & 1 deletion src/discount/dto/coupon.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiProperty, PartialType, IntersectionType } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { Transform, Expose } from 'class-transformer';
import {
IsNotEmpty,
IsString,
Expand All @@ -8,6 +8,7 @@ import {
Min,
IsDateString,
IsOptional,
IsUUID,
} from 'class-validator';
import { BaseDTO } from 'src/utils/dto/base.dto';
import { PaginationQueryDTO } from 'src/utils/dto/pagination.dto';
Expand Down Expand Up @@ -73,3 +74,33 @@ export class CouponQueryDTO extends PaginationQueryDTO {
this.expirationBetween = expirationBetween ? expirationBetween : [];
}
}

export class CouponListDeleteDTO {
@IsUUID(undefined, { each: true })
@ApiProperty({
description: 'List of coupon ids to be deleted',
type: [String],
})
ids: string[];
}

export class CouponListUpdateDTO {
@IsUUID(undefined, { each: true })
@ApiProperty({
description: 'List of coupon ids to be updated',
type: [String],
})
ids: string[];

@Expose()
@IsOptional()
@ApiProperty({ description: 'The new expiration date of the coupons' })
expirationDate: Date;

@Expose()
@ApiProperty({ description: 'Maximum number of coupon uses' })
@IsOptional()
@IsInt()
@Min(0)
maxUses: number;
}
23 changes: 23 additions & 0 deletions src/discount/dto/promo.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
IsString,
IsDateString,
IsOptional,
IsUUID,
} from 'class-validator';
import { BaseDTO } from 'src/utils/dto/base.dto';
import { PaginationQueryDTO } from 'src/utils/dto/pagination.dto';
Expand Down Expand Up @@ -58,3 +59,25 @@ export class PromoQueryDTO extends PaginationQueryDTO {
this.expirationBetween = expirationBetween ? expirationBetween : [];
}
}

export class PromoListDeleteDTO {
@IsUUID(undefined, { each: true })
@ApiProperty({
description: 'List of promo ids to be deleted',
type: [String],
})
ids: string[];
}

export class PromoListUpdateDTO {
@IsUUID(undefined, { each: true })
@ApiProperty({
description: 'List of promo ids to be updated',
type: [String],
})
ids: string[];

@IsNotEmpty()
@ApiProperty({ description: 'The new expiration date of the promos' })
expiredAt: Date;
}
27 changes: 26 additions & 1 deletion src/discount/services/coupon.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { In, IsNull, Repository } from 'typeorm';
import { Coupon } from '../entities/coupon.entity';
import { CouponDTO, UpdateCouponDTO } from '../dto/coupon.dto';

Expand Down Expand Up @@ -76,4 +76,29 @@ export class CouponService {
}
return true;
}

async bulkDelete(ids: string[]) {
const coupons = await this.couponRepository.findBy({
id: In(ids),
deletedAt: IsNull(),
});
if (coupons.length === 0) {
throw new NotFoundException(`No coupons found with the given IDs`);
}
await this.couponRepository.softDelete({ id: In(ids) });
}

async bulkUpdate(ids: string[], maxUses?: number, expirationDate?: Date) {
const coupons = await this.couponRepository.findBy({
id: In(ids),
deletedAt: IsNull(),
});
if (coupons.length === 0) {
throw new NotFoundException(`No coupons found with the given IDs`);
}
const couponsToUpdate = coupons.map((coupon) => {
return { ...coupon, maxUses, expirationDate };
});
await this.couponRepository.save(couponsToUpdate);
}
}
27 changes: 26 additions & 1 deletion src/discount/services/promo.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { IsNull, Repository } from 'typeorm';
import { In, IsNull, Repository } from 'typeorm';
import { PromoDTO, UpdatePromoDTO } from '../dto/promo.dto';
import { Promo } from '../entities/promo.entity';

Expand Down Expand Up @@ -69,4 +69,29 @@ export class PromoService {
});
return result.affected === 1;
}

async bulkDelete(ids: string[]) {
const promos = await this.promoRepository.findBy({
id: In(ids),
deletedAt: IsNull(),
});
if (promos.length === 0) {
throw new NotFoundException(`No promos found with the given IDs`);
}
await this.promoRepository.softDelete({ id: In(ids) });
}

async bulkUpdate(ids: string[], expiredAt: Date) {
const promos = await this.promoRepository.findBy({
id: In(ids),
deletedAt: IsNull(),
});
if (promos.length === 0) {
throw new NotFoundException(`No promos found with the given IDs`);
}
await this.promoRepository.update(
{ id: In(ids) },
{ expiredAt, updatedAt: new Date() },
);
}
}
17 changes: 17 additions & 0 deletions src/order/controllers/order.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
import { OrderService } from '../order.service';
import {
CreateOrderDTO,
OrderListUpdateDTO,
OrderQueryDTO,
ResponseOrderDetailedDTO,
ResponseOrderDTO,
Expand Down Expand Up @@ -162,6 +163,22 @@ export class OrderController {
};
}

@UseGuards(AuthGuard, RolesGuard)
@Roles(UserRole.ADMIN)
@Patch('bulk')
@ApiBearerAuth()
@ApiOperation({ summary: 'Bulk update orders' })
@ApiResponse({
status: HttpStatus.NO_CONTENT,
description: 'Orders updated successfully',
})
async bulkUpdate(@Body() updateOrderDto: OrderListUpdateDTO): Promise<void> {
await this.orderService.bulkUpdate(
updateOrderDto.orders,
updateOrderDto.status,
);
}

@Get(':id')
@UseGuards(AuthGuard)
@ApiBearerAuth()
Expand Down
11 changes: 11 additions & 0 deletions src/order/dto/order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
IsArray,
IsEnum,
IsInt,
IsNotEmpty,
IsOptional,
IsPositive,
IsString,
Expand Down Expand Up @@ -213,6 +214,16 @@ export class UpdateOrderStatusWsDTO {
status: OrderStatus;
}

export class OrderListUpdateDTO {
@ArrayNotEmpty()
@IsUUID(undefined, { each: true })
orders: string[];

@IsNotEmpty()
@IsEnum(OrderStatus)
status: OrderStatus;
}

export class SalesReportDTO {
@Expose()
@ApiProperty({ description: 'ID of the order' })
Expand Down
18 changes: 17 additions & 1 deletion src/order/order.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { CreateOrderDTO, SalesReportDTO } from './dto/order';
import { User, UserRole } from 'src/user/entities/user.entity';
import { ProductPresentationService } from 'src/products/services/product-presentation.service';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { In, Repository } from 'typeorm';
import {
Order,
OrderDetail,
Expand Down Expand Up @@ -276,6 +276,22 @@ export class OrderService {
return await this.orderRepository.save(order);
}

async bulkUpdate(ordersIds: string[], status: OrderStatus) {
const orders = await this.orderRepository.findBy({
id: In(ordersIds),
});
if (orders.length === 0) {
throw new NotFoundException('No orders found');
}
const updatedOrders = orders.map((order) => {
if (order.status !== OrderStatus.COMPLETED) {
order.status = status;
return order;
} else return order;
});
return await this.orderRepository.save(updatedOrders);
}

async findAllOD(
user: User,
page: number,
Expand Down
13 changes: 13 additions & 0 deletions src/products/dto/product-presentation.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,16 @@ export class ResponseOrderProductPresentationDetailDTO extends IntersectionType(
@ApiProperty({ type: ResponsePromoDTO })
promo: ResponsePromoDTO;
}

export class ProductPresentationListUpdateDTO {
@ApiProperty({ description: 'The IDs of the product presentation' })
@IsUUID(undefined, { each: true })
ids: string[];

@ApiProperty({
description: 'Indicates if the product presentation is visible',
default: true,
})
@IsBoolean()
isVisible: boolean;
}
Loading
Loading