Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions backend/services/billPaymentScheduler/billService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// BillService: CRUD, scheduling logic

const { Bill } = require('./models');

// In-memory bill storage
const bills = [];

class BillService {
static createBill(billData) {
const bill = new Bill(
bills.length + 1,
billData.userId,
billData.name,
billData.amount,
billData.dueDate,
billData.recurring,
billData.frequency,
'pending',
billData.paymentMethodId
);
bills.push(bill);
return bill;
}

static getBillsByUser(userId) {
return bills.filter(b => b.userId === userId);
}

static getBillById(billId) {
return bills.find(b => b.id === billId);
}

static updateBill(billId, updateData) {
const bill = this.getBillById(billId);
if (!bill) return null;
Object.assign(bill, updateData);
return bill;
}

static deleteBill(billId) {
const idx = bills.findIndex(b => b.id === billId);
if (idx !== -1) {
bills.splice(idx, 1);
return true;
}
return false;
}

static getUpcomingBills(userId, daysAhead = 7) {
const now = new Date();
const future = new Date(now.getTime() + daysAhead * 24 * 60 * 60 * 1000);
return bills.filter(b => b.userId === userId && new Date(b.dueDate) <= future && b.status === 'pending');
}

static markBillPaid(billId) {
const bill = this.getBillById(billId);
if (bill) {
bill.status = 'paid';
return bill;
}
return null;
}

static scheduleRecurringBills() {
bills.forEach(bill => {
if (bill.recurring && bill.status === 'paid') {
// Schedule next bill
let nextDue;
const currentDue = new Date(bill.dueDate);
switch (bill.frequency) {
case 'monthly':
nextDue = new Date(currentDue);
nextDue.setMonth(nextDue.getMonth() + 1);
break;
case 'weekly':
nextDue = new Date(currentDue);
nextDue.setDate(nextDue.getDate() + 7);
break;
case 'yearly':
nextDue = new Date(currentDue);
nextDue.setFullYear(nextDue.getFullYear() + 1);
break;
default:
nextDue = null;
}
if (nextDue) {
bill.dueDate = nextDue.toISOString();
bill.status = 'pending';
}
}
});
}
}

module.exports = BillService;
43 changes: 43 additions & 0 deletions backend/services/billPaymentScheduler/controllers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Controllers: API endpoints for bills, payments, schedules

const BillService = require('./billService');
const PaymentService = require('./paymentService');
const SchedulerService = require('./schedulerService');

const controllers = {
createBill: (req, res) => {
const bill = BillService.createBill(req.body);
res.status(201).json(bill);
},
getBills: (req, res) => {
const bills = BillService.getBillsByUser(req.params.userId);
res.json(bills);
},
updateBill: (req, res) => {
const bill = BillService.updateBill(parseInt(req.params.billId), req.body);
if (bill) res.json(bill);
else res.status(404).json({ error: 'Bill not found' });
},
deleteBill: (req, res) => {
const success = BillService.deleteBill(parseInt(req.params.billId));
if (success) res.json({ success: true });
else res.status(404).json({ error: 'Bill not found' });
},
processPayment: (req, res) => {
const payment = PaymentService.processPayment(req.body);
if (payment.status === 'success') {
BillService.markBillPaid(payment.billId);
}
res.status(201).json(payment);
},
getPayments: (req, res) => {
const payments = PaymentService.getPaymentsByUser(req.params.userId);
res.json(payments);
},
runScheduler: (req, res) => {
SchedulerService.runScheduler();
res.json({ success: true });
}
};

module.exports = controllers;
59 changes: 59 additions & 0 deletions backend/services/billPaymentScheduler/models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Bill, User, Payment, Schedule models
// ...existing code...
// User Model
class User {
constructor(id, name, email, phone, paymentMethods = []) {
this.id = id;
this.name = name;
this.email = email;
this.phone = phone;
this.paymentMethods = paymentMethods;
}
}

// Bill Model
class Bill {
constructor(id, userId, name, amount, dueDate, recurring, frequency, status = 'pending', paymentMethodId = null) {
this.id = id;
this.userId = userId;
this.name = name;
this.amount = amount;
this.dueDate = dueDate;
this.recurring = recurring;
this.frequency = frequency; // e.g. 'monthly', 'weekly', 'yearly'
this.status = status;
this.paymentMethodId = paymentMethodId;
}
}

// Payment Model
class Payment {
constructor(id, billId, userId, amount, date, status, gatewayResponse = null) {
this.id = id;
this.billId = billId;
this.userId = userId;
this.amount = amount;
this.date = date;
this.status = status; // 'success', 'failed', 'pending'
this.gatewayResponse = gatewayResponse;
}
}

// Schedule Model
class Schedule {
constructor(id, billId, userId, nextRun, frequency, enabled = true) {
this.id = id;
this.billId = billId;
this.userId = userId;
this.nextRun = nextRun;
this.frequency = frequency;
this.enabled = enabled;
}
}

module.exports = {
User,
Bill,
Payment,
Schedule
};
40 changes: 40 additions & 0 deletions backend/services/billPaymentScheduler/paymentService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// PaymentService: payment gateway integration

const { Payment } = require('./models');
const payments = [];

class PaymentService {
static processPayment(paymentData) {
// Simulate payment gateway integration
const gatewayResponse = {
transactionId: 'TXN' + Math.floor(Math.random() * 1000000),
status: 'success',
timestamp: new Date().toISOString()
};
const payment = new Payment(
payments.length + 1,
paymentData.billId,
paymentData.userId,
paymentData.amount,
new Date().toISOString(),
gatewayResponse.status,
gatewayResponse
);
payments.push(payment);
return payment;
}

static getPaymentsByUser(userId) {
return payments.filter(p => p.userId === userId);
}

static getPaymentsByBill(billId) {
return payments.filter(p => p.billId === billId);
}

static getPaymentById(paymentId) {
return payments.find(p => p.id === paymentId);
}
}

module.exports = PaymentService;
23 changes: 23 additions & 0 deletions backend/services/billPaymentScheduler/reminderService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// ReminderService: notifications for upcoming bills

const BillService = require('./billService');
const { User } = require('./models');

class ReminderService {
static sendReminder(user, bill) {
// Simulate sending email/SMS
console.log(`Reminder sent to ${user.email} for bill '${bill.name}' due on ${bill.dueDate}`);
return true;
}

static sendUpcomingReminders(users, daysAhead = 7) {
users.forEach(user => {
const upcomingBills = BillService.getUpcomingBills(user.id, daysAhead);
upcomingBills.forEach(bill => {
this.sendReminder(user, bill);
});
});
}
}

module.exports = ReminderService;
17 changes: 17 additions & 0 deletions backend/services/billPaymentScheduler/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Express routes for API

const express = require('express');
const controllers = require('./controllers');
const router = express.Router();

router.post('/bill', controllers.createBill);
router.get('/bills/:userId', controllers.getBills);
router.put('/bill/:billId', controllers.updateBill);
router.delete('/bill/:billId', controllers.deleteBill);

router.post('/payment', controllers.processPayment);
router.get('/payments/:userId', controllers.getPayments);

router.post('/scheduler/run', controllers.runScheduler);

module.exports = router;
13 changes: 13 additions & 0 deletions backend/services/billPaymentScheduler/schedulerService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SchedulerService: manages recurring schedules

const BillService = require('./billService');

class SchedulerService {
static runScheduler() {
// Run recurring bill scheduling
BillService.scheduleRecurringBills();
console.log('Recurring bills scheduled.');
}
}

module.exports = SchedulerService;
36 changes: 36 additions & 0 deletions backend/services/billPaymentScheduler/tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Unit/integration tests

const BillService = require('./billService');
const PaymentService = require('./paymentService');
const ReminderService = require('./reminderService');
const SchedulerService = require('./schedulerService');

function runTests() {
// Create user and bills
const user = { id: 1, name: 'Alice', email: 'alice@example.com', phone: '1234567890' };
const bill1 = BillService.createBill({ userId: user.id, name: 'Electricity', amount: 100, dueDate: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000).toISOString(), recurring: true, frequency: 'monthly', paymentMethodId: 1 });
const bill2 = BillService.createBill({ userId: user.id, name: 'Internet', amount: 50, dueDate: new Date(Date.now() + 5 * 24 * 60 * 60 * 1000).toISOString(), recurring: true, frequency: 'monthly', paymentMethodId: 1 });

// Get bills
const bills = BillService.getBillsByUser(user.id);
console.log('Bills:', bills);

// Send reminders
ReminderService.sendUpcomingReminders([user], 7);

// Process payment
const payment = PaymentService.processPayment({ billId: bill1.id, userId: user.id, amount: bill1.amount });
console.log('Payment:', payment);

// Mark bill paid
BillService.markBillPaid(bill1.id);

// Run scheduler
SchedulerService.runScheduler();

// Check recurring bill
const updatedBill = BillService.getBillById(bill1.id);
console.log('Updated Bill:', updatedBill);
}

runTests();
38 changes: 38 additions & 0 deletions backend/services/billPaymentScheduler/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Utils: Notification, Logger, PaymentGateway

const Notification = {
sendEmail: (to, subject, message) => {
console.log(`Email sent to ${to}: ${subject} - ${message}`);
return true;
},
sendSMS: (to, message) => {
console.log(`SMS sent to ${to}: ${message}`);
return true;
}
};

const Logger = {
log: (msg) => {
console.log(`[LOG] ${new Date().toISOString()} - ${msg}`);
},
error: (msg) => {
console.error(`[ERROR] ${new Date().toISOString()} - ${msg}`);
}
};

const PaymentGateway = {
process: (paymentInfo) => {
// Simulate payment gateway
return {
transactionId: 'TXN' + Math.floor(Math.random() * 1000000),
status: 'success',
timestamp: new Date().toISOString()
};
}
};

module.exports = {
Notification,
Logger,
PaymentGateway
};
Loading