in agora/store_queue_monitoring_backend/src/Helpers/CheckoutGenerator.cs [120:212]
public List<CheckoutHistory> GenerateData(DateTime startTime, DateTime? endTime = null, List<Checkout> updatedCheckouts = null, bool redistributeOnly = false)
{
lock (generateDataLock)
{
if (endTime == null)
endTime = DateTime.UtcNow;
// Update checkouts if provided
if (updatedCheckouts != null)
{
foreach (var updatedCheckout in updatedCheckouts)
{
var existingCheckout = this.checkouts.FirstOrDefault(c => c.Id == updatedCheckout.Id);
if (existingCheckout != null)
{
existingCheckout.Type = updatedCheckout.Type;
existingCheckout.AvgProcessingTime = updatedCheckout.AvgProcessingTime;
if (existingCheckout.Closed != updatedCheckout.Closed)
{
if (updatedCheckout.Closed && existingCheckout.Customers.Count > 0)
{
//redistribute customers to other open checkouts
while (existingCheckout.Customers.Count > 0)
{
var checkout = GetCheckoutWithShortestQueue(existingCheckout.Id);
if (checkout == null || existingCheckout.Customers.Count == 0)
break;
var cust = existingCheckout.Customers.Dequeue();
checkout.Customers.Enqueue(cust);
}
}
else if (!updatedCheckout.Closed)
{
//redistribute customers to newly opened checkout
var totalOpenCheckouts = updatedCheckouts.Where(x => !x.Closed).Count();
var existingOpenCheckouts = this.checkouts.Where(c => !c.Closed).ToList();
int totalQueueLength = existingOpenCheckouts.Sum(c => c.Customers.Count);
int avgQueueLength = totalQueueLength / totalOpenCheckouts;
while (existingCheckout.Customers.Count < avgQueueLength)
{
var maxQueueCheckout = existingOpenCheckouts.OrderByDescending(c => c.Customers.Count).First();
if (maxQueueCheckout.Customers.Count <= avgQueueLength)
break;
existingCheckout.Customers.Enqueue(maxQueueCheckout.Customers.Dequeue());
}
}
}
existingCheckout.Closed = updatedCheckout.Closed;
}
}
}
var checkoutHistories = new List<CheckoutHistory>();
for (DateTime currentTime = startTime; currentTime <= endTime; currentTime = currentTime.AddSeconds(1))
{
// Generate customers at the start of each minute if not redistributing only
if (currentTime.TimeOfDay.Seconds == 0 && !redistributeOnly)
GenerateCustomers(currentTime.TimeOfDay);
foreach (var checkout in checkouts)
{
// Process customers in the queue if not redistributing only
if (checkout.Customers.Count > 0 && !redistributeOnly)
{
var customer = checkout.Customers.Peek();
if (customer != null)
{
customer.CheckoutTime -= 1;
if (customer.CheckoutTime <= 0)
checkout.Customers.Dequeue();
}
}
// Record checkout history at the start of each minute
if (currentTime.TimeOfDay.Seconds == 0)
{
var checkoutHistory = new CheckoutHistory
{
Timestamp = currentTime,
CheckoutId = checkout.Id,
CheckoutType = checkout.Type,
QueueLength = checkout.Customers.Count,
AverageWaitTimeSeconds = checkout.Customers.Count * checkout.AvgProcessingTime
};
checkoutHistories.Add(checkoutHistory);
}
}
}
return checkoutHistories;
}
}