diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index bf428c8..4589d03 100644 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -257,6 +257,7 @@ export const enum OrderMessage { TrackingEmailSent = "ایمیل حاوی اطلاعات سفارس و کد رهگیری برای شما ارسال شد", ItemAlreadyReceived = "سفارش شما قبلا تحویل گرفته شده است", ItemNotShipped = "سفارش هنوز ارسال نشده است", + CancelCompleted = "فرآیند لغو کالا تکمیل شد", } export const enum TicketMessage { diff --git a/src/common/types/query.type.ts b/src/common/types/query.type.ts index ace4d42..f01aa01 100644 --- a/src/common/types/query.type.ts +++ b/src/common/types/query.type.ts @@ -100,4 +100,4 @@ export type NotificationQuery = { since: number; }; -export type OrderStatusQuery = "Delivered" | "Processing" | "Cancelled" | "Returned"; +export type OrderStatusQuery = "Delivered" | "Processing" | "Cancelled" | "Returned" | "Shipped"; diff --git a/src/modules/admin/controllers/order.controller.ts b/src/modules/admin/controllers/order.controller.ts index 5182c39..ad8e1b3 100644 --- a/src/modules/admin/controllers/order.controller.ts +++ b/src/modules/admin/controllers/order.controller.ts @@ -166,6 +166,17 @@ export class AdminOrderController extends BaseController { return this.response(data); } + @ApiOperation("complete a cancell order with cancel order id") + @ApiResponse("successful", HttpStatus.Ok) + @ApiParam("cancellOrderId", "id of return order", true) + @ApiModel(CompeleteReturnRequestDTO) + @ApiAuth() + @httpPost("/cancel/:cancelOrderId/complete", Guard.authAdmin(), Guard.checkAdminPermissions([PermissionEnum.ADMIN])) + public async completeCancelOrder(@requestParam("cancelOrderId") cancelOrderId: string, @requestBody() dto: CompeleteReturnRequestDTO) { + const data = await this.cancelService.completeCancelOrder(cancelOrderId, dto); + return this.response(data); + } + //get orders for admin panel @ApiOperation("get all native shop orders") @ApiResponse("successfully", HttpStatus.Ok) diff --git a/src/modules/cancel/DTO/cancel.dto.ts b/src/modules/cancel/DTO/cancel.dto.ts index 8e73815..36e9029 100644 --- a/src/modules/cancel/DTO/cancel.dto.ts +++ b/src/modules/cancel/DTO/cancel.dto.ts @@ -1,5 +1,5 @@ import { Expose, Transform, Type, plainToClass } from "class-transformer"; -import { ArrayMinSize, IsArray, IsNotEmpty, IsNumber, IsString, Min, ValidateNested } from "class-validator"; +import { ArrayMinSize, IsArray, IsNotEmpty, IsNumber, IsOptional, IsString, Min, ValidateNested } from "class-validator"; import { ApiProperty } from "../../../common/decorator/swggerDocs"; import { IsValidId } from "../../../common/decorator/validation.decorator"; @@ -113,3 +113,24 @@ export class CreateCancelDTO { }) items: CancelOrderItemsDTO[]; } + +export class CompeleteCancelOrderDTO { + @Expose() + @IsNotEmpty() + @IsString() + @ApiProperty({ type: "string", description: "Date", example: "1404/02/02" }) + refundDate: string; + + @Expose() + @IsNotEmpty() + @IsString() + @ApiProperty({ type: "string", description: "comment", example: "متن دلخواه" }) + refundComment: string; + + @Expose() + @IsOptional() + @IsNotEmpty() + @IsString() + @ApiProperty({ type: "string", description: "the image of receipt if mandatory ", example: "https://cdn.com" }) + refundReceipt?: string; +} diff --git a/src/modules/cancel/cancel.service.ts b/src/modules/cancel/cancel.service.ts index a45f669..4346cec 100644 --- a/src/modules/cancel/cancel.service.ts +++ b/src/modules/cancel/cancel.service.ts @@ -2,9 +2,9 @@ import { inject, injectable } from "inversify"; import { isValidObjectId, startSession } from "mongoose"; import { CancelOrderItemRepo, CancelOrderRepo, CancelReasonRepo } from "./cancel.repository"; -import { CancelOrderDTO, CreateCancelDTO } from "./DTO/cancel.dto"; +import { CancelOrderDTO, CompeleteCancelOrderDTO, CreateCancelDTO } from "./DTO/cancel.dto"; import { CancelReasonDTO } from "./DTO/cancelReason.dto"; -import { CommonMessage } from "../../common/enums/message.enum"; +import { CommonMessage, OrderMessage } from "../../common/enums/message.enum"; import { OrderItemsStatus } from "../../common/enums/order.enum"; import { AdminCancelsQueries } from "../../common/types/query.type"; import { BadRequestError } from "../../core/app/app.errors"; @@ -13,6 +13,7 @@ import { OrderItemRefEnum, ReasonRefEnum } from "../fine/models/fine.model"; import { FineRepo } from "../fine/repository/fine.repository"; import { OrderItemRepo } from "../order/order.repository"; import { CancellerRefEnum } from "./models/cancel.model"; +import { StatusEnum } from "../../common/enums/status.enum"; import { FineRuleRepo } from "../fine/repository/fineRule.repository"; import { NotificationService } from "../notification/notification.service"; @@ -344,6 +345,26 @@ class CancelService { message: CommonMessage.Deleted, }; } + + async completeCancelOrder(cancelRequestId: string, dto: CompeleteCancelOrderDTO) { + const { refundComment, refundDate, refundReceipt } = dto; + + const cancelOrder = await this.cancelOrderRepo.model.findByIdAndUpdate(cancelRequestId, { + status: StatusEnum.Completed, + refundComment, + refundDate, + refundReceipt, + }); + if (!cancelOrder) throw new BadRequestError(OrderMessage.NotFound); + + return { + message: OrderMessage.CancelCompleted, + }; + } + + //####################################################### + //####################################################### + //####################################################### //####################################################### // async updateReturnReason(reasonId: string, updateReasonDto: UpdateReasonDTO) { diff --git a/src/modules/cancel/models/Abstraction/ICancel.ts b/src/modules/cancel/models/Abstraction/ICancel.ts index 1cb524a..387d6c5 100644 --- a/src/modules/cancel/models/Abstraction/ICancel.ts +++ b/src/modules/cancel/models/Abstraction/ICancel.ts @@ -1,12 +1,14 @@ import { Types } from "mongoose"; -import { OrderItemsStatus } from "../../../../common/enums/order.enum"; -import { CancellerRefEnum } from "../cancel.model"; +import { CancelStatusEnum, CancellerRefEnum } from "../cancel.model"; export interface ICancelOrder { order: number; canceller: Types.ObjectId; cancellerRef: CancellerRefEnum; - status: OrderItemsStatus; + status: CancelStatusEnum; total_price: number; + cancellReceipt: string; + cancellComment: string; + cancellDate: Date; } diff --git a/src/modules/cancel/models/cancel.model.ts b/src/modules/cancel/models/cancel.model.ts index 083ff80..c6041d4 100644 --- a/src/modules/cancel/models/cancel.model.ts +++ b/src/modules/cancel/models/cancel.model.ts @@ -1,7 +1,6 @@ import { Schema, model } from "mongoose"; import { ICancelOrder } from "./Abstraction/ICancel"; -import { OrderItemsStatus } from "../../../common/enums/order.enum"; export enum CancellerRefEnum { User = "User", @@ -9,13 +8,21 @@ export enum CancellerRefEnum { Admin = "Admin", } +export enum CancelStatusEnum { + Pending = "Pending", + Completed = "Completed", +} + const CancelOrderSchema = new Schema( { order: { type: Number, ref: "Order", required: true }, canceller: { type: Schema.Types.ObjectId, refPath: "cancellerRef", required: true }, cancellerRef: { type: String, enum: CancellerRefEnum, required: true }, - status: { type: String, enum: OrderItemsStatus, default: OrderItemsStatus.cancelled_system }, + status: { type: String, enum: CancelStatusEnum, default: CancelStatusEnum.Pending }, total_price: { type: Number, default: 0 }, + cancellReceipt: { type: String, default: null }, + cancellComment: { type: String, default: null }, + cancellDate: { type: Date, default: null }, }, { timestamps: true, toJSON: { versionKey: false, virtuals: true }, id: false }, ); diff --git a/src/modules/order/order.repository.ts b/src/modules/order/order.repository.ts index b2ef8fd..3b7dcd5 100644 --- a/src/modules/order/order.repository.ts +++ b/src/modules/order/order.repository.ts @@ -18,9 +18,7 @@ class OrderRepository extends BaseRepository { async getUserOrderCount(userId: string) { const pipeline = [ { - $match: { - user: new Types.ObjectId(userId), - }, + $match: { user: new Types.ObjectId(userId) }, }, { $lookup: { @@ -30,9 +28,7 @@ class OrderRepository extends BaseRepository { as: "orderItems", }, }, - { - $unwind: "$orderItems", - }, + { $unwind: "$orderItems" }, { $group: { _id: { @@ -49,34 +45,25 @@ class OrderRepository extends BaseRepository { $sum: { $cond: [ { - $or: [ - { $eq: ["$_id.orderStatus", OrdersStatus.process_by_seller] }, - { $eq: ["$_id.orderStatus", OrdersStatus.wait_payment] }, - ], - }, - { - $cond: [ - { - $or: [ - { $eq: ["$_id.itemStatus", OrderItemsStatus.Processing] }, - { $eq: ["$_id.itemStatus", OrderItemsStatus.Shipped] }, - ], - }, - 1, - 0, - ], + $or: [{ $eq: ["$_id.itemStatus", OrderItemsStatus.Processing] }], }, + 1, 0, ], }, }, delivered: { + $sum: { + $cond: [{ $eq: ["$_id.itemStatus", OrderItemsStatus.Delivered] }, 1, 0], + }, + }, + cancelled: { $sum: { $cond: [ { - $and: [ - { $eq: ["$_id.orderStatus", OrdersStatus.process_by_seller] }, - { $eq: ["$_id.itemStatus", OrderItemsStatus.Delivered] }, + $in: [ + "$_id.itemStatus", + [OrderItemsStatus.cancelled_system, OrderItemsStatus.cancelled_user, OrderItemsStatus.cancelled_shop], ], }, 1, @@ -84,18 +71,14 @@ class OrderRepository extends BaseRepository { ], }, }, - cancelled: { + returned: { $sum: { - $cond: [ - { - $and: [ - { $eq: ["$_id.orderStatus", OrdersStatus.cancelled_system] }, - { $eq: ["$_id.itemStatus", OrderItemsStatus.cancelled_system] }, - ], - }, - 1, - 0, - ], + $cond: [{ $eq: ["$_id.itemStatus", OrderItemsStatus.Returned] }, 1, 0], + }, + }, + shipped: { + $sum: { + $cond: [{ $eq: ["$_id.itemStatus", OrderItemsStatus.Shipped] }, 1, 0], }, }, }, @@ -106,24 +89,33 @@ class OrderRepository extends BaseRepository { processing: 1, delivered: 1, cancelled: 1, + returned: 1, + shipped: 1, }, }, ]; - const result = await this.model.aggregate(pipeline); - return result[0] || { processing: 0, delivered: 0, cancelled: 0 }; + const [result] = await this.model.aggregate(pipeline); + return ( + result || { + processing: 0, + delivered: 0, + cancelled: 0, + returned: 0, + shipped: 0, + } + ); } async getUserOrders(userId: string, statusQuery: OrderStatusQuery) { const matchQuery: { [k: string]: unknown } = { user: new Types.ObjectId(userId), - $or: [], + // $or: [], }; const orderItemsMatchQuery: { [k: string]: unknown } = {}; switch (statusQuery) { case "Cancelled": - matchQuery.$or = [{ orderStatus: OrdersStatus.cancelled_system }, { orderStatus: OrdersStatus.Cancelled }]; orderItemsMatchQuery.$or = [ { "orderItems.status": OrderItemsStatus.cancelled_system }, { "orderItems.status": OrderItemsStatus.cancelled_shop }, @@ -131,20 +123,17 @@ class OrderRepository extends BaseRepository { ]; break; case "Processing": - matchQuery.$or = [{ orderStatus: OrdersStatus.process_by_seller }, { orderStatus: OrdersStatus.wait_payment }]; - orderItemsMatchQuery.$or = [ - { "orderItems.status": OrderItemsStatus.Processing }, - { "orderItems.status": OrderItemsStatus.Shipped }, - ]; + orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Processing; break; case "Delivered": - matchQuery.orderStatus = OrdersStatus.process_by_seller; orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Delivered; break; case "Returned": - matchQuery.orderStatus = OrdersStatus.process_by_seller; orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Returned; break; + case "Shipped": + orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Shipped; + break; default: break; } diff --git a/src/modules/return/DTO/return.dto.ts b/src/modules/return/DTO/return.dto.ts index a04fea3..faa5ba2 100644 --- a/src/modules/return/DTO/return.dto.ts +++ b/src/modules/return/DTO/return.dto.ts @@ -45,7 +45,7 @@ export class ReturnRequestItemsDTO { @Expose() @IsOptional() - @IsNotEmpty() + @IsNotEmpty({ message: "عکس نمیتواند خالی باشد" }) @IsString() @ApiProperty({ type: "string", description: "the image of return if mandatory ", example: "https://cdn.com" }) imagesUrl?: string; diff --git a/src/modules/user/user.controller.ts b/src/modules/user/user.controller.ts index ab60f09..8c17396 100644 --- a/src/modules/user/user.controller.ts +++ b/src/modules/user/user.controller.ts @@ -181,7 +181,7 @@ class UserController extends BaseController { //order @ApiOperation("get current logged in user order ") @ApiResponse("successful", HttpStatus.Ok) - @ApiQuery("status", "the status of order ==> can be = Delivered | Cancelled | Processing") + @ApiQuery("status", "the status of order ==> can be = Delivered | Cancelled | Processing | Returned | Shipped") @ApiAuth() @httpGet("/profile/orders", Guard.authUser()) public async getUserOrders(@request() req: Request, @queryParam("status") status: string) {