From 61f70a54f6ae2a71288b6b4ea14806fd55ea260c Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Wed, 20 May 2026 14:57:10 +0530 Subject: [PATCH] Implement Generate Invoice PAY001: Generate Invoice 1. Added Utility.h to project configuration for supporting invoice generation utilities. 2. Updated Invoice model to use string-based keys for parts mapping instead of integer keys. 3. Implemented PaymentManagementService::generateInvoice to aggregate labour cost, parts cost, and apply discounts. 4. Integrated invoice creation with Factory to instantiate Invoice objects and persist them into datastore. 5. Enhanced Enums with PaymentMode::NOTSET to handle default invoice state. Acceptance Criteria: 1. Invoice auto-generates for each service booking once jobs are completed. 2. Invoice shows a clear breakdown of charges including labour cost, parts cost, discount, and total amount. Precondition: 1. Service booking exists with at least one service and required inventory items. 2. Datastore is available for storing invoices. 3. Payment mode and status enums are properly configured. Steps: 1. Complete all jobs in a service booking. - Verify that PaymentManagementService::generateInvoice is triggered. 2. Check datastore for newly created invoice. - Verify that invoice contains booking ID, labour cost, parts cost, discount, and total amount. 3. Inspect invoice details. - Verify that breakdown of charges is accurate and discount is applied correctly. 4. Confirm invoice status. - Verify that invoice is created with PaymentMode::NOTSET and PaymentStatus::PENDING. Sreeja Reghukumar, please review --- .../Trenser.VehicleServiceSystem.vcxproj | 1 + ...enser.VehicleServiceSystem.vcxproj.filters | 3 + .../models/Invoice.cpp | 7 ++- .../models/Invoice.h | 10 ++-- .../models/JobCard.cpp | 8 +-- .../models/JobCard.h | 10 ++-- .../services/PaymentManagementService.cpp | 56 +++++++++++++++++++ .../utilities/Enums.h | 5 +- .../utilities/Utility.h | 15 +++++ 9 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj index a65c46d..819264c 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj @@ -176,6 +176,7 @@ + diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters index 77d0509..7c17f4e 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters @@ -233,5 +233,8 @@ Header Files\Models + + Header Files\Utilities + \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.cpp index ba7bc84..507f274 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.cpp @@ -16,7 +16,8 @@ Invoice::Invoice( const std::string& bookingId, ServiceBooking* booking, const util::Timestamp& invoiceDate, - double laborCost, const util::Map& parts, double partsCost, double discountPercentage, @@ -63,7 +64,7 @@ double Invoice::getLaborCost() const return m_laborCost; } -const util::Map& Invoice::getParts() const +const util::Map& Invoice::getParts() const { return m_parts; } @@ -123,7 +124,7 @@ void Invoice::setLaborCost(double laborCost) m_laborCost = laborCost; } -void Invoice::setParts(const util::Map& parts) +void Invoice::setParts(const util::Map& parts) { m_parts = parts; } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.h index 212d33f..f78f7c9 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.h @@ -16,7 +16,7 @@ private: ServiceBooking* m_booking; util::Timestamp m_invoiceDate; double m_laborCost; - util::Map m_parts; + util::Map m_parts; double m_partsCost; double m_discountPercentage; double m_totalAmount; @@ -30,8 +30,8 @@ public: const std::string& bookingId, ServiceBooking* booking, const util::Timestamp& invoiceDate, - double laborCost, const util::Map& parts, + double laborCost, + const util::Map& parts, double partsCost, double discountPercentage, double totalAmount, @@ -44,7 +44,7 @@ public: ServiceBooking* getBooking() const; const util::Timestamp& getInvoiceDate() const; double getLaborCost() const; - const util::Map& getParts() const; + const util::Map& getParts() const; double getPartsCost() const; double getDiscountPercentage() const; double getTotalAmount() const; @@ -56,7 +56,7 @@ public: void setBooking(ServiceBooking* booking); void setInvoiceDate(const util::Timestamp& invoiceDate); void setLaborCost(double laborCost); - void setParts(const util::Map& parts); + void setParts(const util::Map& parts); void setPartsCost(double partsCost); void setDiscountPercentage(double discountPercentage); void setTotalAmount(double totalAmount); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp index 04e9195..b9f1eee 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp @@ -7,7 +7,7 @@ JobCard::JobCard() m_booking(nullptr), m_service(nullptr), m_technician(nullptr), - m_status(ServiceJobStatus()) {} + m_status(util::ServiceJobStatus()) {} JobCard::JobCard(const std::string& bookingId, ServiceBooking* booking, @@ -16,7 +16,7 @@ JobCard::JobCard(const std::string& bookingId, const std::string& technicianId, User* technician, const util::Timestamp& assignedDate, - ServiceJobStatus status, + util::ServiceJobStatus status, const util::Timestamp& completionDate ) : m_id("JC" + std::to_string(++m_uid)), @@ -70,7 +70,7 @@ const util::Timestamp& JobCard::getAssignedDate() const return m_assignedDate; } -ServiceJobStatus JobCard::getStatus() const +util::ServiceJobStatus JobCard::getStatus() const { return m_status; } @@ -120,7 +120,7 @@ void JobCard::setAssignedDate(const util::Timestamp& assignedDate) m_assignedDate = assignedDate; } -void JobCard::setStatus(ServiceJobStatus status) +void JobCard::setStatus(util::ServiceJobStatus status) { m_status = status; } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h index 15a8a5d..880767a 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h @@ -1,12 +1,12 @@ #pragma once #include +#include "Enums.h" #include "Timestamp.h" class ServiceBooking; class Service; class User; -enum class ServiceJobStatus : int; class JobCard { @@ -20,7 +20,7 @@ private: std::string m_technicianId; User* m_technician; util::Timestamp m_assignedDate; - ServiceJobStatus m_status; + util::ServiceJobStatus m_status; util::Timestamp m_completionDate; public: @@ -32,7 +32,7 @@ public: const std::string& technicianId, User* technician, const util::Timestamp& assignedDate, - ServiceJobStatus status, + util::ServiceJobStatus status, const util::Timestamp& completionDate ); const std::string& getId() const; @@ -43,7 +43,7 @@ public: const std::string& getTechnicianId() const; User* getTechnician() const; const util::Timestamp& getAssignedDate() const; - ServiceJobStatus getStatus() const; + util::ServiceJobStatus getStatus() const; const util::Timestamp& getCompletionDate() const; void setId(const std::string& id); void setBookingId(const std::string& bookingId); @@ -53,6 +53,6 @@ public: void setTechnicianId(const std::string& technicianId); void setTechnician(User* technician); void setAssignedDate(const util::Timestamp& assignedDate); - void setStatus(ServiceJobStatus status); + void setStatus(util::ServiceJobStatus status); void setCompletionDate(const util::Timestamp& completionDate); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp index 786ebcf..8f391c5 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp @@ -1 +1,57 @@ #include "PaymentManagementService.h" +#include "ServiceBooking.h" +#include "Service.h" +#include "InventoryItem.h" +#include "Utility.h" +#include "Factory.h" +#include "Timestamp.h" +#include "Invoice.h" +#include "JobCard.h" +#include "Enums.h" + +static void createInventoryItemsMap(util::Map& completeInventoryItemMapOfBooking, const Service* currentService) +{ + auto& currentRequiredInventoryItems = currentService->getRequiredInventoryItems(); + for (int iterator = 0; iterator < currentRequiredInventoryItems.getSize(); iterator++) + { + auto& currentRequiredInventoryItem = currentRequiredInventoryItems.getValueAt(iterator); + completeInventoryItemMapOfBooking.insert(currentRequiredInventoryItem->getId(), currentRequiredInventoryItem); + } +} + +void PaymentManagementService::generateInvoice(ServiceBooking* booking) +{ + if (!booking) + { + throw std::runtime_error("Invoice generation failed: booking is null."); + } + double totalLabourCost = 0, totalPartsCost = 0, totalServiceCost = 0; + double discountPercentage = booking->getDiscountPercentage(); + std::string bookingID = booking->getId(); + util::Map servicesInTheBookedService = booking->getServices(); + util::Map completeInventoryItemMapOfBooking; + util::Map currentJobCards = m_dataStore.getJobCards(); + for (int iterator = 0; iterator < currentJobCards.getSize(); iterator++) + { + JobCard* currentJobCard = currentJobCards.getValueAt(iterator); + if (currentJobCard->getBookingId() == bookingID && currentJobCard->getStatus() != util::ServiceJobStatus::COMPLETED) + { + throw std::runtime_error("Invoice generation failed: not all job cards are completed for booking '" + bookingID + "'."); + } + } + for (int iterator = 0; iterator < servicesInTheBookedService.getSize(); iterator++) + { + Service* currentService = servicesInTheBookedService.getValueAt(iterator); + if (currentService) + { + createInventoryItemsMap(completeInventoryItemMapOfBooking, currentService); + totalLabourCost += currentService->getLaborCost(); + totalPartsCost += calculatePartsCost(currentService); + } + } + totalServiceCost = totalLabourCost + totalPartsCost; + totalServiceCost -= (totalServiceCost * (discountPercentage / 100)); + Invoice* invoice = Factory::getObject(bookingID, booking, util::Timestamp(), totalLabourCost, completeInventoryItemMapOfBooking, totalPartsCost, discountPercentage, totalServiceCost, util::Timestamp(), util::PaymentMode::NOTSET, util::PaymentStatus::PENDING); + util::Map& currentInvoices = m_dataStore.getInvoices(); + currentInvoices.insert(invoice->getId(), invoice); +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h index 24bbdcd..5b615b5 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h @@ -13,7 +13,8 @@ namespace util enum class PaymentMode { ONLINE, - OFFLINE + OFFLINE, + NOTSET }; enum class PaymentStatus @@ -73,6 +74,8 @@ namespace util return "ONLINE"; case PaymentMode::OFFLINE: return "OFFLINE"; + case PaymentMode::NOTSET: + return "NOTSET"; } throw std::invalid_argument("Invalid PaymentMode"); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h new file mode 100644 index 0000000..cb9b990 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h @@ -0,0 +1,15 @@ +#pragma once +#include "Service.h" +#include "InventoryItem.h" + +inline double calculatePartsCost(const Service* service) +{ + double cost = 0; + auto& requiredInventoryItems = service->getRequiredInventoryItems(); + int requiredInventoryItemsSize = requiredInventoryItems.getSize(); + for (int index = 0; index < requiredInventoryItemsSize; index++) + { + cost += requiredInventoryItems.getValueAt(index)->getPrice(); + } + return cost; +} \ No newline at end of file