@@ -257,6 +257,7 @@ export const enum OrderMessage {
|
|||||||
TrackingEmailSent = "ایمیل حاوی اطلاعات سفارس و کد رهگیری برای شما ارسال شد",
|
TrackingEmailSent = "ایمیل حاوی اطلاعات سفارس و کد رهگیری برای شما ارسال شد",
|
||||||
ItemAlreadyReceived = "سفارش شما قبلا تحویل گرفته شده است",
|
ItemAlreadyReceived = "سفارش شما قبلا تحویل گرفته شده است",
|
||||||
ItemNotShipped = "سفارش هنوز ارسال نشده است",
|
ItemNotShipped = "سفارش هنوز ارسال نشده است",
|
||||||
|
CancelCompleted = "فرآیند لغو کالا تکمیل شد",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum TicketMessage {
|
export const enum TicketMessage {
|
||||||
|
|||||||
@@ -100,4 +100,4 @@ export type NotificationQuery = {
|
|||||||
since: number;
|
since: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type OrderStatusQuery = "Delivered" | "Processing" | "Cancelled" | "Returned";
|
export type OrderStatusQuery = "Delivered" | "Processing" | "Cancelled" | "Returned" | "Shipped";
|
||||||
|
|||||||
@@ -166,6 +166,17 @@ export class AdminOrderController extends BaseController {
|
|||||||
return this.response(data);
|
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
|
//get orders for admin panel
|
||||||
@ApiOperation("get all native shop orders")
|
@ApiOperation("get all native shop orders")
|
||||||
@ApiResponse("successfully", HttpStatus.Ok)
|
@ApiResponse("successfully", HttpStatus.Ok)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Expose, Transform, Type, plainToClass } from "class-transformer";
|
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 { ApiProperty } from "../../../common/decorator/swggerDocs";
|
||||||
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
||||||
@@ -113,3 +113,24 @@ export class CreateCancelDTO {
|
|||||||
})
|
})
|
||||||
items: CancelOrderItemsDTO[];
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { inject, injectable } from "inversify";
|
|||||||
import { isValidObjectId, startSession } from "mongoose";
|
import { isValidObjectId, startSession } from "mongoose";
|
||||||
|
|
||||||
import { CancelOrderItemRepo, CancelOrderRepo, CancelReasonRepo } from "./cancel.repository";
|
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 { 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 { OrderItemsStatus } from "../../common/enums/order.enum";
|
||||||
import { AdminCancelsQueries } from "../../common/types/query.type";
|
import { AdminCancelsQueries } from "../../common/types/query.type";
|
||||||
import { BadRequestError } from "../../core/app/app.errors";
|
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 { FineRepo } from "../fine/repository/fine.repository";
|
||||||
import { OrderItemRepo } from "../order/order.repository";
|
import { OrderItemRepo } from "../order/order.repository";
|
||||||
import { CancellerRefEnum } from "./models/cancel.model";
|
import { CancellerRefEnum } from "./models/cancel.model";
|
||||||
|
import { StatusEnum } from "../../common/enums/status.enum";
|
||||||
import { FineRuleRepo } from "../fine/repository/fineRule.repository";
|
import { FineRuleRepo } from "../fine/repository/fineRule.repository";
|
||||||
import { NotificationService } from "../notification/notification.service";
|
import { NotificationService } from "../notification/notification.service";
|
||||||
|
|
||||||
@@ -344,6 +345,26 @@ class CancelService {
|
|||||||
message: CommonMessage.Deleted,
|
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) {
|
// async updateReturnReason(reasonId: string, updateReasonDto: UpdateReasonDTO) {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
import { OrderItemsStatus } from "../../../../common/enums/order.enum";
|
import { CancelStatusEnum, CancellerRefEnum } from "../cancel.model";
|
||||||
import { CancellerRefEnum } from "../cancel.model";
|
|
||||||
|
|
||||||
export interface ICancelOrder {
|
export interface ICancelOrder {
|
||||||
order: number;
|
order: number;
|
||||||
canceller: Types.ObjectId;
|
canceller: Types.ObjectId;
|
||||||
cancellerRef: CancellerRefEnum;
|
cancellerRef: CancellerRefEnum;
|
||||||
status: OrderItemsStatus;
|
status: CancelStatusEnum;
|
||||||
total_price: number;
|
total_price: number;
|
||||||
|
cancellReceipt: string;
|
||||||
|
cancellComment: string;
|
||||||
|
cancellDate: Date;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Schema, model } from "mongoose";
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
import { ICancelOrder } from "./Abstraction/ICancel";
|
import { ICancelOrder } from "./Abstraction/ICancel";
|
||||||
import { OrderItemsStatus } from "../../../common/enums/order.enum";
|
|
||||||
|
|
||||||
export enum CancellerRefEnum {
|
export enum CancellerRefEnum {
|
||||||
User = "User",
|
User = "User",
|
||||||
@@ -9,13 +8,21 @@ export enum CancellerRefEnum {
|
|||||||
Admin = "Admin",
|
Admin = "Admin",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CancelStatusEnum {
|
||||||
|
Pending = "Pending",
|
||||||
|
Completed = "Completed",
|
||||||
|
}
|
||||||
|
|
||||||
const CancelOrderSchema = new Schema<ICancelOrder>(
|
const CancelOrderSchema = new Schema<ICancelOrder>(
|
||||||
{
|
{
|
||||||
order: { type: Number, ref: "Order", required: true },
|
order: { type: Number, ref: "Order", required: true },
|
||||||
canceller: { type: Schema.Types.ObjectId, refPath: "cancellerRef", required: true },
|
canceller: { type: Schema.Types.ObjectId, refPath: "cancellerRef", required: true },
|
||||||
cancellerRef: { type: String, enum: CancellerRefEnum, 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 },
|
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 },
|
{ timestamps: true, toJSON: { versionKey: false, virtuals: true }, id: false },
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ class OrderRepository extends BaseRepository<IOrder> {
|
|||||||
async getUserOrderCount(userId: string) {
|
async getUserOrderCount(userId: string) {
|
||||||
const pipeline = [
|
const pipeline = [
|
||||||
{
|
{
|
||||||
$match: {
|
$match: { user: new Types.ObjectId(userId) },
|
||||||
user: new Types.ObjectId(userId),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$lookup: {
|
$lookup: {
|
||||||
@@ -30,9 +28,7 @@ class OrderRepository extends BaseRepository<IOrder> {
|
|||||||
as: "orderItems",
|
as: "orderItems",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ $unwind: "$orderItems" },
|
||||||
$unwind: "$orderItems",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
$group: {
|
$group: {
|
||||||
_id: {
|
_id: {
|
||||||
@@ -49,34 +45,25 @@ class OrderRepository extends BaseRepository<IOrder> {
|
|||||||
$sum: {
|
$sum: {
|
||||||
$cond: [
|
$cond: [
|
||||||
{
|
{
|
||||||
$or: [
|
$or: [{ $eq: ["$_id.itemStatus", OrderItemsStatus.Processing] }],
|
||||||
{ $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,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
1,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
delivered: {
|
delivered: {
|
||||||
|
$sum: {
|
||||||
|
$cond: [{ $eq: ["$_id.itemStatus", OrderItemsStatus.Delivered] }, 1, 0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cancelled: {
|
||||||
$sum: {
|
$sum: {
|
||||||
$cond: [
|
$cond: [
|
||||||
{
|
{
|
||||||
$and: [
|
$in: [
|
||||||
{ $eq: ["$_id.orderStatus", OrdersStatus.process_by_seller] },
|
"$_id.itemStatus",
|
||||||
{ $eq: ["$_id.itemStatus", OrderItemsStatus.Delivered] },
|
[OrderItemsStatus.cancelled_system, OrderItemsStatus.cancelled_user, OrderItemsStatus.cancelled_shop],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
1,
|
1,
|
||||||
@@ -84,18 +71,14 @@ class OrderRepository extends BaseRepository<IOrder> {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cancelled: {
|
returned: {
|
||||||
$sum: {
|
$sum: {
|
||||||
$cond: [
|
$cond: [{ $eq: ["$_id.itemStatus", OrderItemsStatus.Returned] }, 1, 0],
|
||||||
{
|
},
|
||||||
$and: [
|
},
|
||||||
{ $eq: ["$_id.orderStatus", OrdersStatus.cancelled_system] },
|
shipped: {
|
||||||
{ $eq: ["$_id.itemStatus", OrderItemsStatus.cancelled_system] },
|
$sum: {
|
||||||
],
|
$cond: [{ $eq: ["$_id.itemStatus", OrderItemsStatus.Shipped] }, 1, 0],
|
||||||
},
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -106,24 +89,33 @@ class OrderRepository extends BaseRepository<IOrder> {
|
|||||||
processing: 1,
|
processing: 1,
|
||||||
delivered: 1,
|
delivered: 1,
|
||||||
cancelled: 1,
|
cancelled: 1,
|
||||||
|
returned: 1,
|
||||||
|
shipped: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const result = await this.model.aggregate(pipeline);
|
const [result] = await this.model.aggregate(pipeline);
|
||||||
return result[0] || { processing: 0, delivered: 0, cancelled: 0 };
|
return (
|
||||||
|
result || {
|
||||||
|
processing: 0,
|
||||||
|
delivered: 0,
|
||||||
|
cancelled: 0,
|
||||||
|
returned: 0,
|
||||||
|
shipped: 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserOrders(userId: string, statusQuery: OrderStatusQuery) {
|
async getUserOrders(userId: string, statusQuery: OrderStatusQuery) {
|
||||||
const matchQuery: { [k: string]: unknown } = {
|
const matchQuery: { [k: string]: unknown } = {
|
||||||
user: new Types.ObjectId(userId),
|
user: new Types.ObjectId(userId),
|
||||||
$or: [],
|
// $or: [],
|
||||||
};
|
};
|
||||||
const orderItemsMatchQuery: { [k: string]: unknown } = {};
|
const orderItemsMatchQuery: { [k: string]: unknown } = {};
|
||||||
|
|
||||||
switch (statusQuery) {
|
switch (statusQuery) {
|
||||||
case "Cancelled":
|
case "Cancelled":
|
||||||
matchQuery.$or = [{ orderStatus: OrdersStatus.cancelled_system }, { orderStatus: OrdersStatus.Cancelled }];
|
|
||||||
orderItemsMatchQuery.$or = [
|
orderItemsMatchQuery.$or = [
|
||||||
{ "orderItems.status": OrderItemsStatus.cancelled_system },
|
{ "orderItems.status": OrderItemsStatus.cancelled_system },
|
||||||
{ "orderItems.status": OrderItemsStatus.cancelled_shop },
|
{ "orderItems.status": OrderItemsStatus.cancelled_shop },
|
||||||
@@ -131,20 +123,17 @@ class OrderRepository extends BaseRepository<IOrder> {
|
|||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
case "Processing":
|
case "Processing":
|
||||||
matchQuery.$or = [{ orderStatus: OrdersStatus.process_by_seller }, { orderStatus: OrdersStatus.wait_payment }];
|
orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Processing;
|
||||||
orderItemsMatchQuery.$or = [
|
|
||||||
{ "orderItems.status": OrderItemsStatus.Processing },
|
|
||||||
{ "orderItems.status": OrderItemsStatus.Shipped },
|
|
||||||
];
|
|
||||||
break;
|
break;
|
||||||
case "Delivered":
|
case "Delivered":
|
||||||
matchQuery.orderStatus = OrdersStatus.process_by_seller;
|
|
||||||
orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Delivered;
|
orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Delivered;
|
||||||
break;
|
break;
|
||||||
case "Returned":
|
case "Returned":
|
||||||
matchQuery.orderStatus = OrdersStatus.process_by_seller;
|
|
||||||
orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Returned;
|
orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Returned;
|
||||||
break;
|
break;
|
||||||
|
case "Shipped":
|
||||||
|
orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Shipped;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export class ReturnRequestItemsDTO {
|
|||||||
|
|
||||||
@Expose()
|
@Expose()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty({ message: "عکس نمیتواند خالی باشد" })
|
||||||
@IsString()
|
@IsString()
|
||||||
@ApiProperty({ type: "string", description: "the image of return if mandatory ", example: "https://cdn.com" })
|
@ApiProperty({ type: "string", description: "the image of return if mandatory ", example: "https://cdn.com" })
|
||||||
imagesUrl?: string;
|
imagesUrl?: string;
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ class UserController extends BaseController {
|
|||||||
//order
|
//order
|
||||||
@ApiOperation("get current logged in user order ")
|
@ApiOperation("get current logged in user order ")
|
||||||
@ApiResponse("successful", HttpStatus.Ok)
|
@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()
|
@ApiAuth()
|
||||||
@httpGet("/profile/orders", Guard.authUser())
|
@httpGet("/profile/orders", Guard.authUser())
|
||||||
public async getUserOrders(@request() req: Request, @queryParam("status") status: string) {
|
public async getUserOrders(@request() req: Request, @queryParam("status") status: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user