Improve integration between invoice and order processing

master
nicekid1 2 months ago
parent 122bbacc0d
commit 187811a048
  1. 33
      src/cart/cart.controller.ts
  2. 61
      src/cart/cart.service.ts
  3. 2
      src/config/database.config.ts
  4. 56
      src/invoice/entities/invoice.entity.ts
  5. 5
      src/invoice/invoice.controller.ts
  6. 52
      src/invoice/invoice.service.ts
  7. 4
      src/main.ts

@ -4,6 +4,7 @@ import { JwtAuthGuard } from "src/guard/auth.guard";
import { AddToCartDto } from "./dto/add-to-cart.dto"; import { AddToCartDto } from "./dto/add-to-cart.dto";
import { UpdateCartDto } from "./dto/update-cart.dto"; import { UpdateCartDto } from "./dto/update-cart.dto";
import { Cart } from "./entities/cart.entity"; import { Cart } from "./entities/cart.entity";
import { Invoice } from "src/invoice/entities/invoice.entity";
@Controller("cart") @Controller("cart")
export class CartController { export class CartController {
@ -45,19 +46,23 @@ export class CartController {
} }
@Post(':userId/checkout') @Post(':userId/checkout')
async processOrder( async processOrder(
@Param('userId') userId: number, @Param('userId') userId: number,
@Body('totalAmount') totalAmount: number, @Body('totalAmount') totalAmount: number,
): Promise<string> { ): Promise<{ message: string; invoice: Invoice }> {
if (!totalAmount || totalAmount <= 0) { if (!totalAmount || totalAmount <= 0 || isNaN(totalAmount)) {
throw new HttpException('Invalid total amount.', HttpStatus.BAD_REQUEST); throw new HttpException('Invalid total amount.', HttpStatus.BAD_REQUEST);
}
try {
const result = await this.cartService.processOrder(userId, totalAmount);
return result;
} catch (error) {
throw new HttpException(error.message || 'Order processing failed.', HttpStatus.INTERNAL_SERVER_ERROR);
}
} }
try {
const result = await this.cartService.processOrder(userId, totalAmount);
return result;
} catch (error) {
throw new HttpException(
error.message || 'An unexpected error occurred while processing the order.',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
} }

@ -4,6 +4,7 @@ import { Cart } from "./entities/cart.entity";
import { Product } from "src/products/entities/product.entity"; import { Product } from "src/products/entities/product.entity";
import { WalletService } from "src/wallet/wallet.service"; import { WalletService } from "src/wallet/wallet.service";
import { InvoiceService } from "src/invoice/invoice.service"; import { InvoiceService } from "src/invoice/invoice.service";
import { Invoice } from "src/invoice/entities/invoice.entity";
@Injectable() @Injectable()
export class CartService { export class CartService {
@ -12,7 +13,7 @@ export class CartService {
@InjectModel(Product) private readonly productModel: typeof Product, @InjectModel(Product) private readonly productModel: typeof Product,
private readonly walletService: WalletService, private readonly walletService: WalletService,
@Inject(forwardRef(() => InvoiceService)) @Inject(forwardRef(() => InvoiceService))
private invoiceService: InvoiceService private invoiceService: InvoiceService,
) {} ) {}
// Add product to cart // Add product to cart
@ -108,33 +109,47 @@ export class CartService {
} }
//order(clearCart unable) //order(clearCart unable)
async processOrder(userId: number, totalAmount: number): Promise<string> { async processOrder(userId: number, totalAmount: number): Promise<{ message: string; invoice: Invoice }> {
// Deducting credit from wallet try {
await this.walletService.processPayment(userId, totalAmount); // Deducting credit from wallet
//Reduce the number purchased from the number of products await this.walletService.processPayment(userId, totalAmount);
const cartItems = await this.cartModel.findAll({ where: { userId } });
if (cartItems.length === 0) { // Retrieve cart items
throw new HttpException("Cart is empty.", HttpStatus.BAD_REQUEST); const cartItems = await this.cartModel.findAll({ where: { userId } });
} if (cartItems.length === 0) {
for (const cartItem of cartItems) { throw new HttpException("Cart is empty.", HttpStatus.BAD_REQUEST);
const { productId, quantity } = cartItem; }
const product = await this.productModel.findOne({ where: { id: productId } }); // Process each cart item and update stock
for (const cartItem of cartItems) {
const { productId, quantity } = cartItem;
if (!product) { const product = await this.productModel.findOne({ where: { id: productId } });
throw new HttpException(`Product with ID ${productId} not found.`, HttpStatus.NOT_FOUND);
} if (!product) {
throw new HttpException(`Product with ID ${productId} not found.`, HttpStatus.NOT_FOUND);
}
if (product.quantity < quantity) {
throw new HttpException(`Insufficient stock for product ID ${productId}.`, HttpStatus.BAD_REQUEST);
}
if (product.quantity < quantity) { product.quantity -= quantity; // Reduce stock
throw new HttpException(`Insufficient stock for product ID ${productId}.`, HttpStatus.BAD_REQUEST); await product.save();
} }
product.quantity -= quantity; // Create the invoice after processing the cart
await product.save(); const invoice = await this.invoiceService.createInvoiceFromCart(userId);
// await this.clearCart(userId);
}
const invoice = await this.invoiceService.createInvoiceFromCart(userId)
return "Order processed successfully"; return { message: "Order processed successfully", invoice };
} catch (error) {
console.log(error);
if (error instanceof HttpException) {
throw error;
} else {
throw new HttpException(`An error occurred while processing the order: ${error.message}`, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
} }
} }

@ -13,5 +13,5 @@ export const databaseConfig: SequelizeModuleOptions = {
database: process.env.DATABASE_NAME || "ecommerce", database: process.env.DATABASE_NAME || "ecommerce",
models: [path.join(__dirname, "../**/entities/*.entity.ts")], models: [path.join(__dirname, "../**/entities/*.entity.ts")],
autoLoadModels: true, autoLoadModels: true,
synchronize: true, synchronize:true,
}; };

@ -9,21 +9,55 @@ export class Invoice extends Model<Invoice> {
@BelongsTo(() => User, { onDelete: "CASCADE" }) @BelongsTo(() => User, { onDelete: "CASCADE" })
user: User; user: User;
@Column({
type: DataType.STRING,
allowNull: false,
})
firstName: string;
@Column({
type: DataType.STRING,
allowNull: false,
})
lastName: string;
@Column({
type: DataType.STRING,
allowNull: false,
})
phoneNumber: string;
@Column({
type: DataType.STRING,
allowNull: false,
unique: false,
})
email: string;
@Column @Column
totalAmount: number; totalAmount: number;
@Column({ type: DataType.JSON }) @Column({
products: { type: DataType.INTEGER,
productId: number; allowNull: false,
quantity: number; })
price: number; productId: number;
name: string;
}[];
@Column @Column({
paymentStatus: string; type: DataType.INTEGER,
allowNull: false,
})
quantity: number;
@Column @Column({
refId: string; type: DataType.DECIMAL(10, 2),
allowNull: false,
})
price: number;
@Column({
type: DataType.STRING,
allowNull: false,
})
productName: string;
} }

@ -4,11 +4,6 @@ import { InvoiceService } from "./invoice.service";
@Controller("invoice") @Controller("invoice")
export class InvoiceController { export class InvoiceController {
constructor(private readonly invoiceService: InvoiceService) {} constructor(private readonly invoiceService: InvoiceService) {}
@Post("create")
async createInvoice(@Body() body: { userId: number; totalAmount: number; products: any[]; refId: string; paymentStatus: string }) {
const { userId, totalAmount, products, refId, paymentStatus } = body;
return this.invoiceService.createInvoice(userId, totalAmount, products, refId, paymentStatus);
}
@Get(":userId") @Get(":userId")
async getInvoices(@Param("userId") userId: number): Promise<any> { async getInvoices(@Param("userId") userId: number): Promise<any> {
return this.invoiceService.getInvoicesByUser(userId); return this.invoiceService.getInvoicesByUser(userId);

@ -23,36 +23,42 @@ export class InvoiceService {
throw new HttpException("Cart is empty", HttpStatus.BAD_REQUEST); throw new HttpException("Cart is empty", HttpStatus.BAD_REQUEST);
} }
const totalAmount = userCartItems.totalPrice; const products = userCartItems.cartItems.map(item => {
return {
const products = userCartItems.cartItems.map(item => ({ productId: item.productId,
productId: item.productId, quantity: item.quantity,
quantity: item.quantity, price: item.productPrice,
price: item.productPrice, productName: item.productName,
name: item.productName, totalPrice: item.totalPrice,
})); };
const newInvoice = await this.invoiceModel.create({
userId,
totalAmount,
products,
paymentStatus: "pending",
refId: "",
}); });
return newInvoice; for (const product of products) {
} await this.invoiceModel.create({
async createInvoice(userId: number, totalAmount: number, products: any[], refId: string, paymentStatus: string): Promise<Invoice> { userId,
const newInvoice = await this.invoiceModel.create({ firstName: user.firstName,
lastName: user.lastName,
phoneNumber: user.phoneNumber,
email: user.email,
totalAmount: userCartItems.totalPrice,
productId: product.productId,
quantity: product.quantity,
price: product.price,
productName: product.productName,
});
}
const newInvoice = new Invoice({
userId, userId,
totalAmount, firstName: user.firstName,
products, lastName: user.lastName,
refId, phoneNumber: user.phoneNumber,
paymentStatus, email: user.email,
totalAmount: userCartItems.totalPrice,
}); });
return newInvoice; return newInvoice;
} }
async getInvoicesByUser(userId: number): Promise<Invoice[]> { async getInvoicesByUser(userId: number): Promise<Invoice[]> {
try { try {
if (!userId) { if (!userId) {

@ -1,9 +1,11 @@
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common'; import { ValidationPipe } from '@nestjs/common';
import { Sequelize } from 'sequelize-typescript';
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule);
const sequelize = app.get(Sequelize);
await sequelize.sync({ alter: true });
app.useGlobalPipes(new ValidationPipe()); app.useGlobalPipes(new ValidationPipe());
await app.listen(process.env.PORT ?? 3000); await app.listen(process.env.PORT ?? 3000);
} }

Loading…
Cancel
Save