Skip to content

Commit

Permalink
Merge pull request hngprojects#420 from Uzo-Felix/feat/billing-plan-s…
Browse files Browse the repository at this point in the history
…chema

feat: billing plan schema
  • Loading branch information
PreciousIfeaka authored Aug 1, 2024
2 parents 25bf22f + ab4f087 commit 8aff990
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 25 deletions.
12 changes: 6 additions & 6 deletions src/controllers/PaymentController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ export class PaymentController {
const { transactionId } = req.params;
const verificationResponse = await verifyPayment(transactionId);

const paymentRepository = dataSource.getRepository(Payment);
const payment = await paymentRepository.findOneBy({ id: transactionId });
// const paymentRepository = dataSource.getRepository(Payment);
// const payment = await paymentRepository.findOneBy({ id: transactionId });

if (payment) {
// payment.status = verificationResponse.status === 'successful' ? 'completed' : 'failed';
await paymentRepository.save(payment);
}
// if (payment) {
// // payment.status = verificationResponse.status === 'successful' ? 'completed' : 'failed';
// await paymentRepository.save(payment);
// }

return res.json(verificationResponse);
} catch (error) {
Expand Down
1 change: 0 additions & 1 deletion src/controllers/PaymentLemonSqueezyController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ export const LemonSqueezyWebhook = async (req: Request, res: Response) => {
currency,
status: mappedStatus,
provider: "lemonsqueezy",
payer_email,
created_at,
updated_at,
});
Expand Down
44 changes: 44 additions & 0 deletions src/models/billing-plan.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToOne,
OneToMany,
} from "typeorm";
import { Organization } from "./organization";
import { Payment } from "./payment";

@Entity()
export class BillingPlan {
@PrimaryGeneratedColumn("uuid")
id: string;

@Column("uuid")
organizationId: string;

@Column()
name: string;

@Column("decimal", { precision: 10, scale: 2 })
price: number;

@Column()
currency: string;

@Column()
duration: string;

@Column({ nullable: true })
description: string;

@Column("simple-array")
features: string[];

@ManyToOne(() => Organization, (organization) => organization.billingPlans, {
onDelete: "CASCADE",
})
organization: Organization;

@OneToMany(() => Payment, (payment) => payment.billingPlan)
payments: Payment[];
}
4 changes: 4 additions & 0 deletions src/models/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { User } from ".";
import { v4 as uuidv4 } from "uuid";
import { UserOrganization } from "./user-organisation";
import ExtendedBaseEntity from "./extended-base-entity";
import { BillingPlan } from "./billing-plan";
import { Payment } from "./payment";

@Entity()
Expand Down Expand Up @@ -66,6 +67,9 @@ export class Organization extends ExtendedBaseEntity {
@OneToMany(() => Payment, (payment) => payment.organization)
payments: Payment[];

@OneToMany(() => BillingPlan, (billingPlan) => billingPlan.organization)
billingPlans: BillingPlan[];

@BeforeInsert()
generateSlug() {
this.slug = uuidv4();
Expand Down
22 changes: 11 additions & 11 deletions src/models/payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,26 @@ import {
UpdateDateColumn,
ManyToOne,
} from "typeorm";
import { IsEmail } from "class-validator";
import { User } from "./user";
import { Organization } from "./organization";
import { BillingPlan } from "./billing-plan";

@Entity()
export class Payment {
@PrimaryGeneratedColumn("uuid")
id: string;

@Column("uuid", { nullable: true })
billingPlanId: string;

@Column("decimal", { precision: 10, scale: 2 })
amount: number;

@Column()
currency: string;

@Column({ nullable: true })
paymentServiceId: string | null;

@Column({
type: "enum",
enum: ["pending", "completed", "failed"],
Expand All @@ -33,12 +38,6 @@ export class Payment {
})
provider: "stripe" | "flutterwave" | "lemonsqueezy" | "paystack";

@Column("uuid", { nullable: true })
userId: string | null;

@ManyToOne(() => User, (user) => user.payments, { nullable: true })
user: User | null;

@Column("uuid", { nullable: true })
organizationId: string | null;

Expand All @@ -47,9 +46,10 @@ export class Payment {
})
organization: Organization | null;

@Column({ nullable: true })
@IsEmail()
payer_email: string;
@ManyToOne(() => BillingPlan, (billingPlan) => billingPlan.payments, {
onDelete: "CASCADE",
})
billingPlan: BillingPlan;

@Column({ nullable: true })
description: string;
Expand Down
4 changes: 0 additions & 4 deletions src/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { UserRole } from "../enums/userRoles";
import { getIsInvalidMessage } from "../utils";
import ExtendedBaseEntity from "./extended-base-entity";
import { Like } from "./like";
import { Payment } from "./payment";
import { UserOrganization } from "./user-organisation";

@Entity()
Expand Down Expand Up @@ -82,9 +81,6 @@ export class User extends ExtendedBaseEntity {
@OneToMany(() => Sms, (sms) => sms.sender, { cascade: true })
sms: Sms[];

@OneToMany(() => Payment, (payment) => payment.user)
payments: Payment[];

@ManyToMany(() => Organization, (organization) => organization.users, {
cascade: true,
})
Expand Down
16 changes: 13 additions & 3 deletions src/services/payment/flutter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const initializePayment = async (
description: `Payment of ${detailsWithoutUserId.amount} ${detailsWithoutUserId.currency} via Flutterwave`,
metadata: { tx_ref, flutterwave_response: response },
// status: response.data.status,
id: response.data.metadata.data.id,
status: "completed",
provider: "flutterwave",
});
Expand All @@ -72,10 +73,12 @@ export const verifyPayment = async (transactionId: string): Promise<object> => {

const paymentStatus =
response.data.status === "successful" ? "completed" : "failed";
await updatePaymentStatus(transactionId, paymentStatus);
await updatePaymentStatus(transactionIdNumber, paymentStatus);

console.log(response);
return response;
} catch (error) {
console.log(error);
throw error;
}
};
Expand All @@ -99,9 +102,16 @@ async function saveTransactionToDatabase(
* @param {'completed' | 'failed'} status - The new status of the payment.
*/
async function updatePaymentStatus(
transactionId: string,
transactionIdNumber: number,
status: "completed" | "failed",
): Promise<void> {
const paymentRepository = AppDataSource.getRepository(Payment);
await paymentRepository.update({ id: transactionId }, { status });
await paymentRepository
.createQueryBuilder()
.update(Payment)
.set({ status })
.where(`metadata->'data'->>'id' = :transactionIdNumber`, {
transactionIdNumber,
})
.execute();
}

0 comments on commit 8aff990

Please sign in to comment.