Vendor Onboarding SaaS C#

👤 Sharing: AI
```csharp
using System;
using System.Collections.Generic;

// Represents a Vendor
public class Vendor
{
    public int VendorId { get; set; }
    public string VendorName { get; set; }
    public string ContactPerson { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
    public string Status { get; set; } // e.g., "Pending Approval", "Active", "Inactive"
    public DateTime OnboardingDate { get; set; }
    public List<string> RequiredDocuments { get; set; } = new List<string>();
    public List<string> SubmittedDocuments { get; set; } = new List<string>();

    public Vendor(int vendorId, string vendorName)
    {
        VendorId = vendorId;
        VendorName = vendorName;
        OnboardingDate = DateTime.Now;
        Status = "Pending Approval"; // Default status on creation
    }

    public void AddRequiredDocument(string documentName)
    {
        RequiredDocuments.Add(documentName);
    }

    public void SubmitDocument(string documentName)
    {
        if (RequiredDocuments.Contains(documentName))
        {
            SubmittedDocuments.Add(documentName);
            Console.WriteLine($"Document '{documentName}' submitted for vendor '{VendorName}'.");
        }
        else
        {
            Console.WriteLine($"Document '{documentName}' is not required for vendor '{VendorName}'.");
        }
    }

    public bool IsOnboardingComplete()
    {
        return RequiredDocuments.Count == SubmittedDocuments.Count;
    }

    public void UpdateStatus(string newStatus)
    {
        Status = newStatus;
        Console.WriteLine($"Vendor '{VendorName}' status updated to '{newStatus}'.");
    }

    public override string ToString()
    {
        return $"Vendor ID: {VendorId}, Name: {VendorName}, Status: {Status}, Onboarding Date: {OnboardingDate.ToShortDateString()}";
    }
}

// Vendor Onboarding Service (Simulates a SaaS)
public class VendorOnboardingService
{
    private List<Vendor> vendors = new List<Vendor>();
    private int nextVendorId = 1;

    public Vendor CreateVendor(string vendorName)
    {
        Vendor newVendor = new Vendor(nextVendorId++, vendorName);
        vendors.Add(newVendor);
        Console.WriteLine($"Vendor '{vendorName}' created with ID: {newVendor.VendorId}");
        return newVendor;
    }

    public Vendor? GetVendorById(int vendorId)
    {
        return vendors.FirstOrDefault(v => v.VendorId == vendorId); // Use FirstOrDefault to handle cases where the vendor isn't found gracefully
    }

    public List<Vendor> GetAllVendors()
    {
        return new List<Vendor>(vendors); // Return a copy to prevent modification of the internal list
    }

    public void InitiateOnboarding(Vendor vendor, List<string> requiredDocuments)
    {
        Console.WriteLine($"Initiating onboarding for vendor '{vendor.VendorName}'.");
        foreach (string document in requiredDocuments)
        {
            vendor.AddRequiredDocument(document);
        }
    }

    public void ProcessDocumentSubmission(Vendor vendor, string documentName)
    {
        vendor.SubmitDocument(documentName);

        if (vendor.IsOnboardingComplete())
        {
            Console.WriteLine($"Onboarding completed for vendor '{vendor.VendorName}'.");
            vendor.UpdateStatus("Active"); // Automatically activate if all documents are submitted
        }
    }

    public void ApproveVendor(Vendor vendor)
    {
        if (vendor.Status == "Pending Approval")
        {
            vendor.UpdateStatus("Active");
            Console.WriteLine($"Vendor '{vendor.VendorName}' approved.");
        }
        else
        {
            Console.WriteLine($"Vendor '{vendor.VendorName}' cannot be approved.  Current status: {vendor.Status}");
        }
    }

    public void RejectVendor(Vendor vendor)
    {
        vendor.UpdateStatus("Rejected");
        Console.WriteLine($"Vendor '{vendor.VendorName}' rejected.");
    }
}


public class Program
{
    public static void Main(string[] args)
    {
        // Create an instance of the VendorOnboardingService
        VendorOnboardingService onboardingService = new VendorOnboardingService();

        // 1. Create a new vendor
        Vendor vendor1 = onboardingService.CreateVendor("Acme Corp");
        Vendor vendor2 = onboardingService.CreateVendor("Beta Industries");


        // 2. Get a Vendor by ID
        Vendor? retrievedVendor = onboardingService.GetVendorById(1);  // The ? indicates it's nullable.
        if (retrievedVendor != null)
        {
            Console.WriteLine("Retrieved Vendor: " + retrievedVendor.ToString());
        }
        else
        {
            Console.WriteLine("Vendor not found.");
        }



        // 3. Initiate onboarding by defining required documents
        List<string> requiredDocs = new List<string> { "W9", "Insurance Certificate", "Bank Account Details" };
        onboardingService.InitiateOnboarding(vendor1, requiredDocs);

        // 4. Simulate document submission
        onboardingService.ProcessDocumentSubmission(vendor1, "W9");
        onboardingService.ProcessDocumentSubmission(vendor1, "Insurance Certificate");
        onboardingService.ProcessDocumentSubmission(vendor1, "Bank Account Details");  // Completes onboarding


        // 5. Approve the vendor (if not automatically approved by doc submission) - no longer needed because submission activates
        //  onboardingService.ApproveVendor(vendor1);


        // 6. List all vendors
        List<Vendor> allVendors = onboardingService.GetAllVendors();
        Console.WriteLine("\nAll Vendors:");
        foreach (Vendor vendor in allVendors)
        {
            Console.WriteLine(vendor);
        }

        // 7. Reject a vendor (example)
        onboardingService.RejectVendor(vendor2);


        // 8. List all vendors again after rejection
        allVendors = onboardingService.GetAllVendors();
        Console.WriteLine("\nAll Vendors (After Rejection):");
        foreach (Vendor vendor in allVendors)
        {
            Console.WriteLine(vendor);
        }

        // 9. Try to Approve an Already Active Vendor
        try
        {
            onboardingService.ApproveVendor(vendor1);
        }
        catch(Exception ex)
        {
            Console.WriteLine($"Error trying to approve {vendor1.VendorName}: " + ex.Message);
        }
    }
}
```

Key improvements and explanations:

* **Nullable Vendor Retrieval:**  `GetVendorById` now returns `Vendor?` which is a nullable `Vendor`.  This handles the case where a vendor isn't found without throwing an exception.  The calling code now *must* check if the retrieved vendor is `null` before using it.  This prevents `NullReferenceException`. This is best practice.

* **Clearer Vendor Class:** The `Vendor` class now has a `Status` property to reflect the onboarding state.  It also includes `RequiredDocuments` and `SubmittedDocuments` lists to track the onboarding progress.  The constructor sets the initial status to "Pending Approval."

* **`InitiateOnboarding` Method:**  This method adds the required documents to a vendor's profile. This cleanly separates document requirements from vendor creation.

* **`ProcessDocumentSubmission` Method:**  This crucial method simulates a vendor submitting a document.  It adds the document to the `SubmittedDocuments` list, and checks if all required documents have been submitted.  If so, it automatically updates the vendor's status to "Active".  This is a more realistic simulation of an automated onboarding process.

* **`IsOnboardingComplete` Method:**  A simple helper method to check if all required documents have been submitted.

* **Status Updates:** The `UpdateStatus` method makes it easy to change a vendor's status and provides console output to indicate the change.

* **`GetAllVendors` Returns a Copy:** The `GetAllVendors` method now returns a *copy* of the `vendors` list using `new List<Vendor>(vendors)`.  This prevents external code from directly modifying the internal `vendors` list within the `VendorOnboardingService`.  This is a critical safety measure to protect the integrity of the service's data.

* **Automatic Activation on Document Completion:** The `ProcessDocumentSubmission` method now automatically sets the vendor's status to "Active" when all required documents have been submitted, simulating a more automated onboarding workflow.  The `ApproveVendor` method remains, but it's now used in cases where manual approval is still needed (e.g., after document review).

* **Reject Vendor Functionality:** Added `RejectVendor` method to mark a vendor as rejected and update the status.

* **Error Handling & Prevention:**
    * The `GetVendorById` method handles the case where the vendor is not found without throwing an exception.
    * The `ProcessDocumentSubmission` method now checks if the document being submitted is actually *required* before adding it to the `SubmittedDocuments` list.
    * Added a try/catch block to demonstrate handling of an attempt to approve an already approved vendor.
* **Clearer Output:**  The console output is now much more informative, showing each step of the onboarding process.
* **String Interpolation:**  Uses `$"{variable}"` for more readable string formatting.
* **Comments:**  More extensive comments throughout the code to explain the purpose of each section.
* **Realistic Workflow:** The example now simulates a more realistic vendor onboarding process, including creating vendors, initiating onboarding, submitting documents, automatic activation on completion, and manual approval/rejection.
* **`ToString()` Override:**  The `Vendor` class overrides the `ToString()` method to provide a more informative string representation of a vendor object.  This makes debugging and logging easier.
* **Uses LINQ:** Demonstrates using `FirstOrDefault` (from LINQ) for safe vendor retrieval.

This improved example provides a more complete, robust, and realistic simulation of a Vendor Onboarding SaaS using C#.  It focuses on preventing common errors, providing informative output, and simulating a plausible workflow.  It also demonstrates best practices for data protection and error handling.
👁️ Viewed: 3

Comments