diff --git a/backend/services/billPaymentScheduler/billService.js b/backend/services/billPaymentScheduler/billService.js new file mode 100644 index 0000000..22b4ce3 --- /dev/null +++ b/backend/services/billPaymentScheduler/billService.js @@ -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; diff --git a/backend/services/billPaymentScheduler/controllers.js b/backend/services/billPaymentScheduler/controllers.js new file mode 100644 index 0000000..2ce31e0 --- /dev/null +++ b/backend/services/billPaymentScheduler/controllers.js @@ -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; diff --git a/backend/services/billPaymentScheduler/models.js b/backend/services/billPaymentScheduler/models.js new file mode 100644 index 0000000..0ccd102 --- /dev/null +++ b/backend/services/billPaymentScheduler/models.js @@ -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 +}; diff --git a/backend/services/billPaymentScheduler/paymentService.js b/backend/services/billPaymentScheduler/paymentService.js new file mode 100644 index 0000000..c0fe9ce --- /dev/null +++ b/backend/services/billPaymentScheduler/paymentService.js @@ -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; diff --git a/backend/services/billPaymentScheduler/reminderService.js b/backend/services/billPaymentScheduler/reminderService.js new file mode 100644 index 0000000..fc0621e --- /dev/null +++ b/backend/services/billPaymentScheduler/reminderService.js @@ -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; diff --git a/backend/services/billPaymentScheduler/routes.js b/backend/services/billPaymentScheduler/routes.js new file mode 100644 index 0000000..1b6ca0f --- /dev/null +++ b/backend/services/billPaymentScheduler/routes.js @@ -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; diff --git a/backend/services/billPaymentScheduler/schedulerService.js b/backend/services/billPaymentScheduler/schedulerService.js new file mode 100644 index 0000000..3f6c770 --- /dev/null +++ b/backend/services/billPaymentScheduler/schedulerService.js @@ -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; diff --git a/backend/services/billPaymentScheduler/tests.js b/backend/services/billPaymentScheduler/tests.js new file mode 100644 index 0000000..1600472 --- /dev/null +++ b/backend/services/billPaymentScheduler/tests.js @@ -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(); diff --git a/backend/services/billPaymentScheduler/utils.js b/backend/services/billPaymentScheduler/utils.js new file mode 100644 index 0000000..a0fc8da --- /dev/null +++ b/backend/services/billPaymentScheduler/utils.js @@ -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 +};