Update CollectionStatus property for all sub FRUs

On VPD collection failure, CollectionStatus Dbus property is updated
only for the base FRU, this results in the mismatch of collection
status with the remaining sub FRUs.

This commit updates the CollectionStatus as failed for all FRUs
present under the EEPROM, if there is any VPD collection failure for
any reason.

Output:
```
root@p10bmc:~# busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/dimm8 com.ibm.VPD.Collection CollectionStatus
s "com.ibm.VPD.Collection.Status.Failure"

root@p10bmc:~# busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/dimm8/unit0 com.ibm.VPD.Collection CollectionStatus

root@p10bmc:~# busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/dimm8/unit1 com.ibm.VPD.Collection CollectionStatus
s "com.ibm.VPD.Collection.Status.Failure"

root@p10bmc:~# busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/dimm8/unit2 com.ibm.VPD.Collection CollectionStatus
s "com.ibm.VPD.Collection.Status.Failure"

root@p10bmc:~# busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/dimm8/unit3 com.ibm.VPD.Collection CollectionStatus
s "com.ibm.VPD.Collection.Status.Failure"

```

Change-Id: I900590d9a5c89e02dc791722d5a2fc5c5983e158
Signed-off-by: Anupama B R <anupama.b.r1@ibm.com>
diff --git a/vpd-manager/include/worker.hpp b/vpd-manager/include/worker.hpp
index b560162..0080696 100644
--- a/vpd-manager/include/worker.hpp
+++ b/vpd-manager/include/worker.hpp
@@ -531,6 +531,18 @@
                i_fru.value("handlePresence", true);
     }
 
+    /**
+     * @brief API to set CollectionStatus property.
+     *
+     * This API updates the CollectionStatus property of the given FRU with the
+     * given value.
+     *
+     * @param[in] i_vpdPath - EEPROM or inventory path.
+     * @param[in] i_value - Value to be set.
+     */
+    void setCollectionStatusProperty(const std::string& i_fruPath,
+                                     const std::string& i_value) const noexcept;
+
     // Parsed JSON file.
     nlohmann::json m_parsedJson{};
 
diff --git a/vpd-manager/src/worker.cpp b/vpd-manager/src/worker.cpp
index 87112ce..48d0c3b 100644
--- a/vpd-manager/src/worker.cpp
+++ b/vpd-manager/src/worker.cpp
@@ -1404,14 +1404,8 @@
     }
     catch (const std::exception& ex)
     {
-        // Notify FRU's VPD CollectionStatus as Failure
-        if (!dbusUtility::notifyFRUCollectionStatus(
-                l_inventoryPath, constants::vpdCollectionFailure))
-        {
-            logging::logMessage(
-                "Call to PIM Notify method failed to update Collection status as Failure for " +
-                i_vpdFilePath);
-        }
+        setCollectionStatusProperty(i_vpdFilePath,
+                                    constants::vpdCollectionFailure);
 
         // handle all the exceptions internally. Return only true/false
         // based on status of execution.
@@ -1917,4 +1911,75 @@
         logging::logMessage(std::string(l_error.what()));
     }
 }
+
+void Worker::setCollectionStatusProperty(
+    const std::string& i_vpdPath, const std::string& i_value) const noexcept
+{
+    try
+    {
+        if (i_vpdPath.empty())
+        {
+            throw std::runtime_error(
+                "Given path is empty. Can't set CollectionStatus property");
+        }
+
+        types::ObjectMap l_objectInterfaceMap;
+
+        if (m_parsedJson["frus"].contains(i_vpdPath))
+        {
+            for (const auto& l_Fru : m_parsedJson["frus"][i_vpdPath])
+            {
+                sdbusplus::message::object_path l_fruObjectPath(
+                    l_Fru["inventoryPath"]);
+
+                types::PropertyMap l_propertyValueMap;
+                l_propertyValueMap.emplace("CollectionStatus", i_value);
+
+                types::InterfaceMap l_interfaces;
+                vpdSpecificUtility::insertOrMerge(
+                    l_interfaces, constants::vpdCollectionInterface,
+                    move(l_propertyValueMap));
+
+                l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
+                                             std::move(l_interfaces));
+            }
+        }
+        else
+        {
+            // consider it as an inventory path.
+            if (i_vpdPath.find(constants::pimPath) != constants::VALUE_0)
+            {
+                throw std::runtime_error(
+                    "Invalid inventory path: " + i_vpdPath +
+                    ". Can't set CollectionStatus property");
+            }
+
+            types::PropertyMap l_propertyValueMap;
+            l_propertyValueMap.emplace("CollectionStatus", i_value);
+
+            types::InterfaceMap l_interfaces;
+            vpdSpecificUtility::insertOrMerge(l_interfaces,
+                                              constants::vpdCollectionInterface,
+                                              move(l_propertyValueMap));
+
+            l_objectInterfaceMap.emplace(i_vpdPath, std::move(l_interfaces));
+        }
+
+        // Notify PIM
+        if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
+        {
+            throw DbusException(
+                std::string(__FUNCTION__) +
+                "Call to PIM failed while setting CollectionStatus property for path " +
+                i_vpdPath);
+        }
+    }
+    catch (const std::exception& l_ex)
+    {
+        EventLogger::createSyncPel(
+            EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
+            __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
+            std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+    }
+}
 } // namespace vpd