In the dynamic world of car repair and maintenance, effective data management is crucial for ensuring smooth operations and excellent customer service. A well-designed database can streamline numerous processes, from tracking customer interactions to managing repair schedules and handling billing. In this article, we will explore how to design and implement a comprehensive database for a car repair shop using MongoDB.
MongoDB, a NoSQL database, offers flexibility and scalability, making it an ideal choice for a car repair shop that needs to handle diverse data types and relationships. Our database design will encompass several key modules, including repair shops and employees, customers and contacts, vehicles, services and offers, and visits. Additionally, we will incorporate essential features such as notification systems for repair status updates, a billing system using Stripe, and a photo upload mechanism for employees to share images of car parts and repairs with customers.
Key Modules and Their Functions
1. Repair Shops & Employees
This module will cover the setup and management of repair shops and their employees. It includes creating repair shop records, managing employee information, and scheduling employee work shifts. Key features include tracking employee start and end dates, positions, and active status, as well as maintaining detailed work schedules.
2. Customers & Contacts
Managing customer data and interactions is critical for any service-oriented business. This module will handle customer information, including personal details, contact information, and interaction history. By tracking every contact with customers, the system can ensure that no communication is overlooked and that customer service remains top-notch.
3. Vehicles
A car repair shop needs to manage a wide variety of vehicles, from different makes and models to individual vehicle histories. This module will include defining vehicle makes and models, recording vehicle details, and associating vehicles with their respective owners. It will also facilitate regulatory reporting and insurance claims by maintaining comprehensive vehicle records.
4. Services & Offers
Offering a variety of services and creating customized offers for customers is a core function of a car repair shop. This module will manage service catalogs, individual tasks, and customer offers. It will include defining service details, applying discounts, and tracking the status of each offer made to customers.
5. Visits
Tracking customer visits to the repair shop is essential for managing workflow and ensuring timely service delivery. This module will record visit details, including planned and actual start and end times, services performed, and any tasks completed during the visit. It will also handle financial transactions related to each visit, from invoicing to payment processing.
6. Notification System
Keeping customers informed about the status of their repairs is a critical aspect of customer service. This module will handle notifications, alerting customers when repairs start and finish. By ensuring timely communication, the shop can enhance customer satisfaction and trust.
7. Billing System
Handling payments efficiently is crucial for the financial health of any business. This module will integrate with Stripe to manage billing and payments. It will include creating invoices, tracking payment due dates, and recording when payments are made.
8. Photo Upload System
Allowing employees to share photos of car parts and repairs can enhance transparency and communication with customers. This module will use Multer for handling file uploads and Cloudinary for storing images. It will enable employees to upload images that customers can view, providing a visual record of the repair process.
Module 1: Repair Shops & Employees
In this first module, we will set up the foundational entities for managing repair shops and their employees. This includes creating schemas for repair shops, employees, and employee schedules. By the end of this module, you will have a working system to manage and track the employees of a car repair shop, along with their work schedules.
Step-by-Step Guide
Step 1: Set up MongoDB
- Install MongoDB on your system if you haven’t already. You can download it from the official MongoDB website.
- Create a new database for the car repair shop. You can do this via the MongoDB shell or using a GUI tool like MongoDB Compass.
Step 2: Create Repair Shop Schema
The RepairShop
schema will store basic information about each repair shop.
const mongoose = require('mongoose');
const repairShopSchema = new mongoose.Schema({
name: { type: String, required: true },
address: { type: String, required: true },
phone: { type: String, required: true },
email: { type: String, required: true }
});
const RepairShop = mongoose.model('RepairShop', repairShopSchema);
module.exports = RepairShop;
Step 3: Create Employee Schema
The Employee
schema will store information about the employees working at the repair shop
const employeeSchema = new mongoose.Schema({
first_name: { type: String, required: true },
last_name: { type: String, required: true },
employment_start_date: { type: Date, required: true },
employment_end_date: { type: Date },
position_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Position', required: true },
city_id: { type: mongoose.Schema.Types.ObjectId, ref: 'City', required: true },
is_active: { type: Boolean, default: true }
});
const Employee = mongoose.model('Employee', employeeSchema);
module.exports = Employee;
Step 4: Create Schedule Schema
The Schedule
schema will store the work schedules of employees.
const scheduleSchema = new mongoose.Schema({
repair_shop_id: { type: mongoose.Schema.Types.ObjectId, ref: 'RepairShop', required: true },
employee_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Employee', required: true },
position_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Position', required: true },
schedule_date: { type: Date, required: true },
time_from: { type: String, required: true },
time_to: { type: String, required: true },
plan: { type: Boolean, default: true },
actual: { type: Boolean, default: true },
insert_ts: { type: Date, default: Date.now }
});
const Schedule = mongoose.model('Schedule', scheduleSchema);
module.exports = Schedule;
Step 5: Testing the Module
Testing is a crucial step to ensure that our schemas and relationships work correctly. We’ll use Mocha and Chai for writing and running tests.
Install Mocha and Chai
npm install mocha chai --save-dev
Create Test File Create a test file named test.js
in the root directory of your project.
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const RepairShop = require('./models/RepairShop');
const Employee = require('./models/Employee');
const Schedule = require('./models/Schedule');
describe('Repair Shop and Employee Module', () => {
before((done) => {
mongoose.connect('mongodb://localhost/car_repair_shop', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', () => done()).on('error', (error) => done(error));
});
it('should create a repair shop', (done) => {
const repairShop = new RepairShop({ name: 'AutoFix', address: '123 Main St', phone: '555-1234', email: 'contact@autofix.com' });
repairShop.save((err, savedRepairShop) => {
expect(savedRepairShop.name).to.equal('AutoFix');
done();
});
});
it('should create an employee', (done) => {
const employee = new Employee({ first_name: 'John', last_name: 'Doe', employment_start_date: new Date(), position_id: new mongoose.Types.ObjectId(), city_id: new mongoose.Types.ObjectId(), is_active: true });
employee.save((err, savedEmployee) => {
expect(savedEmployee.first_name).to.equal('John');
done();
});
});
it('should create a schedule', (done) => {
const schedule = new Schedule({ repair_shop_id: new mongoose.Types.ObjectId(), employee_id: new mongoose.Types.ObjectId(), position_id: new mongoose.Types.ObjectId(), schedule_date: new Date(), time_from: '09:00', time_to: '17:00', plan: true, actual: true });
schedule.save((err, savedSchedule) => {
expect(savedSchedule.time_from).to.equal('09:00');
done();
});
});
});
Run the Tests Run the tests using Mocha.
npx mocha test.js
By following these steps, you will have successfully created the foundational module for managing repair shops and employees in your car repair shop database. This module sets the stage for building more complex features and ensures that the core entities are correctly structured and tested.
Module 2: Customers & Contacts
In this module, we will set up the entities and relationships necessary to manage customers and their contacts. This includes creating schemas for customers, contact types, and contacts. By the end of this module, you will have a system to manage customer information and track interactions with them.
Step-by-Step Guide
Step 1: Create Customer Schema
The Customer
schema will store basic information about each customer.
const mongoose = require('mongoose');
const customerSchema = new mongoose.Schema({
first_name: { type: String },
last_name: { type: String },
company_name: { type: String },
address: { type: String, required: true },
mobile: { type: String, required: true },
email: { type: String, required: true },
details: { type: String },
insert_ts: { type: Date, default: Date.now }
});
const Customer = mongoose.model('Customer', customerSchema);
module.exports = Customer;
Step 2: Create Contact Type Schema
The ContactType
schema will store the types of contacts we have with customers.
const contactTypeSchema = new mongoose.Schema({
type_name: { type: String, unique: true, required: true }
});
const ContactType = mongoose.model('ContactType', contactTypeSchema);
module.exports = ContactType;
Step 3: Create Contact Schema
The Contact
schema will store information about each contact we have with customers.
const contactSchema = new mongoose.Schema({
contact_type_id: { type: mongoose.Schema.Types.ObjectId, ref: 'ContactType', required: true },
customer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
employee_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Employee', required: true },
details: { type: String },
insert_ts: { type: Date, default: Date.now }
});
const Contact = mongoose.model('Contact', contactSchema);
module.exports = Contact;
Step 4: Testing the Module
To ensure that our schemas and relationships work correctly, we will write unit tests. We will use Mocha and Chai for this purpose.
Update Test File
Add tests for the new schemas in the
test.js
file.
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const RepairShop = require('./models/RepairShop');
const Employee = require('./models/Employee');
const Schedule = require('./models/Schedule');
const Customer = require('./models/Customer');
const ContactType = require('./models/ContactType');
const Contact = require('./models/Contact');
describe('Customer and Contact Module', () => {
before((done) => {
mongoose.connect('mongodb://localhost/car_repair_shop', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', () => done()).on('error', (error) => done(error));
});
it('should create a customer', (done) => {
const customer = new Customer({ first_name: 'Jane', last_name: 'Doe', address: '456 Elm St', mobile: '555-5678', email: 'jane.doe@example.com' });
customer.save((err, savedCustomer) => {
expect(savedCustomer.first_name).to.equal('Jane');
done();
});
});
it('should create a contact type', (done) => {
const contactType = new ContactType({ type_name: 'Phone Call' });
contactType.save((err, savedContactType) => {
expect(savedContactType.type_name).to.equal('Phone Call');
done();
});
});
it('should create a contact', (done) => {
const contactType = new ContactType({ type_name: 'Email' });
contactType.save((err, savedContactType) => {
const customer = new Customer({ first_name: 'John', last_name: 'Smith', address: '789 Oak St', mobile: '555-7890', email: 'john.smith@example.com' });
customer.save((err, savedCustomer) => {
const employee = new Employee({ first_name: 'Alice', last_name: 'Johnson', employment_start_date: new Date(), position_id: new mongoose.Types.ObjectId(), city_id: new mongoose.Types.ObjectId(), is_active: true });
employee.save((err, savedEmployee) => {
const contact = new Contact({
contact_type_id: savedContactType._id,
customer_id: savedCustomer._id,
employee_id: savedEmployee._id,
details: 'Discussed repair details over email.'
});
contact.save((err, savedContact) => {
expect(savedContact.details).to.equal('Discussed repair details over email.');
done();
});
});
});
});
});
});
Run the Tests
Run the tests using Mocha.
npx mocha test.js
By following these steps, you will have successfully created the module for managing customers and their contacts in your car repair shop database. This module allows for the storage and tracking of customer information and interactions, providing a solid foundation for customer relationship management.
Module 3: Vehicles
In this module, we will set up the entities and relationships necessary to manage vehicles in the car repair shop. This includes creating schemas for vehicle makes, models, types, and the vehicles themselves. By the end of this module, you will have a system to manage detailed information about the vehicles serviced by the repair shop.
Step-by-Step Guide
Step 1: Create Make Schema
The Make
schema will store information about different vehicle manufacturers.
const mongoose = require('mongoose');
const makeSchema = new mongoose.Schema({
make_name: { type: String, unique: true, required: true }
});
const Make = mongoose.model('Make', makeSchema);
module.exports = Make;
Step 2: Create Vehicle Type Schema
The VehicleType
schema will store information about different types of vehicles.
const vehicleTypeSchema = new mongoose.Schema({
type_name: { type: String, unique: true, required: true }
});
const VehicleType = mongoose.model('VehicleType', vehicleTypeSchema);
module.exports = VehicleType;
Step 3: Create Model Schema
The Model
schema will store information about different vehicle models.
const modelSchema = new mongoose.Schema({
model_name: { type: String, required: true },
make_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Make', required: true },
vehicle_type_id: { type: mongoose.Schema.Types.ObjectId, ref: 'VehicleType', required: true }
});
const Model = mongoose.model('Model', modelSchema);
module.exports = Model;
Step 4: Create Vehicle Schema
The Vehicle
schema will store detailed information about individual vehicles.
const vehicleSchema = new mongoose.Schema({
vin: { type: String, unique: true, required: true },
license_plate: { type: String, required: true },
customer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
model_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Model', required: true },
manufactured_year: { type: Number, required: true },
manufactured_month: { type: Number, required: true },
details: { type: String },
insert_ts: { type: Date, default: Date.now }
});
const Vehicle = mongoose.model('Vehicle', vehicleSchema);
module.exports = Vehicle;
Step 5: Testing the Module
To ensure that our schemas and relationships work correctly, we will write unit tests. We will use Mocha and Chai for this purpose.
Update Test File
Add tests for the new schemas in the
test.js
file.
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const RepairShop = require('./models/RepairShop');
const Employee = require('./models/Employee');
const Schedule = require('./models/Schedule');
const Customer = require('./models/Customer');
const ContactType = require('./models/ContactType');
const Contact = require('./models/Contact');
const Make = require('./models/Make');
const VehicleType = require('./models/VehicleType');
const Model = require('./models/Model');
const Vehicle = require('./models/Vehicle');
describe('Vehicle Module', () => {
before((done) => {
mongoose.connect('mongodb://localhost/car_repair_shop', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', () => done()).on('error', (error) => done(error));
});
it('should create a vehicle make', (done) => {
const make = new Make({ make_name: 'Toyota' });
make.save((err, savedMake) => {
expect(savedMake.make_name).to.equal('Toyota');
done();
});
});
it('should create a vehicle type', (done) => {
const vehicleType = new VehicleType({ type_name: 'Sedan' });
vehicleType.save((err, savedVehicleType) => {
expect(savedVehicleType.type_name).to.equal('Sedan');
done();
});
});
it('should create a vehicle model', (done) => {
const make = new Make({ make_name: 'Honda' });
make.save((err, savedMake) => {
const vehicleType = new VehicleType({ type_name: 'Coupe' });
vehicleType.save((err, savedVehicleType) => {
const model = new Model({ model_name: 'Civic', make_id: savedMake._id, vehicle_type_id: savedVehicleType._id });
model.save((err, savedModel) => {
expect(savedModel.model_name).to.equal('Civic');
done();
});
});
});
});
it('should create a vehicle', (done) => {
const customer = new Customer({ first_name: 'Michael', last_name: 'Brown', address: '123 Maple St', mobile: '555-1122', email: 'michael.brown@example.com' });
customer.save((err, savedCustomer) => {
const make = new Make({ make_name: 'Ford' });
make.save((err, savedMake) => {
const vehicleType = new VehicleType({ type_name: 'SUV' });
vehicleType.save((err, savedVehicleType) => {
const model = new Model({ model_name: 'Explorer', make_id: savedMake._id, vehicle_type_id: savedVehicleType._id });
model.save((err, savedModel) => {
const vehicle = new Vehicle({
vin: '1FTFW1ET4EKF12345',
license_plate: 'ABC123',
customer_id: savedCustomer._id,
model_id: savedModel._id,
manufactured_year: 2014,
manufactured_month: 6,
details: 'Black exterior, leather seats'
});
vehicle.save((err, savedVehicle) => {
expect(savedVehicle.vin).to.equal('1FTFW1ET4EKF12345');
done();
});
});
});
});
});
});
});
Run the Tests
Run the tests using Mocha.
npx mocha test.js
By following these steps, you will have successfully created the module for managing vehicles in your car repair shop database. This module allows for the storage and tracking of detailed information about vehicles, including their makes, models, and ownership, providing a comprehensive system for vehicle management.
Module 4: Services & Offers
In this module, we will set up the entities and relationships necessary to manage the services and offers provided by the car repair shop. This includes creating schemas for service catalogs, task catalogs, offers, and offer tasks. By the end of this module, you will have a system to manage the services offered to customers and track the tasks involved in those services.
Step-by-Step Guide
Step 1: Create Service Catalog Schema
The ServiceCatalog
schema will store information about the different services offered by the repair shop.
const mongoose = require('mongoose');
const serviceCatalogSchema = new mongoose.Schema({
service_name: { type: String, required: true },
description: { type: String },
service_discount: { type: Number, default: 0 },
is_active: { type: Boolean, default: true }
});
const ServiceCatalog = mongoose.model('ServiceCatalog', serviceCatalogSchema);
module.exports = ServiceCatalog;
Step 2: Create Task Catalog Schema
The TaskCatalog
schema will store information about the tasks that make up each service.
const taskCatalogSchema = new mongoose.Schema({
task_name: { type: String, required: true },
service_catalog_id: { type: mongoose.Schema.Types.ObjectId, ref: 'ServiceCatalog', required: true },
description: { type: String },
ref_interval: { type: Boolean, default: false },
ref_interval_min: { type: Number },
ref_interval_max: { type: Number },
task_price: { type: Number, required: true },
is_active: { type: Boolean, default: true }
});
const TaskCatalog = mongoose.model('TaskCatalog', taskCatalogSchema);
module.exports = TaskCatalog;
Step 3: Create Offer Schema
The Offer
schema will store information about the offers made to customers.
const offerSchema = new mongoose.Schema({
customer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
contact_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Contact' },
offer_description: { type: String },
service_catalog_id: { type: mongoose.Schema.Types.ObjectId, ref: 'ServiceCatalog' },
service_discount: { type: Number },
offer_price: { type: Number, required: true },
insert_ts: { type: Date, default: Date.now }
});
const Offer = mongoose.model('Offer', offerSchema);
module.exports = Offer;
Step 4: Create Offer Task Schema
The OfferTask
schema will store information about the tasks included in each offer.
const offerTaskSchema = new mongoose.Schema({
offer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Offer', required: true },
task_catalog_id: { type: mongoose.Schema.Types.ObjectId, ref: 'TaskCatalog', required: true },
task_price: { type: Number, required: true },
insert_ts: { type: Date, default: Date.now }
});
const OfferTask = mongoose.model('OfferTask', offerTaskSchema);
module.exports = OfferTask;
Step 5: Testing the Module
To ensure that our schemas and relationships work correctly, we will write unit tests. We will use Mocha and Chai for this purpose.
Update Test File
Add tests for the new schemas in the
test.js
file.
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const RepairShop = require('./models/RepairShop');
const Employee = require('./models/Employee');
const Schedule = require('./models/Schedule');
const Customer = require('./models/Customer');
const ContactType = require('./models/ContactType');
const Contact = require('./models/Contact');
const Make = require('./models/Make');
const VehicleType = require('./models/VehicleType');
const Model = require('./models/Model');
const Vehicle = require('./models/Vehicle');
const ServiceCatalog = require('./models/ServiceCatalog');
const TaskCatalog = require('./models/TaskCatalog');
const Offer = require('./models/Offer');
const OfferTask = require('./models/OfferTask');
describe('Service and Offer Module', () => {
before((done) => {
mongoose.connect('mongodb://localhost/car_repair_shop', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', () => done()).on('error', (error) => done(error));
});
it('should create a service catalog', (done) => {
const serviceCatalog = new ServiceCatalog({ service_name: 'Oil Change', description: 'Change engine oil and filter', service_discount: 10 });
serviceCatalog.save((err, savedServiceCatalog) => {
expect(savedServiceCatalog.service_name).to.equal('Oil Change');
done();
});
});
it('should create a task catalog', (done) => {
const serviceCatalog = new ServiceCatalog({ service_name: 'Brake Service', description: 'Brake pad replacement', service_discount: 15 });
serviceCatalog.save((err, savedServiceCatalog) => {
const taskCatalog = new TaskCatalog({
task_name: 'Brake Pad Replacement',
service_catalog_id: savedServiceCatalog._id,
description: 'Replace front and rear brake pads',
task_price: 200
});
taskCatalog.save((err, savedTaskCatalog) => {
expect(savedTaskCatalog.task_name).to.equal('Brake Pad Replacement');
done();
});
});
});
it('should create an offer', (done) => {
const customer = new Customer({ first_name: 'Sarah', last_name: 'Lee', address: '321 Pine St', mobile: '555-3344', email: 'sarah.lee@example.com' });
customer.save((err, savedCustomer) => {
const serviceCatalog = new ServiceCatalog({ service_name: 'Tire Rotation', description: 'Rotate tires', service_discount: 5 });
serviceCatalog.save((err, savedServiceCatalog) => {
const offer = new Offer({
customer_id: savedCustomer._id,
offer_description: 'Offer for tire rotation',
service_catalog_id: savedServiceCatalog._id,
service_discount: savedServiceCatalog.service_discount,
offer_price: 50
});
offer.save((err, savedOffer) => {
expect(savedOffer.offer_description).to.equal('Offer for tire rotation');
done();
});
});
});
});
it('should create an offer task', (done) => {
const customer = new Customer({ first_name: 'Tom', last_name: 'Cruise', address: '111 Hollywood Blvd', mobile: '555-7777', email: 'tom.cruise@example.com' });
customer.save((err, savedCustomer) => {
const serviceCatalog = new ServiceCatalog({ service_name: 'Full Service', description: 'Complete car checkup', service_discount: 20 });
serviceCatalog.save((err, savedServiceCatalog) => {
const taskCatalog = new TaskCatalog({
task_name: 'Engine Checkup',
service_catalog_id: savedServiceCatalog._id,
description: 'Thorough engine inspection',
task_price: 300
});
taskCatalog.save((err, savedTaskCatalog) => {
const offer = new Offer({
customer_id: savedCustomer._id,
offer_description: 'Offer for full service',
service_catalog_id: savedServiceCatalog._id,
service_discount: savedServiceCatalog.service_discount,
offer_price: 600
});
offer.save((err, savedOffer) => {
const offerTask = new OfferTask({
offer_id: savedOffer._id,
task_catalog_id: savedTaskCatalog._id,
task_price: savedTaskCatalog.task_price
});
offerTask.save((err, savedOfferTask) => {
expect(savedOfferTask.task_price).to.equal(300);
done();
});
});
});
});
});
});
});
Run the Tests
Run the tests using Mocha.
npx mocha test.js
By following these steps, you will have successfully created the module for managing services and offers in your car repair shop database. This module allows for the storage and tracking of services offered to customers and the tasks involved in those services, providing a comprehensive system for service management.
Module 5: Visits
In this module, we will set up the entities and relationships necessary to manage customer visits to the car repair shop. This includes creating schemas for visits and visit tasks. By the end of this module, you will have a system to manage and track customer visits and the tasks performed during those visits.
Step-by-Step Guide
Step 1: Create Visit Schema
The Visit
schema will store information about each customer visit to the repair shop.
const mongoose = require('mongoose');
const visitSchema = new mongoose.Schema({
repair_shop_id: { type: mongoose.Schema.Types.ObjectId, ref: 'RepairShop', required: true },
customer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
vehicle_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Vehicle', required: true },
visit_start_date: { type: Date, required: true },
visit_start_time: { type: String, required: true },
visit_end_date: { type: Date },
visit_end_time: { type: String },
license_plate: { type: String, required: true },
offer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Offer' },
service_catalog_id: { type: mongoose.Schema.Types.ObjectId, ref: 'ServiceCatalog' },
service_discount: { type: Number },
visit_price: { type: Number, required: true },
invoice_created: { type: Date },
invoice_due: { type: Date },
invoice_charged: { type: Date },
insert_ts: { type: Date, default: Date.now }
});
const Visit = mongoose.model('Visit', visitSchema);
module.exports = Visit;
Step 2: Create Visit Task Schema
The VisitTask
schema will store information about the tasks performed during each visit.
const visitTaskSchema = new mongoose.Schema({
visit_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Visit', required: true },
task_catalog_id: { type: mongoose.Schema.Types.ObjectId, ref: 'TaskCatalog', required: true },
value_measured: { type: String },
task_description: { type: String },
pass: { type: Boolean },
task_price: { type: Number, required: true },
insert_ts: { type: Date, default: Date.now }
});
const VisitTask = mongoose.model('VisitTask', visitTaskSchema);
module.exports = VisitTask;
Step 3: Testing the Module
To ensure that our schemas and relationships work correctly, we will write unit tests. We will use Mocha and Chai for this purpose.
Update Test File
Add tests for the new schemas in the
test.js
file.
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const RepairShop = require('./models/RepairShop');
const Employee = require('./models/Employee');
const Schedule = require('./models/Schedule');
const Customer = require('./models/Customer');
const ContactType = require('./models/ContactType');
const Contact = require('./models/Contact');
const Make = require('./models/Make');
const VehicleType = require('./models/VehicleType');
const Model = require('./models/Model');
const Vehicle = require('./models/Vehicle');
const ServiceCatalog = require('./models/ServiceCatalog');
const TaskCatalog = require('./models/TaskCatalog');
const Offer = require('./models/Offer');
const OfferTask = require('./models/OfferTask');
const Visit = require('./models/Visit');
const VisitTask = require('./models/VisitTask');
describe('Visit Module', () => {
before((done) => {
mongoose.connect('mongodb://localhost/car_repair_shop', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', () => done()).on('error', (error) => done(error));
});
it('should create a visit', (done) => {
const repairShop = new RepairShop({ name: 'AutoFix', address: '123 Main St', phone: '555-1234', email: 'contact@autofix.com' });
repairShop.save((err, savedRepairShop) => {
const customer = new Customer({ first_name: 'John', last_name: 'Doe', address: '456 Elm St', mobile: '555-5678', email: 'john.doe@example.com' });
customer.save((err, savedCustomer) => {
const vehicle = new Vehicle({
vin: '1FTFW1ET4EKF54321',
license_plate: 'XYZ789',
customer_id: savedCustomer._id,
model_id: new mongoose.Types.ObjectId(),
manufactured_year: 2015,
manufactured_month: 5,
details: 'Red exterior, cloth seats'
});
vehicle.save((err, savedVehicle) => {
const visit = new Visit({
repair_shop_id: savedRepairShop._id,
customer_id: savedCustomer._id,
vehicle_id: savedVehicle._id,
visit_start_date: new Date(),
visit_start_time: '10:00',
license_plate: 'XYZ789',
visit_price: 150
});
visit.save((err, savedVisit) => {
expect(savedVisit.license_plate).to.equal('XYZ789');
done();
});
});
});
});
});
it('should create a visit task', (done) => {
const visit = new Visit({
repair_shop_id: new mongoose.Types.ObjectId(),
customer_id: new mongoose.Types.ObjectId(),
vehicle_id: new mongoose.Types.ObjectId(),
visit_start_date: new Date(),
visit_start_time: '11:00',
license_plate: 'ABC123',
visit_price: 200
});
visit.save((err, savedVisit) => {
const taskCatalog = new TaskCatalog({
task_name: 'Oil Change',
service_catalog_id: new mongoose.Types.ObjectId(),
description: 'Change engine oil and filter',
task_price: 50
});
taskCatalog.save((err, savedTaskCatalog) => {
const visitTask = new VisitTask({
visit_id: savedVisit._id,
task_catalog_id: savedTaskCatalog._id,
value_measured: 'N/A',
task_description: 'Changed oil filter',
pass: true,
task_price: 50
});
visitTask.save((err, savedVisitTask) => {
expect(savedVisitTask.task_description).to.equal('Changed oil filter');
done();
});
});
});
});
});
Run the Tests
Run the tests using Mocha.
npx mocha test.js
By following these steps, you will have successfully created the module for managing customer visits in your car repair shop database. This module allows for the storage and tracking of detailed information about customer visits and the tasks performed during those visits, providing a comprehensive system for visit management.
Module 6: Notification System
In this module, we will set up a notification system to keep customers informed about the status of their vehicle repairs. The system will send notifications when repairs start and finish. We will use MongoDB to store notification records and integrate a notification service (e.g., email or SMS) to deliver these notifications.
Step-by-Step Guide
Step 1: Create Notification Schema
The Notification
schema will store information about notifications sent to customers.
const mongoose = require('mongoose');
const notificationSchema = new mongoose.Schema({
customer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
vehicle_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Vehicle', required: true },
type: { type: String, enum: ['Repair Started', 'Repair Finished'], required: true },
message: { type: String, required: true },
status: { type: String, enum: ['Sent', 'Pending', 'Failed'], default: 'Pending' },
send_date: { type: Date },
insert_ts: { type: Date, default: Date.now }
});
const Notification = mongoose.model('Notification', notificationSchema);
module.exports = Notification;
Step 2: Notification Service Integration
For this example, let’s use a simple email notification service. We’ll use Nodemailer to send emails. Install Nodemailer:
npm install nodemailer
Step 3: Create Notification Service
Create a file named notificationService.js
to handle sending notifications.
const nodemailer = require('nodemailer');
const Notification = require('./models/Notification');
const transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'your-email@gmail.com',
pass: 'your-email-password'
}
});
const sendNotification = async (notificationId) => {
try {
const notification = await Notification.findById(notificationId).populate('customer_id vehicle_id');
if (!notification) {
throw new Error('Notification not found');
}
const mailOptions = {
from: 'your-email@gmail.com',
to: notification.customer_id.email,
subject: `Notification: ${notification.type}`,
text: notification.message
};
await transporter.sendMail(mailOptions);
notification.status = 'Sent';
notification.send_date = new Date();
await notification.save();
} catch (error) {
console.error('Error sending notification:', error);
const notification = await Notification.findById(notificationId);
notification.status = 'Failed';
await notification.save();
}
};
module.exports = { sendNotification };
Step 4: Update Visit Schema to Trigger Notifications
Update the Visit
schema to trigger notifications when repairs start and finish.
const visitSchema = new mongoose.Schema({
repair_shop_id: { type: mongoose.Schema.Types.ObjectId, ref: 'RepairShop', required: true },
customer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
vehicle_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Vehicle', required: true },
visit_start_date: { type: Date, required: true },
visit_start_time: { type: String, required: true },
visit_end_date: { type: Date },
visit_end_time: { type: String },
license_plate: { type: String, required: true },
offer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Offer' },
service_catalog_id: { type: mongoose.Schema.Types.ObjectId, ref: 'ServiceCatalog' },
service_discount: { type: Number },
visit_price: { type: Number, required: true },
invoice_created: { type: Date },
invoice_due: { type: Date },
invoice_charged: { type: Date },
insert_ts: { type: Date, default: Date.now }
});
// Trigger notifications on save
visitSchema.post('save', async function(doc) {
const Notification = require('./models/Notification');
const { sendNotification } = require('../notificationService');
if (this.isNew) {
// New visit, trigger "Repair Started" notification
const notification = new Notification({
customer_id: doc.customer_id,
vehicle_id: doc.vehicle_id,
type: 'Repair Started',
message: `Repair has started for your vehicle with license plate ${doc.license_plate}.`
});
const savedNotification = await notification.save();
sendNotification(savedNotification._id);
} else if (this.visit_end_date && this.visit_end_time) {
// Visit end date and time set, trigger "Repair Finished" notification
const notification = new Notification({
customer_id: doc.customer_id,
vehicle_id: doc.vehicle_id,
type: 'Repair Finished',
message: `Repair has been completed for your vehicle with license plate ${doc.license_plate}.`
});
const savedNotification = await notification.save();
sendNotification(savedNotification._id);
}
});
const Visit = mongoose.model('Visit', visitSchema);
module.exports = Visit;
Step 5: Testing the Module
To ensure that our notification system works correctly, we will write unit tests. We will use Mocha and Chai for this purpose.
Update Test File
Add tests for the new notification functionality in the
test.js
file.
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const RepairShop = require('./models/RepairShop');
const Customer = require('./models/Customer');
const Vehicle = require('./models/Vehicle');
const Visit = require('./models/Visit');
const Notification = require('./models/Notification');
describe('Notification Module', () => {
before((done) => {
mongoose.connect('mongodb://localhost/car_repair_shop', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', () => done()).on('error', (error) => done(error));
});
it('should trigger a "Repair Started" notification', (done) => {
const repairShop = new RepairShop({ name: 'AutoFix', address: '123 Main St', phone: '555-1234', email: 'contact@autofix.com' });
repairShop.save((err, savedRepairShop) => {
const customer = new Customer({ first_name: 'John', last_name: 'Doe', address: '456 Elm St', mobile: '555-5678', email: 'john.doe@example.com' });
customer.save((err, savedCustomer) => {
const vehicle = new Vehicle({
vin: '1FTFW1ET4EKF54321',
license_plate: 'XYZ789',
customer_id: savedCustomer._id,
model_id: new mongoose.Types.ObjectId(),
manufactured_year: 2015,
manufactured_month: 5,
details: 'Red exterior, cloth seats'
});
vehicle.save((err, savedVehicle) => {
const visit = new Visit({
repair_shop_id: savedRepairShop._id,
customer_id: savedCustomer._id,
vehicle_id: savedVehicle._id,
visit_start_date: new Date(),
visit_start_time: '10:00',
license_plate: 'XYZ789',
visit_price: 150
});
visit.save(async (err, savedVisit) => {
const notifications = await Notification.find({ customer_id: savedCustomer._id });
expect(notifications).to.have.lengthOf(1);
expect(notifications[0].type).to.equal('Repair Started');
done();
});
});
});
});
});
it('should trigger a "Repair Finished" notification', (done) => {
const visit = new Visit({
repair_shop_id: new mongoose.Types.ObjectId(),
customer_id: new mongoose.Types.ObjectId(),
vehicle_id: new mongoose.Types.ObjectId(),
visit_start_date: new Date(),
visit_start_time: '11:00',
visit_end_date: new Date(),
visit_end_time: '12:00',
license_plate: 'ABC123',
visit_price: 200
});
visit.save(async (err, savedVisit) => {
const notifications = await Notification.find({ customer_id: savedVisit.customer_id });
expect
Run the Tests
Run the tests using Mocha.
npx mocha test.js
By following these steps, you will have successfully created the notification system for your car repair shop database. This module allows for sending notifications to customers when their vehicle repairs start and finish, enhancing customer communication and service.
Module 7: Billing System
In this module, we will set up the billing system for the car repair shop, integrating it with Stripe to handle billing and payments. This includes creating schemas for invoices and integrating with the Stripe API to manage payments.
Step-by-Step Guide
Step 1: Create Invoice Schema
The Invoice
schema will store information about invoices generated for customer visits.
const mongoose = require('mongoose');
const invoiceSchema = new mongoose.Schema({
visit_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Visit', required: true },
customer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
amount: { type: Number, required: true },
currency: { type: String, default: 'USD' },
status: { type: String, enum: ['Pending', 'Paid', 'Failed'], default: 'Pending' },
stripe_invoice_id: { type: String },
created_at: { type: Date, default: Date.now },
paid_at: { type: Date }
});
const Invoice = mongoose.model('Invoice', invoiceSchema);
module.exports = Invoice;
Step 2: Install Stripe SDK
Install the Stripe SDK to handle billing and payments.
npm install stripe
Step 3: Create Billing Service
Create a file named billingService.js
to handle Stripe integration.
const stripe = require('stripe')('your-stripe-secret-key');
const Invoice = require('./models/Invoice');
const createStripeInvoice = async (invoiceId) => {
try {
const invoice = await Invoice.findById(invoiceId).populate('customer_id visit_id');
if (!invoice) {
throw new Error('Invoice not found');
}
const customer = invoice.customer_id;
const visit = invoice.visit_id;
const stripeCustomer = await stripe.customers.create({
name: `${customer.first_name} ${customer.last_name}`,
email: customer.email,
address: {
line1: customer.address
}
});
const stripeInvoiceItem = await stripe.invoiceItems.create({
customer: stripeCustomer.id,
amount: invoice.amount * 100, // amount in cents
currency: invoice.currency,
description: `Invoice for visit on ${visit.visit_start_date}`
});
const stripeInvoice = await stripe.invoices.create({
customer: stripeCustomer.id,
auto_advance: true // automatically finalize and pay the invoice
});
invoice.stripe_invoice_id = stripeInvoice.id;
invoice.status = 'Pending';
await invoice.save();
return stripeInvoice;
} catch (error) {
console.error('Error creating Stripe invoice:', error);
const invoice = await Invoice.findById(invoiceId);
invoice.status = 'Failed';
await invoice.save();
}
};
module.exports = { createStripeInvoice };
Step 4: Update Visit Schema to Generate Invoices
Update the Visit
schema to generate invoices when a visit is completed.
const visitSchema = new mongoose.Schema({
repair_shop_id: { type: mongoose.Schema.Types.ObjectId, ref: 'RepairShop', required: true },
customer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
vehicle_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Vehicle', required: true },
visit_start_date: { type: Date, required: true },
visit_start_time: { type: String, required: true },
visit_end_date: { type: Date },
visit_end_time: { type: String },
license_plate: { type: String, required: true },
offer_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Offer' },
service_catalog_id: { type: mongoose.Schema.Types.ObjectId, ref: 'ServiceCatalog' },
service_discount: { type: Number },
visit_price: { type: Number, required: true },
invoice_created: { type: Date },
invoice_due: { type: Date },
invoice_charged: { type: Date },
insert_ts: { type: Date, default: Date.now }
});
// Trigger invoice creation on visit completion
visitSchema.post('save', async function(doc) {
const Invoice = require('./models/Invoice');
const { createStripeInvoice } = require('../billingService');
if (doc.visit_end_date && doc.visit_end_time && !doc.invoice_created) {
// Visit completed, create invoice
const invoice = new Invoice({
visit_id: doc._id,
customer_id: doc.customer_id,
amount: doc.visit_price
});
const savedInvoice = await invoice.save();
createStripeInvoice(savedInvoice._id);
doc.invoice_created = new Date();
await doc.save();
}
});
const Visit = mongoose.model('Visit', visitSchema);
module.exports = Visit;
Step 5: Testing the Module
To ensure that our billing system works correctly, we will write unit tests. We will use Mocha and Chai for this purpose.
Update Test File
Add tests for the new billing functionality in the
test.js
file.
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const RepairShop = require('./models/RepairShop');
const Customer = require('./models/Customer');
const Vehicle = require('./models/Vehicle');
const Visit = require('./models/Visit');
const Invoice = require('./models/Invoice');
const { createStripeInvoice } = require('../billingService');
describe('Billing Module', () => {
before((done) => {
mongoose.connect('mongodb://localhost/car_repair_shop', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', () => done()).on('error', (error) => done(error));
});
it('should create an invoice when visit is completed', (done) => {
const repairShop = new RepairShop({ name: 'AutoFix', address: '123 Main St', phone: '555-1234', email: 'contact@autofix.com' });
repairShop.save((err, savedRepairShop) => {
const customer = new Customer({ first_name: 'John', last_name: 'Doe', address: '456 Elm St', mobile: '555-5678', email: 'john.doe@example.com' });
customer.save((err, savedCustomer) => {
const vehicle = new Vehicle({
vin: '1FTFW1ET4EKF54321',
license_plate: 'XYZ789',
customer_id: savedCustomer._id,
model_id: new mongoose.Types.ObjectId(),
manufactured_year: 2015,
manufactured_month: 5,
details: 'Red exterior, cloth seats'
});
vehicle.save((err, savedVehicle) => {
const visit = new Visit({
repair_shop_id: savedRepairShop._id,
customer_id: savedCustomer._id,
vehicle_id: savedVehicle._id,
visit_start_date: new Date(),
visit_start_time: '10:00',
visit_end_date: new Date(),
visit_end_time: '11:00',
license_plate: 'XYZ789',
visit_price: 150
});
visit.save(async (err, savedVisit) => {
const invoices = await Invoice.find({ visit_id: savedVisit._id });
expect(invoices).to.have.lengthOf(1);
expect(invoices[0].amount).to.equal(150);
done();
});
});
});
});
});
it('should create a Stripe invoice', (done) => {
const invoice = new Invoice({
visit_id: new mongoose.Types.ObjectId(),
customer_id: new mongoose.Types.ObjectId(),
amount: 200
});
invoice.save(async (err, savedInvoice) => {
const stripeInvoice = await createStripeInvoice(savedInvoice._id);
expect(stripeInvoice).to.have.property('id');
expect(stripeInvoice.amount_due).to.equal(200 * 100); // amount in cents
done();
});
});
});
Run the Tests
Run the tests using Mocha.
npx mocha test.js
By following these steps, you will have successfully created the billing system for your car repair shop database. This module allows for generating and managing invoices using Stripe, ensuring efficient handling of billing and payments.
Module 8: Photo Upload System
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.
In this module, we will set up a system for employees to upload photos of car parts or repairs. We will use Multer for handling file uploads and Cloudinary for storing images. This module includes creating schemas for storing photo metadata and integrating with Multer and Cloudinary to handle the file upload process.
Step-by-Step Guide
Step 1: Install Multer and Cloudinary
First, install the necessary packages for file uploads and image storage.
npm install multer cloudinary multer-storage-cloudinary
Step 2: Configure Cloudinary
Create a cloudinaryConfig.js
file to configure Cloudinary.
const cloudinary = require('cloudinary').v2;
cloudinary.config({
cloud_name: 'your-cloud-name',
api_key: 'your-api-key',
api_secret: 'your-api-secret'
});
module.exports = cloudinary;
Step 3: Create Photo Schema
The Photo
schema will store metadata about the uploaded photos.
const mongoose = require('mongoose');
const photoSchema = new mongoose.Schema({
employee_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Employee', required: true },
vehicle_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Vehicle', required: true },
url: { type: String, required: true },
public_id: { type: String, required: true },
created_at: { type: Date, default: Date.now }
});
const Photo = mongoose.model('Photo', photoSchema);
module.exports = Photo;
Step 4: Set Up Multer with Cloudinary
Create a multerConfig.js
file to configure Multer with Cloudinary.
const multer = require('multer');
const { CloudinaryStorage } = require('multer-storage-cloudinary');
const cloudinary = require('./cloudinaryConfig');
const storage = new CloudinaryStorage({
cloudinary: cloudinary,
params: {
folder: 'car_repair_photos',
format: async (req, file) => 'jpeg', // supports promises as well
public_id: (req, file) => file.originalname
}
});
const upload = multer({ storage: storage });
module.exports = upload;
Step 5: Create Photo Upload Endpoint
Create an endpoint for handling photo uploads.
const express = require('express');
const router = express.Router();
const upload = require('../multerConfig');
const Photo = require('../models/Photo');
// Endpoint to upload photo
router.post('/upload', upload.single('photo'), async (req, res) => {
try {
const { employee_id, vehicle_id } = req.body;
const { path, filename } = req.file;
const photo = new Photo({
employee_id,
vehicle_id,
url: path,
public_id: filename
});
await photo.save();
res.status(200).json({ message: 'Photo uploaded successfully', photo });
} catch (error) {
console.error('Error uploading photo:', error);
res.status(500).json({ error: 'Failed to upload photo' });
}
});
module.exports = router;
Step 6: Testing the Module
To ensure that our photo upload system works correctly, we will write unit tests. We will use Mocha and Chai for this purpose.
Update Test File
Add tests for the new photo upload functionality in the
test.js
file.
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const express = require('express');
const request = require('supertest');
const Employee = require('./models/Employee');
const Vehicle = require('./models/Vehicle');
const Photo = require('./models/Photo');
const uploadRouter = require('../routes/upload');
const app = express();
app.use(express.json());
app.use('/api', uploadRouter);
describe('Photo Upload Module', () => {
before((done) => {
mongoose.connect('mongodb://localhost/car_repair_shop', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', () => done()).on('error', (error) => done(error));
});
it('should upload a photo', (done) => {
const employee = new Employee({ first_name: 'John', last_name: 'Doe', employment_start_date: new Date(), position_id: new mongoose.Types.ObjectId(), city_id: new mongoose.Types.ObjectId(), is_active: true });
employee.save((err, savedEmployee) => {
const vehicle = new Vehicle({
vin: '1FTFW1ET4EKF54321',
license_plate: 'XYZ789',
customer_id: new mongoose.Types.ObjectId(),
model_id: new mongoose.Types.ObjectId(),
manufactured_year: 2015,
manufactured_month: 5,
details: 'Red exterior, cloth seats'
});
vehicle.save((err, savedVehicle) => {
request(app)
.post('/api/upload')
.field('employee_id', savedEmployee._id.toString())
.field('vehicle_id', savedVehicle._id.toString())
.attach('photo', 'test/fixtures/car_part.jpg')
.expect(200)
.end((err, res) => {
if (err) return done(err);
expect(res.body.message).to.equal('Photo uploaded successfully');
expect(res.body.photo).to.have.property('url');
done();
});
});
});
});
});
Run the Tests
Run the tests using Mocha.
npx mocha test.js
By following these steps, you will have successfully created the photo upload system for your car repair shop database. This module allows employees to upload photos of car parts or repairs, providing a visual record of the repair process and enhancing communication with customers.
Welcome to DevTechTutor.com, your ultimate resource for mastering web development and technology! Whether you're a beginner eager to dive into coding or an experienced developer looking to sharpen your skills, DevTechTutor.com is here to guide you every step of the way. Our mission is to make learning web development accessible, engaging, and effective.