Implement Generate Invoice
<UserStory> PAY001: Generate Invoice </UserStory>
<Changes>
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.
</Changes>
<Test>
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.
</Test>
<Review>
Sreeja Reghukumar, please review
</Review>
This commit is contained in:
+1
@@ -176,6 +176,7 @@
|
||||
<ClInclude Include="utilities\Map.h" />
|
||||
<ClInclude Include="utilities\OutputHelper.h" />
|
||||
<ClInclude Include="utilities\Timestamp.h" />
|
||||
<ClInclude Include="utilities\Utility.h" />
|
||||
<ClInclude Include="utilities\Validator.h" />
|
||||
<ClInclude Include="utilities\Vector.h" />
|
||||
<ClInclude Include="views\AdminMenu.h" />
|
||||
|
||||
+3
@@ -233,5 +233,8 @@
|
||||
<ClInclude Include="models\ComboPackage.h">
|
||||
<Filter>Header Files\Models</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utilities\Utility.h">
|
||||
<Filter>Header Files\Utilities</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -16,7 +16,8 @@ Invoice::Invoice(
|
||||
const std::string& bookingId,
|
||||
ServiceBooking* booking,
|
||||
const util::Timestamp& invoiceDate,
|
||||
double laborCost, const util::Map<int,
|
||||
double laborCost,
|
||||
const util::Map<std::string,
|
||||
InventoryItem*>& parts,
|
||||
double partsCost,
|
||||
double discountPercentage,
|
||||
@@ -63,7 +64,7 @@ double Invoice::getLaborCost() const
|
||||
return m_laborCost;
|
||||
}
|
||||
|
||||
const util::Map<int, InventoryItem*>& Invoice::getParts() const
|
||||
const util::Map<std::string, InventoryItem*>& Invoice::getParts() const
|
||||
{
|
||||
return m_parts;
|
||||
}
|
||||
@@ -123,7 +124,7 @@ void Invoice::setLaborCost(double laborCost)
|
||||
m_laborCost = laborCost;
|
||||
}
|
||||
|
||||
void Invoice::setParts(const util::Map<int, InventoryItem*>& parts)
|
||||
void Invoice::setParts(const util::Map<std::string, InventoryItem*>& parts)
|
||||
{
|
||||
m_parts = parts;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ private:
|
||||
ServiceBooking* m_booking;
|
||||
util::Timestamp m_invoiceDate;
|
||||
double m_laborCost;
|
||||
util::Map<int, InventoryItem*> m_parts;
|
||||
util::Map<std::string, InventoryItem*> 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<int,
|
||||
InventoryItem*>& parts,
|
||||
double laborCost,
|
||||
const util::Map<std::string,InventoryItem*>& 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<int, InventoryItem*>& getParts() const;
|
||||
const util::Map<std::string, InventoryItem*>& 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<int, InventoryItem*>& parts);
|
||||
void setParts(const util::Map<std::string, InventoryItem*>& parts);
|
||||
void setPartsCost(double partsCost);
|
||||
void setDiscountPercentage(double discountPercentage);
|
||||
void setTotalAmount(double totalAmount);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#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);
|
||||
};
|
||||
+56
@@ -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<std::string, InventoryItem*>& 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<std::string, Service*> servicesInTheBookedService = booking->getServices();
|
||||
util::Map<std::string, InventoryItem*> completeInventoryItemMapOfBooking;
|
||||
util::Map<std::string, JobCard*> 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<Invoice>(bookingID, booking, util::Timestamp(), totalLabourCost, completeInventoryItemMapOfBooking, totalPartsCost, discountPercentage, totalServiceCost, util::Timestamp(), util::PaymentMode::NOTSET, util::PaymentStatus::PENDING);
|
||||
util::Map<std::string, Invoice*>& currentInvoices = m_dataStore.getInvoices();
|
||||
currentInvoices.insert(invoice->getId(), invoice);
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user