This commit is contained in:
@@ -8,6 +8,9 @@ class PriceDetailDTO {
|
||||
@Expose()
|
||||
shipping_cost: number;
|
||||
|
||||
@Expose()
|
||||
shipping_cost_on_delivery: number;
|
||||
|
||||
@Expose()
|
||||
process_cost: number;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface ICartPayment {
|
||||
|
||||
export interface IPriceDetails {
|
||||
shipping_cost: number;
|
||||
shipping_cost_on_delivery: number;
|
||||
process_cost: number;
|
||||
total_retail_price: number;
|
||||
total_payable_price: number;
|
||||
|
||||
@@ -6,6 +6,7 @@ import { PaymentStatus } from "../../../common/enums/order.enum";
|
||||
const PaymentPriceDetails = new Schema<IPriceDetails>(
|
||||
{
|
||||
shipping_cost: { type: Number, required: true },
|
||||
shipping_cost_on_delivery: { type: Number, default: 0 },
|
||||
process_cost: { type: Number, required: true },
|
||||
total_retail_price: { type: Number, required: true },
|
||||
total_discount: { type: Number, default: 0 },
|
||||
|
||||
@@ -21,6 +21,7 @@ import { OrderService } from "../../order/order.service";
|
||||
import { PricingRepository } from "../../pricing/pricing.repository";
|
||||
import { ProductService } from "../../product/providers/product.service";
|
||||
import { ShopRepo } from "../../shop/shop.repository";
|
||||
import { ShipmentRepository } from "../../shipment/shipment.repository";
|
||||
import { IUser } from "../../user/models/Abstraction/IUser";
|
||||
import { WalletService } from "../../wallet/wallet.service";
|
||||
import { CartCheckoutDTO } from "../DTO/cartCheckout.dto";
|
||||
@@ -46,6 +47,7 @@ class PaymentService {
|
||||
@inject(IOCTYPES.WalletService) walletService: WalletService;
|
||||
@inject(IOCTYPES.NotificationService) notificationService: NotificationService;
|
||||
@inject(IOCTYPES.ShopRepo) shopRepo: ShopRepo;
|
||||
@inject(IOCTYPES.ShipmentRepository) shipmentRepo: ShipmentRepository;
|
||||
|
||||
//##################################################################
|
||||
//##################################################################
|
||||
@@ -98,7 +100,7 @@ class PaymentService {
|
||||
|
||||
if (!paymentMethods) throw new BadRequestError(PaymentMessage.PaymentMethodsNotFound);
|
||||
|
||||
const { price } = this.calculateTotalPrice(cart, cartShipmentItems);
|
||||
const { price } = await this.calculateTotalPrice(cart, cartShipmentItems);
|
||||
return {
|
||||
cart,
|
||||
cartShipmentItems,
|
||||
@@ -135,7 +137,7 @@ class PaymentService {
|
||||
const paymentMethod = await this.paymentMethodRepo.findById(cartCheckoutDto.payment_method_id);
|
||||
if (!paymentMethod) throw new BadRequestError(PaymentMessage.PaymentMethodNotFound);
|
||||
|
||||
const { price, description } = this.calculateTotalPrice(cart, cartShipmentItems);
|
||||
const { price, description } = await this.calculateTotalPrice(cart, cartShipmentItems);
|
||||
|
||||
// extracted to handle payment creation
|
||||
const { payment, paymentData } = await this.handlePaymentCreation(paymentMethod, price, user, description, session);
|
||||
@@ -238,26 +240,33 @@ class PaymentService {
|
||||
//##################################################################
|
||||
//##################################################################
|
||||
// Helper method to calculate the total price of cart items
|
||||
private calculateTotalPrice(cart: CartDTO, cartShipItem: ICartShipmentItem[]) {
|
||||
private async calculateTotalPrice(cart: CartDTO, cartShipItem: ICartShipmentItem[]) {
|
||||
const totalShippingCost = cartShipItem.reduce(
|
||||
(sum, item) => sum + item.shipmentItems.reduce((subSum, shipmentItem) => subSum + shipmentItem.shipmentCost, 0),
|
||||
0,
|
||||
);
|
||||
|
||||
// const totalCouponDiscount = cartShipItem.reduce((sum, item) => sum + item.totalCouponDiscount, 0);
|
||||
// const totalShippingCost = cartShipItem.reduce((sum, item) => sum + item.shipmentCost, 0);
|
||||
const shipperIds = [...new Set(cartShipItem.map((item) => item.shipper))];
|
||||
const shippers = await this.shipmentRepo.model.find({ _id: { $in: shipperIds } }).select("_id payDeliveryFeeOnDelivery").lean();
|
||||
const payOnDeliveryShipperIds = new Set(
|
||||
shippers.filter((shipper) => shipper.payDeliveryFeeOnDelivery).map((shipper) => shipper._id),
|
||||
);
|
||||
|
||||
const onlineShippingCost = cartShipItem.reduce((sum, item) => {
|
||||
const itemShippingCost = item.shipmentItems.reduce((subSum, shipmentItem) => subSum + shipmentItem.shipmentCost, 0);
|
||||
return sum + (payOnDeliveryShipperIds.has(item.shipper) ? 0 : itemShippingCost);
|
||||
}, 0);
|
||||
const shippingCostOnDelivery = totalShippingCost - onlineShippingCost;
|
||||
|
||||
const price = {
|
||||
shipping_cost: totalShippingCost,
|
||||
// process_cost: totalShippingCost,
|
||||
shipping_cost: onlineShippingCost,
|
||||
shipping_cost_on_delivery: shippingCostOnDelivery,
|
||||
process_cost: 0,
|
||||
cart_retail_price: cart.retail_price,
|
||||
// cart_payable_price: cart.payable_price - cart.coupon_discount,
|
||||
cart_payable_price: cart.payable_price,
|
||||
total_discount: cart.total_discount,
|
||||
coupon_discount: cart.coupon_discount,
|
||||
// total_payable_price: cart.payable_price + totalShippingCost * 2,
|
||||
total_payable_price: cart.isWholeSale ? cart.retail_price + totalShippingCost : cart.payable_price + totalShippingCost,
|
||||
total_payable_price: cart.isWholeSale ? cart.retail_price + onlineShippingCost : cart.payable_price + onlineShippingCost,
|
||||
};
|
||||
|
||||
const items = cart.items;
|
||||
@@ -357,6 +366,7 @@ class PaymentService {
|
||||
|
||||
const priceDetails: Partial<IPriceDetails> = {
|
||||
shipping_cost: price.shipping_cost,
|
||||
shipping_cost_on_delivery: price.shipping_cost_on_delivery,
|
||||
process_cost: price.process_cost,
|
||||
total_retail_price: price.cart_retail_price,
|
||||
total_discount: price.total_discount,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Expose, Type } from "class-transformer";
|
||||
import { ArrayMinSize, IsArray, IsNotEmpty, IsNumber, IsString, ValidateNested } from "class-validator";
|
||||
import { ArrayMinSize, IsArray, IsBoolean, IsNotEmpty, IsNumber, IsOptional, IsString, ValidateNested } from "class-validator";
|
||||
|
||||
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
||||
|
||||
@@ -71,4 +71,14 @@ export class CreateShipProvidersDTO {
|
||||
@IsNumber()
|
||||
@ApiProperty({ type: "number", description: "Delivery time in days", example: 3 })
|
||||
deliveryTime: number;
|
||||
|
||||
@Expose()
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@ApiProperty({
|
||||
type: "boolean",
|
||||
description: "If true, delivery fee must be paid at delivery time instead of checkout",
|
||||
example: false,
|
||||
})
|
||||
payDeliveryFeeOnDelivery?: boolean;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ class ShipperInfoDTO {
|
||||
@Expose()
|
||||
totalShippingCost: number;
|
||||
|
||||
@Expose()
|
||||
payDeliveryFeeOnDelivery: boolean;
|
||||
|
||||
@Expose()
|
||||
@Type(() => ShipperItemsDTO)
|
||||
items: ShipperItemsDTO[];
|
||||
@@ -89,4 +92,7 @@ export class ShipmentMethodDTO {
|
||||
|
||||
@Expose()
|
||||
deliveryType: string;
|
||||
|
||||
@Expose()
|
||||
payDeliveryFeeOnDelivery: boolean;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface IShipmentProviders {
|
||||
costs: IShipmentCost[];
|
||||
deliveryType: DeliveryType;
|
||||
deliveryTime: number;
|
||||
payDeliveryFeeOnDelivery: boolean;
|
||||
deleted: boolean;
|
||||
}
|
||||
export interface IShipmentCost {
|
||||
|
||||
@@ -27,6 +27,7 @@ const ShipmentSchema = new Schema<IShipmentProviders>(
|
||||
costs: [ShipmentCostSchema],
|
||||
deliveryType: { type: String, enum: DeliveryType, required: true },
|
||||
deliveryTime: { type: Number, required: true },
|
||||
payDeliveryFeeOnDelivery: { type: Boolean, default: false },
|
||||
deleted: { type: Boolean, default: false },
|
||||
},
|
||||
{ timestamps: true, toJSON: { versionKey: false }, _id: false, id: false },
|
||||
|
||||
@@ -35,7 +35,7 @@ class ShipmentService {
|
||||
//###################################################################
|
||||
//###################################################################
|
||||
async createShipmentProviderS(createDto: CreateShipProvidersDTO) {
|
||||
const existShipper = await this.shipmentRepo.model.exists({ name: createDto.name });
|
||||
const existShipper = await this.shipmentRepo.model.exists({ name: createDto.name, deleted: false });
|
||||
if (existShipper) throw new BadRequestError(CommonMessage.DuplicateName);
|
||||
|
||||
const deliveryType = this.getDeliveryType(createDto.deliveryTime);
|
||||
@@ -48,7 +48,7 @@ class ShipmentService {
|
||||
|
||||
//###################################################################
|
||||
async updateShipmentProvider(shipmentId: number, updateDto: UpdateShipmentProviderDTO) {
|
||||
const existShipper = await this.shipmentRepo.model.exists({ name: updateDto.name, _id: { $ne: shipmentId } });
|
||||
const existShipper = await this.shipmentRepo.model.exists({ name: updateDto.name, _id: { $ne: shipmentId }, deleted: false });
|
||||
if (existShipper) throw new BadRequestError(CommonMessage.DuplicateName);
|
||||
|
||||
if (updateDto.deliveryTime) {
|
||||
@@ -157,6 +157,7 @@ class ShipmentService {
|
||||
shipperName: shipmentProvider.name,
|
||||
shippingDaysRange: this.calculateShippingDays(shipmentProvider.deliveryType, shipmentProvider.deliveryTime),
|
||||
totalShippingCost,
|
||||
payDeliveryFeeOnDelivery: shipmentProvider.payDeliveryFeeOnDelivery ?? false,
|
||||
items: shipperItems,
|
||||
});
|
||||
}
|
||||
@@ -230,15 +231,25 @@ class ShipmentService {
|
||||
}));
|
||||
|
||||
if (existingCartShipmentItem) {
|
||||
// update the existing CartShipmentItem
|
||||
const totalSellingPrice = shipmentItems.reduce((acc, item) => acc + item.selling_price * item.quantity, 0);
|
||||
const totalRetailPrice = shipmentItems.reduce((acc, item) => acc + item.retail_price * item.quantity, 0);
|
||||
const totalShipmentCost = shipmentItems.reduce((acc, item) => acc + item.shipmentCost, 0);
|
||||
const onlineShipmentCost = selectedShipper.payDeliveryFeeOnDelivery ? 0 : totalShipmentCost;
|
||||
|
||||
existingCartShipmentItem.shipmentItems = shipmentItems;
|
||||
existingCartShipmentItem.shipper = selectedShipper.shipperId;
|
||||
existingCartShipmentItem.totalSellingPrice = totalSellingPrice;
|
||||
existingCartShipmentItem.totalRetailPrice = totalRetailPrice;
|
||||
existingCartShipmentItem.totalShipmentCost = totalShipmentCost;
|
||||
existingCartShipmentItem.totalPaymentPrice = totalSellingPrice + onlineShipmentCost;
|
||||
existingCartShipmentItem.itemsCount = shipmentItems.reduce((acc, item) => acc + item.quantity, 0);
|
||||
|
||||
await existingCartShipmentItem.save();
|
||||
} else {
|
||||
const totalSellingPrice = shipmentItems.reduce((acc, item) => acc + item.selling_price * item.quantity, 0);
|
||||
const totalRetailPrice = shipmentItems.reduce((acc, item) => acc + item.retail_price * item.quantity, 0);
|
||||
const totalShipmentCost = shipmentItems.reduce((acc, item) => acc + item.shipmentCost, 0);
|
||||
const onlineShipmentCost = selectedShipper.payDeliveryFeeOnDelivery ? 0 : totalShipmentCost;
|
||||
|
||||
// create a new CartShipmentItem
|
||||
await this.cartShipItemRepo.model.create({
|
||||
@@ -249,7 +260,7 @@ class ShipmentService {
|
||||
totalSellingPrice,
|
||||
totalRetailPrice,
|
||||
totalShipmentCost,
|
||||
totalPaymentPrice: totalShipmentCost + totalSellingPrice,
|
||||
totalPaymentPrice: totalSellingPrice + onlineShipmentCost,
|
||||
itemsCount: shipmentItems.reduce((acc, item) => acc + item.quantity, 0),
|
||||
});
|
||||
}
|
||||
@@ -261,12 +272,15 @@ class ShipmentService {
|
||||
(sum, item) => sum + item.shipmentItems.reduce((subSum, shipmentItem) => subSum + shipmentItem.shipmentCost, 0),
|
||||
0,
|
||||
);
|
||||
const onlineShippingCost = cartShipmentItems.reduce((sum, item) => sum + (item.totalPaymentPrice - item.totalSellingPrice), 0);
|
||||
|
||||
return {
|
||||
cartShipmentItems: cartShipmentItems,
|
||||
shippingCost: totalShippingCost,
|
||||
processCost: totalShippingCost,
|
||||
payable_price: cart.payable_price + totalShippingCost * 2,
|
||||
onlineShippingCost,
|
||||
shippingCostOnDelivery: totalShippingCost - onlineShippingCost,
|
||||
processCost: onlineShippingCost,
|
||||
payable_price: cart.payable_price + onlineShippingCost,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user