payment on deleivery
Build and Deploy / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-07-09 10:44:26 +03:30
parent f5a803d86f
commit 8e5e20320d
9 changed files with 64 additions and 17 deletions
+3
View File
@@ -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;
}
+6
View File
@@ -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 },
+20 -6
View File
@@ -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,
};
}