Create stripe integration skeleton

main
MiguelMLorente 2025-11-22 16:07:46 +01:00
parent 0fadcfd732
commit 7c8bb78f56
8 changed files with 126 additions and 0 deletions

21
package-lock.json generated
View File

@ -14,6 +14,7 @@
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"stripe": "^20.0.0",
"typeorm": "^0.3.27" "typeorm": "^0.3.27"
}, },
"devDependencies": { "devDependencies": {
@ -9247,6 +9248,26 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/stripe": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-20.0.0.tgz",
"integrity": "sha512-EaZeWpbJOCcDytdjKSwdrL5BxzbDGNueiCfHjHXlPdBQvLqoxl6AAivC35SPzTmVXJb5duXQlXFGS45H0+e6Gg==",
"license": "MIT",
"dependencies": {
"qs": "^6.11.0"
},
"engines": {
"node": ">=16"
},
"peerDependencies": {
"@types/node": ">=16"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
}
}
},
"node_modules/strtok3": { "node_modules/strtok3": {
"version": "10.3.4", "version": "10.3.4",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.4.tgz", "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.4.tgz",

View File

@ -20,6 +20,7 @@
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"stripe": "^20.0.0",
"typeorm": "^0.3.27" "typeorm": "^0.3.27"
}, },
"devDependencies": { "devDependencies": {

44
src/buy.controller.ts Normal file
View File

@ -0,0 +1,44 @@
import { Controller, Get, Post, Redirect } from "@nestjs/common";
import Stripe from 'stripe'
import { PurchaseService } from "./purchase.service";
import { UserService } from "./user.service";
import { PurchaseItem } from "./dto/purchase-item";
@Controller('/buy')
export class BuyController {
private static TEST_KEY = "sk_test_51SVqfTBQui1OXGpt6kgnIuDpbwAqQBZqNoVXkn77UeoxfOMgjC3xFuXCet1h51REAq9XeP72qBDWdXlbaTvxb4yN00YWF6TWFm"
private readonly stripe = new Stripe(BuyController.TEST_KEY)
constructor(private readonly purchaseService: PurchaseService, private readonly userService: UserService) {}
@Post("start")
@Redirect()
public async getStripeSessionUrl(userId: number) {
const user = this.userService.getUserById(userId)
const purchase = this.purchaseService.recordPurchaseStart(user, PurchaseItem.PAELLA, 1)
const session = await this.stripe.checkout.sessions.create({
line_items: [
{
price: purchase.purchasedProduct,
quantity: purchase.purchasedUnits
}
],
mode: "payment",
success_url: "https://localhost:3000/buy/complete",
cancel_url: "https://localhost:3000/buy/cancel",
})
return {url: session.url}
}
@Get("complete")
public complete() {
}
@Get("cancel")
public cancel() {
}
}

4
src/dto/purchase-item.ts Normal file
View File

@ -0,0 +1,4 @@
export enum PurchaseItem {
PAELLA = "PAELLA",
}

View File

@ -0,0 +1,6 @@
export enum PurchaseStatus {
CREATED = "CREATED",
COMPLETED = "COMPLETED",
FAILED = "FAILED",
}

11
src/dto/purchase.ts Normal file
View File

@ -0,0 +1,11 @@
import { PurchaseItem } from "./purchase-item";
import { PurchaseStatus } from "./purchase-status";
import { User } from "./user";
export class Purchase {
id: number;
purchasedBy: User;
purchasedProduct: PurchaseItem;
purchasedUnits: number;
status: PurchaseStatus
}

31
src/purchase.service.ts Normal file
View File

@ -0,0 +1,31 @@
import { Injectable, Logger } from "@nestjs/common";
import { Purchase } from "./dto/purchase";
import { User } from "./dto/user";
import { PurchaseItem } from "./dto/purchase-item";
import { PurchaseStatus } from "./dto/purchase-status";
@Injectable()
export class PurchaseService {
private readonly purchases: Purchase[] = [];
private readonly logger = new Logger(PurchaseService.name);
constructor() {}
public recordPurchaseStart(user: User, purchasedItem: PurchaseItem, units: number): Purchase {
this.logger.debug(`Recording purchase for user ID: ${user.id}`)
const purchase: Purchase = {
id: this.purchases.length,
purchasedBy: user,
purchasedProduct: purchasedItem,
purchasedUnits: units,
status: PurchaseStatus.CREATED
}
this.purchases.push(purchase)
return purchase;
}
public findPurchasesByUser(userId: number): Purchase[] {
this.logger.debug(`Searching purchases for user ID: ${userId}`)
return this.purchases.filter(purchase => purchase.purchasedBy.id = userId);
}
}

View File

@ -15,6 +15,14 @@ export class UserService {
return user; return user;
} }
public getUserById(userId: number): User {
const user = this.users.find((u) => u.id === userId);
if (!user) {
throw new NotFoundException();
}
return user;
}
public createUser(name: string, password: string): void { public createUser(name: string, password: string): void {
try { try {
this.getUserByName(name); this.getUserByName(name);