Here's an implementation for a Financial Management system focusing on fee management, billing, payments, and financial report generation using Next.js, NestJS, and GraphQL.
Backend (NestJS)
1. Entities
Fee Entity:
// fee.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { User } from './user.entity';
@Entity()
export class Fee {
  @PrimaryGeneratedColumn()
  id: number;
  @ManyToOne(() => User, (user) => user.fees)
  user: User;
  @Column()
  amount: number;
  @Column()
  dueDate: Date;
  @Column()
  status: string;  // Pending, Paid, Overdue
}
Payment Entity:
// payment.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, CreateDateColumn } from 'typeorm';
import { Fee } from './fee.entity';
@Entity()
export class Payment {
  @PrimaryGeneratedColumn()
  id: number;
  @ManyToOne(() => Fee, (fee) => fee.payments)
  fee: Fee;
  @Column()
  amount: number;
  @CreateDateColumn()
  paymentDate: Date;
  @Column()
  method: string;  // e.g., Credit Card, Bank Transfer
}
2. Services
Fee Service:
// fee.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Fee } from './fee.entity';
@Injectable()
export class FeeService {
  constructor(
    @InjectRepository(Fee)
    private feeRepository: Repository<Fee>,
  ) {}
  findAll(): Promise<Fee[]> {
    return this.feeRepository.find({ relations: ['user'] });
  }
  findOne(id: number): Promise<Fee> {
    return this.feeRepository.findOne(id, { relations: ['user'] });
  }
  create(userId: number, amount: number, dueDate: Date): Promise<Fee> {
    const newFee = this.feeRepository.create({ user: { id: userId }, amount, dueDate, status: 'Pending' });
    return this.feeRepository.save(newFee);
  }
  updateStatus(id: number, status: string): Promise<Fee> {
    return this.feeRepository.save({ id, status });
  }
}
Payment Service:
// payment.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Payment } from './payment.entity';
@Injectable()
export class PaymentService {
  constructor(
    @InjectRepository(Payment)
    private paymentRepository: Repository<Payment>,
  ) {}
  findAll(): Promise<Payment[]> {
    return this.paymentRepository.find({ relations: ['fee'] });
  }
  create(feeId: number, amount: number, method: string): Promise<Payment> {
    const newPayment = this.paymentRepository.create({ fee: { id: feeId }, amount, method });
    return this.paymentRepository.save(newPayment);
  }
}
3. Resolvers
Fee Resolver:
// fee.resolver.ts
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
import { FeeService } from './fee.service';
import { Fee } from './fee.entity';
@Resolver(() => Fee)
export class FeeResolver {
  constructor(private feeService: FeeService) {}
  @Query(() => [Fee])
  async fees() {
    return this.feeService.findAll();
  }
  @Mutation(() => Fee)
  async createFee(
    @Args('userId') userId: number,
    @Args('amount') amount: number,
    @Args('dueDate') dueDate: string,
  ) {
    return this.feeService.create(userId, amount, new Date(dueDate));
  }
  @Mutation(() => Fee)
  async updateFeeStatus(
    @Args('id') id: number,
    @Args('status') status: string,
  ) {
    return this.feeService.updateStatus(id, status);
  }
}
Payment Resolver:
// payment.resolver.ts
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
import { PaymentService } from './payment.service';
import { Payment } from './payment.entity';
@Resolver(() => Payment)
export class PaymentResolver {
  constructor(private paymentService: PaymentService) {}
  @Query(() => [Payment])
  async payments() {
    return this.paymentService.findAll();
  }
  @Mutation(() => Payment)
  async createPayment(
    @Args('feeId') feeId: number,
    @Args('amount') amount: number,
    @Args('method') method: string,
  ) {
    return this.paymentService.create(feeId, amount, method);
  }
}
Frontend (Next.js)
1. Apollo Client Setup
// apollo-client.js
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
  uri: 'http://localhost:3000/graphql',
  cache: new InMemoryCache(),
});
export default client;
2. Fee Management Page
// pages/fees.js
import { useState } from 'react';
import { useQuery, useMutation, gql } from '@apollo/client';
const GET_FEES = gql`
  query GetFees {
    fees {
      id
      amount
      dueDate
      status
      user {
        username
      }
    }
  }
`;
const CREATE_FEE = gql`
  mutation CreateFee($userId: Int!, $amount: Float!, $dueDate: String!) {
    createFee(userId: $userId, amount: $amount, dueDate: $dueDate) {
      id
      amount
      dueDate
      status
    }
  }
`;
const UPDATE_FEE_STATUS = gql`
  mutation UpdateFeeStatus($id: Int!, $status: String!) {
    updateFeeStatus(id: $id, status: $status) {
      id
      status
    }
  }
`;
export default function Fees() {
  const { loading, error, data } = useQuery(GET_FEES);
  const [createFee] = useMutation(CREATE_FEE);
  const [updateFeeStatus] = useMutation(UPDATE_FEE_STATUS);
  const [userId, setUserId] = useState('');
  const [amount, setAmount] = useState('');
  const [dueDate, setDueDate] = useState('');
  const [feeId, setFeeId] = useState('');
  const [status, setStatus] = useState('');
  const handleCreateFee = async (e) => {
    e.preventDefault();
    await createFee({ variables: { userId: parseInt(userId), amount: parseFloat(amount), dueDate } });
    setUserId('');
    setAmount('');
    setDueDate('');
  };
  const handleUpdateFeeStatus = async (e) => {
    e.preventDefault();
    await updateFeeStatus({ variables: { id: parseInt(feeId), status } });
    setFeeId('');
    setStatus('');
  };
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  return (
    <div>
      <h1>Fees</h1>
      <form onSubmit={handleCreateFee}>
        <input
          type="number"
          placeholder="User ID"
          value={userId}
          onChange={(e) => setUserId(e.target.value)}
        />
        <input
          type="number"
          placeholder="Amount"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
        />
        <input
          type="date"
          placeholder="Due Date"
          value={dueDate}
          onChange={(e) => setDueDate(e.target.value)}
        />
        <button type="submit">Create Fee</button>
      </form>
      <form onSubmit={handleUpdateFeeStatus}>
        <input
          type="number"
          placeholder="Fee ID"
          value={feeId}
          onChange={(e) => setFeeId(e.target.value)}
        />
        <input
          type="text"
          placeholder="Status"
          value={status}
          onChange={(e) => setStatus(e.target.value)}
        />
        <button type="submit">Update Fee Status</button>
      </form>
      <ul>
        {data.fees.map((fee) => (
          <li key={fee.id}>
            User: {fee.user.username}, Amount: {fee.amount}, Due: {fee.dueDate}, Status: {fee.status}
          </li>
        ))}
      </ul>
    </div>
  );
}
3. Payment Management Page
// pages/payments.js
import { useState } from 'react';
import { useQuery, useMutation, gql } from '@apollo/client';
const GET_PAYMENTS = gql`
  query GetPayments {
    payments {
      id
      amount
      paymentDate
      method
      fee {
        amount
        user {
          username
        }
      }
    }
  }
`;
const CREATE_PAYMENT = gql`
  mutation CreatePayment($feeId: Int!, $amount: Float!, $method: String!) {
    createPayment(feeId: $feeId, amount
: $amount, method: $method) {
      id
      amount
      paymentDate
      method
    }
  }
`;
export default function Payments() {
  const { loading, error, data } = useQuery(GET_PAYMENTS);
  const [createPayment] = useMutation(CREATE_PAYMENT);
  const [feeId, setFeeId] = useState('');
  const [amount, setAmount] = useState('');
  const [method, setMethod] = useState('');
  const handleCreatePayment = async (e) => {
    e.preventDefault();
    await createPayment({ variables: { feeId: parseInt(feeId), amount: parseFloat(amount), method } });
    setFeeId('');
    setAmount('');
    setMethod('');
  };
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  return (
    <div>
      <h1>Payments</h1>
      <form onSubmit={handleCreatePayment}>
        <input
          type="number"
          placeholder="Fee ID"
          value={feeId}
          onChange={(e) => setFeeId(e.target.value)}
        />
        <input
          type="number"
          placeholder="Amount"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
        />
        <input
          type="text"
          placeholder="Method"
          value={method}
          onChange={(e) => setMethod(e.target.value)}
        />
        <button type="submit">Create Payment</button>
      </form>
      <ul>
        {data.payments.map((payment) => (
          <li key={payment.id}>
            Fee: {payment.fee.amount}, User: {payment.fee.user.username}, Amount: {payment.amount}, Date: {payment.paymentDate}, Method: {payment.method}
          </li>
        ))}
      </ul>
    </div>
  );
}
Financial Reports (Next.js)
To generate financial reports, we can create a new page that aggregates data from fees and payments.
Financial Reports Page
// pages/financial-reports.js
import { useQuery, gql } from '@apollo/client';
const GET_FEES_AND_PAYMENTS = gql`
  query GetFeesAndPayments {
    fees {
      id
      amount
      dueDate
      status
      user {
        username
      }
    }
    payments {
      id
      amount
      paymentDate
      method
      fee {
        amount
        user {
          username
        }
      }
    }
  }
`;
export default function FinancialReports() {
  const { loading, error, data } = useQuery(GET_FEES_AND_PAYMENTS);
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  const totalFees = data.fees.reduce((sum, fee) => sum + fee.amount, 0);
  const totalPayments = data.payments.reduce((sum, payment) => sum + payment.amount, 0);
  return (
    <div>
      <h1>Financial Reports</h1>
      <h2>Total Fees: ${totalFees}</h2>
      <h2>Total Payments: ${totalPayments}</h2>
      <h3>Fees</h3>
      <ul>
        {data.fees.map((fee) => (
          <li key={fee.id}>
            User: {fee.user.username}, Amount: {fee.amount}, Due: {fee.dueDate}, Status: {fee.status}
          </li>
        ))}
      </ul>
      <h3>Payments</h3>
      <ul>
        {data.payments.map((payment) => (
          <li key={payment.id}>
            Fee: {payment.fee.amount}, User: {payment.fee.user.username}, Amount: {payment.amount}, Date: {payment.paymentDate}, Method: {payment.method}
          </li>
        ))}
      </ul>
    </div>
  );
}
GraphQL Schema
Define your GraphQL schema to match the resolver functions:
type User {
  id: ID!
  username: String!
}
type Fee {
  id: ID!
  amount: Float!
  dueDate: String!
  status: String!
  user: User!
}
type Payment {
  id: ID!
  amount: Float!
  paymentDate: String!
  method: String!
  fee: Fee!
}
type Query {
  fees: [Fee!]!
  payments: [Payment!]!
}
type Mutation {
  createFee(userId: Int!, amount: Float!, dueDate: String!): Fee!
  updateFeeStatus(id: Int!, status: String!): Fee!
  createPayment(feeId: Int!, amount: Float!, method: String!): Payment!
}
This setup covers the backend and frontend code for developing a fee management system with billing, payments, and financial report generation. You can expand on this by adding more features, such as detailed payment history, invoice generation, and more comprehensive financial reports.
Sure! Let's expand the existing system to include detailed payment history and invoice generation. This involves updating the backend to handle invoices and modifying the frontend to display detailed payment history and generate invoices.
Backend (NestJS)
1. Entities
Add a new Invoice entity:
Invoice Entity:
// invoice.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, CreateDateColumn } from 'typeorm';
import { User } from './user.entity';
import { Payment } from './payment.entity';
@Entity()
export class Invoice {
  @PrimaryGeneratedColumn()
  id: number;
  @ManyToOne(() => User, (user) => user.invoices)
  user: User;
  @Column()
  amount: number;
  @CreateDateColumn()
  generatedAt: Date;
  @ManyToOne(() => Payment, (payment) => payment.invoice)
  payment: Payment;
}
2. Services
Invoice Service:
// invoice.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Invoice } from './invoice.entity';
import { Payment } from './payment.entity';
import { User } from './user.entity';
@Injectable()
export class InvoiceService {
  constructor(
    @InjectRepository(Invoice)
    private invoiceRepository: Repository<Invoice>,
  ) {}
  findAll(): Promise<Invoice[]> {
    return this.invoiceRepository.find({ relations: ['user', 'payment'] });
  }
  create(userId: number, paymentId: number, amount: number): Promise<Invoice> {
    const newInvoice = this.invoiceRepository.create({
      user: { id: userId },
      payment: { id: paymentId },
      amount,
    });
    return this.invoiceRepository.save(newInvoice);
  }
}
3. Resolvers
Invoice Resolver:
// invoice.resolver.ts
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
import { InvoiceService } from './invoice.service';
import { Invoice } from './invoice.entity';
@Resolver(() => Invoice)
export class InvoiceResolver {
  constructor(private invoiceService: InvoiceService) {}
  @Query(() => [Invoice])
  async invoices() {
    return this.invoiceService.findAll();
  }
  @Mutation(() => Invoice)
  async createInvoice(
    @Args('userId') userId: number,
    @Args('paymentId') paymentId: number,
    @Args('amount') amount: number,
  ) {
    return this.invoiceService.create(userId, paymentId, amount);
  }
}
4. Update GraphQL Schema
Update your GraphQL schema to include the new Invoice type and related queries and mutations:
type User {
  id: ID!
  username: String!
  invoices: [Invoice!]!
}
type Fee {
  id: ID!
  amount: Float!
  dueDate: String!
  status: String!
  user: User!
}
type Payment {
  id: ID!
  amount: Float!
  paymentDate: String!
  method: String!
  fee: Fee!
  invoice: Invoice
}
type Invoice {
  id: ID!
  amount: Float!
  generatedAt: String!
  user: User!
  payment: Payment!
}
type Query {
  fees: [Fee!]!
  payments: [Payment!]!
  invoices: [Invoice!]!
}
type Mutation {
  createFee(userId: Int!, amount: Float!, dueDate: String!): Fee!
  updateFeeStatus(id: Int!, status: String!): Fee!
  createPayment(feeId: Int!, amount: Float!, method: String!): Payment!
  createInvoice(userId: Int!, paymentId: Int!, amount: Float!): Invoice!
}
Frontend (Next.js)
1. Invoice Management Page
pages/invoices.js
import { useState } from 'react';
import { useQuery, useMutation, gql } from '@apollo/client';
const GET_INVOICES = gql`
  query GetInvoices {
    invoices {
      id
      amount
      generatedAt
      user {
        username
      }
      payment {
        id
        amount
      }
    }
  }
`;
const CREATE_INVOICE = gql`
  mutation CreateInvoice($userId: Int!, $paymentId: Int!, $amount: Float!) {
    createInvoice(userId: $userId, paymentId: $paymentId, amount: $amount) {
      id
      amount
      generatedAt
    }
  }
`;
export default function Invoices() {
  const { loading, error, data } = useQuery(GET_INVOICES);
  const [createInvoice] = useMutation(CREATE_INVOICE);
  const [userId, setUserId] = useState('');
  const [paymentId, setPaymentId] = useState('');
  const [amount, setAmount] = useState('');
  const handleSubmit = async (e) => {
    e.preventDefault();
    await createInvoice({ variables: { userId: parseInt(userId), paymentId: parseInt(paymentId), amount: parseFloat(amount) } });
    setUserId('');
    setPaymentId('');
    setAmount('');
  };
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  return (
    <div>
      <h1>Invoices</h1>
      <form onSubmit={handleSubmit}>
        <input
          type="number"
          placeholder="User ID"
          value={userId}
          onChange={(e) => setUserId(e.target.value)}
        />
        <input
          type="number"
          placeholder="Payment ID"
          value={paymentId}
          onChange={(e) => setPaymentId(e.target.value)}
        />
        <input
          type="number"
          placeholder="Amount"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
        />
        <button type="submit">Create Invoice</button>
      </form>
      <ul>
        {data.invoices.map((invoice) => (
          <li key={invoice.id}>
            User: {invoice.user.username}, Amount: {invoice.amount}, Generated At: {invoice.generatedAt}, Payment ID: {invoice.payment.id}
          </li>
        ))}
      </ul>
    </div>
  );
}
2. Detailed Payment History Page
pages/payment-history.js
import { useQuery, gql } from '@apollo/client';
const GET_PAYMENTS = gql`
  query GetPayments {
    payments {
      id
      amount
      paymentDate
      method
      fee {
        id
        amount
        user {
          username
        }
      }
    }
  }
`;
export default function PaymentHistory() {
  const { loading, error, data } = useQuery(GET_PAYMENTS);
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  return (
    <div>
      <h1>Payment History</h1>
      <ul>
        {data.payments.map((payment) => (
          <li key={payment.id}>
            User: {payment.fee.user.username}, Fee Amount: {payment.fee.amount}, Payment Amount: {payment.amount}, Date: {payment.paymentDate}, Method: {payment.method}
          </li>
        ))}
      </ul>
    </div>
  );
}
Integrating Payment Creation with Invoice Generation
To automatically generate an invoice when a payment is created, we can modify the PaymentService and PaymentResolver to include invoice generation.
payment.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Payment } from './payment.entity';
import { InvoiceService } from './invoice.service';
@Injectable()
export class PaymentService {
  constructor(
    @InjectRepository(Payment)
    private paymentRepository: Repository<Payment>,
    private invoiceService: InvoiceService,
  ) {}
  async findAll(): Promise<Payment[]> {
    return this.paymentRepository.find({ relations: ['fee', 'fee.user'] });
  }
  async create(feeId: number, amount: number, method: string): Promise<Payment> {
    const newPayment = this.paymentRepository.create({ fee: { id: feeId }, amount, method });
    const payment = await this.paymentRepository.save(newPayment);
    await this.invoiceService.create(payment.fee.user.id, payment.id, amount);
    return payment;
  }
}
payment.resolver.ts
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
import { PaymentService } from './payment.service';
import { Payment } from './payment.entity';
@Resolver(() => Payment)
export class PaymentResolver {
  constructor(private paymentService: PaymentService) {}
  @Query(() => [Payment])
  async payments() {
    return this.paymentService.findAll();
  }
  @Mutation(() => Payment)
  async createPayment(
    @Args('feeId') feeId: number,
    @Args('amount') amount: number,
    @Args('method') method: string,
  ) {
    return this.paymentService.create(feeId, amount, method);
  }
}
This completes the implementation of detailed payment history and invoice generation within the financial management system. You can further enhance the system by adding features such as exporting invoices to PDF, sending invoice notifications via email, and more.
Support My Work ❤️
If you enjoy my content and find it valuable, consider supporting me by buying me a coffee. Your support helps me continue creating and sharing useful resources. Thank you!
Connect with Me 🌍
Let’s stay connected! You can follow me or reach out on these platforms:
🔹 YouTube – Tutorials, insights & tech content
🔹 LinkedIn – Professional updates & networking
🔹 GitHub – My open-source projects & contributions
🔹 Instagram – Behind-the-scenes & personal updates
🔹 X (formerly Twitter) – Quick thoughts & tech discussions  
I’d love to hear from you—whether it’s feedback, collaboration ideas, or just a friendly hello!
Disclaimer
This content has been generated with the assistance of AI. While I strive for accuracy and quality, please verify critical information independently.
 

 
    
Top comments (1)
Great post! The detailed implementation of financial management systems is impressive. I was wondering how such systems could be extended to handle region-specific utilities, such as bill payments for FESCO (Faisalabad Electric Supply Company) in Pakistan (fesco-bill.pk/).
For instance, managing integrations with localized billing systems often involves handling unique APIs and currency formats. What challenges do you foresee in implementing such integrations, and how would you recommend ensuring smooth operations in financial management systems for these scenarios?"