Skip to content

Commit

Permalink
Added call center planning page
Browse files Browse the repository at this point in the history
  • Loading branch information
A-Herzog committed May 12, 2024
1 parent 98774a0 commit 7e211d1
Show file tree
Hide file tree
Showing 10 changed files with 1,094 additions and 2 deletions.
242 changes: 242 additions & 0 deletions docs/images/CallCenter_de.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
202 changes: 202 additions & 0 deletions docs/images/CallCenter_de_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
211 changes: 211 additions & 0 deletions docs/images/CallCenter_en.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
171 changes: 171 additions & 0 deletions docs/images/CallCenter_en_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ mainNavBar.insertBefore(buildMultiNavDropdown("DesignMenu",language.GUI.tabDesig
{id: "Compare", name: language.GUI.tabCompare, modes: {values: true}},
{id: "ShortestQueue", name: language.GUI.tabShortestQueue},
{id: "EconomyOfScale", name: language.GUI.tabEconomyOfScale, modes: {table: true, diagram: true}},
{id: "CallCenter", name: language.GUI.tabCallCenter, modes: {diagram: true}},
]),mainNavBar.children[insertCount++]);

/* Content */
Expand Down
32 changes: 31 additions & 1 deletion docs/js/Language.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ lang.GUI.formulaShortestQueueBInfo2="";
lang.GUI.formulaShortestQueueInfoAB="Wahrscheinlichkeit an der kürzeren Warteschlange länger warten zu müssen";
lang.GUI.formulaEconomyOfScale="Economy of Scale";
lang.GUI.formulaEconomyOfScaleLong="Economy of Scale (Positiver Skaleneffekt)";
lang.GUI.formulaEconomyOfScaleInfo="Die Economy of Scale beschreibt in Bezug auf stochatische Systeme den Effekt, dass die Wartezeiten bei insgesamt identischer Auslastung bei größeren Systemen kürzer ausfallen, als bei kleineren Systemen. Bei Warteschlangenmodellen mit mehr Bedienern können sich Schwankungen im Ankunftsstrom und bei den Bedienzeiten besser gegenseitig ausgleichen als bei kleineren Systemen.";
lang.GUI.formulaEconomyOfScaleInfo="Die Economy of Scale beschreibt in Bezug auf stochastische Systeme den Effekt, dass die Wartezeiten bei insgesamt identischer Auslastung bei größeren Systemen kürzer ausfallen, als bei kleineren Systemen. Bei Warteschlangenmodellen mit mehr Bedienern können sich Schwankungen im Ankunftsstrom und bei den Bedienzeiten besser gegenseitig ausgleichen als bei kleineren Systemen.";
lang.GUI.formulaCallCenter="Callcenter-Planung";
lang.GUI.formulaCallCenterLong="Callcenter-Planung";
lang.GUI.formulaCallCenterInfo="In diesem Modell können die Auswirkungen des Hinzufügens oder Entfernens einzelner Bediener von der Bedienstation untersucht werden. Neben einem Diagramm, in dem die Kenngrößen in Abhängigkeit von der Anzahl an eingesetzten Agenten angezeigt werden, wird in Tabellenform ausgegeben, welche konkreten Auswirkungen einzelne Veränderungsschritte haben.";
lang.GUI.tabHome="Start";
lang.GUI.tabErlangB="Erlang-B-Formel";
lang.GUI.tabErlangBInfo="M/M/c/C";
Expand All @@ -108,6 +111,7 @@ lang.GUI.tabDesign="Systemdesign";
lang.GUI.tabCompare="Vergleich verschiedener Strategien";
lang.GUI.tabShortestQueue="Wahl der kürzesten Schlange";
lang.GUI.tabEconomyOfScale="Economy of Scale";
lang.GUI.tabCallCenter="Callcenter-Planung";
lang.GUI.tabSimulation='Simulation';
lang.GUI.tabSimulationInfo='Wenn die Möglichkeiten der (erweiterten) Erlang-C-Formel und der (erweiterten) Allen-Cunneen-Näherungsformel zur Modellierung eines Warteschlangensystems nicht mehr ausreichen, kann eines der hier angebotenen Opensource <b>Simulationswerkzeuge</b> eingesetzt werden.';
lang.GUI.tabHelp="Hilfe";
Expand Down Expand Up @@ -742,6 +746,17 @@ Im Kontext der Warteschlangentheorie ist jedoch besonders der Effekt, dass sich
In dem Rechenmodell kann die mittlere Auslastung (&rho;) der Bediener fest vorgegeben werden. Wird nun die Anzahl an Bedienern (c) verändert, so ändert sich automatisch auch die Zwischenankunftszeit (E[I]), so dass insgesamt die Auslastung (&rho;=E[S]/E[I]/c) konstant bleibt. Auf diese Weise können über die Variation der Anzahl an Bedienern verschieden große Systeme jeweils bei exakt derselben Auslastung verglichen werden.
</p>`;

lang.text.CallCenterDiagram=`
<p>
Sofern Anrufwiederholungen nicht abgebildet werden müssen, können Callcenter über die <a href="javascript:void(0);" onclick="showTab('ExtErlangCValues');">erweiterte Erlang-C-Formel</a> abgebildet werden.
Während Anrufsraten und Bediendauern meist nicht beeinflussbar sind, ist die Anzahl an eingesetzten Agenten die Stellgröße, über die Betriebskosten und Leistungskenngrößen des Systems optimiert werden können.
Je mehr Agenten eingesetzt werden, desto besser fallen die Kenngrößen aus, aber auch desto mehr Lohnkosten fallen an.
</p>
<p>
Auf diese Seite kann die Anzahl an Agenten für vorgegebene Rahmenparameter variiert werden. Die Auswirkungen der verschiedenen Anzahlen an Agenten werden nicht nur in grafischer Form dargestellt, sondern auch
als Tabelle inkl. Zusatzzeilen zur Angabe der jeweiligen Veränderungen von Schritt zu Schritt.
</p>`;

/* English */

const languageEN={};
Expand Down Expand Up @@ -809,6 +824,9 @@ lang.GUI.formulaShortestQueueInfoAB="Probability of having to wait longer in the
lang.GUI.formulaEconomyOfScale="Economy of Scale";
lang.GUI.formulaEconomyOfScaleLong="Economy of Scale";
lang.GUI.formulaEconomyOfScaleInfo="In terms of stochastic systems, the economy of scale describes the effect that waiting times are shorter in larger systems than in smaller systems, with an overall identical workload. In queueing models with more operators, fluctuations in the arrival stream and in the service times can balance each other out better than in smaller systems.";
lang.GUI.formulaCallCenter="Call center planning";
lang.GUI.formulaCallCenterLong="Call center planning";
lang.GUI.formulaCallCenterInfo="This model can be used to examine the effects of adding or removing individual operators from the process station. In addition to a diagram in which the results are displayed as a function of the number of agents used, the specific effects of individual change steps are shown in tabular form.";
lang.GUI.tabHome="Start";
lang.GUI.tabErlangB="Erlang-B formula";
lang.GUI.tabErlangBInfo="M/M/c/C";
Expand All @@ -829,6 +847,7 @@ lang.GUI.tabDesign="System design";
lang.GUI.tabCompare="Comparison of different strategies";
lang.GUI.tabShortestQueue="Choice of the shortest queue";
lang.GUI.tabEconomyOfScale="Economy of Scale";
lang.GUI.tabCallCenter="Call center planning";
lang.GUI.tabSimulation='Simulation';
lang.GUI.tabSimulationInfo='If the capabilities of the (extended) Erlang-C formula and the (extended) Allen-Cunneen approximation formula are not sufficient anymore to model a queueing system, one of the open source <b>simulation tools</b> offered here can be used.';
lang.GUI.tabHelp="Help";
Expand Down Expand Up @@ -1473,6 +1492,17 @@ In the context of queueing theory, the effect that in larger systems the fluctua
In the calculation model, the average utilization (&rho;) of the operators can be fixed. If the number of operators (c) is now changed, the inter-arrival time (E[I]) also changes automatically, so that the overall utilization (&rho;=E[S]/E[I]/c) remains constant. In this way, by varying the number of operators, systems of different sizes can each be compared at exactly the same workload.
</p>`;

lang.text.CallCenterDiagram=`
<p>
If retry is not needed to be mapped, call centers can be mapped using the <a href="javascript:void(0);" onclick="showTab('ExtErlangCValues');">extended Erlang C formula</a>.
While arrival rates and service times cannot usually be influenced, the number of agents deployed is the control variable that can be used to optimize the operating costs and performance parameters of the system.
The more agents deployed, the better the performance indicators, but also the higher the labor costs.
</p>
<p>
On this page, the number of agents can be varied for specified framework parameters. The effects of the different numbers of agents are not only displayed in graphical form,
but also as a table including additional lines to indicate the respective changes from step to step.
</p>`;

/* Activate language */

const language=(document.documentElement.lang=='de')?languageDE:languageEN;
224 changes: 224 additions & 0 deletions docs/js/gui_CallCenter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
/*
Copyright 2024 Alexander Herzog
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

export {tilesCallCenter};

import {TilesBuilder, Table} from './tools_gui.js';
import {calcExtErlangC} from './gui_ExtErlangC.js';
import {language} from './Language.js';


/**
* Input tiles for the economy of scale
*/
const tilesCallCenter=new TilesBuilder('CallCenter');

tilesCallCenter.add(
language.model.inputInterArrivalTimeMean,
"E[I]",
"EI",
100,
5,
150,
language.model.invalidPositiveFloat,
language.model.invalidPositiveFloat,
language.model.inputInterArrivalTimeMeanInfo1,
language.model.inputInterArrivalTimeMeanInfo2,
"PositiveFloat",
false,
false
);

tilesCallCenter.add(
language.model.inputServiceTimeMean,
"E[S]",
"ES",
500,
5,
1000,
language.model.invalidPositiveFloat,
language.model.invalidPositiveFloat,
language.model.inputServiceTimeMeanInfo1,
language.model.inputServiceTimeMeanInfo2,
"PositiveFloat",
false,
false
);

tilesCallCenter.add(
language.model.inputWaitingTimeToleranceMean,
"E[WT]",
"EWT",
900,
30,
60,
language.model.invalidPositiveFloat,
language.model.invalidPositiveFloat,
language.model.inputWaitingTimeToleranceMeanInfo1,
language.model.inputWaitingTimeToleranceMeanInfo2,
"PositiveFloat",
false,
false
);

tilesCallCenter.add(
language.model.inputServiceLevel,
"t",
"t",
20,
1,
0,
language.model.invalidNotNegativeFloat,
language.model.invalidPositiveFloat,
language.model.inputServiceLevelInfo1,
language.model.inputServiceLevelInfo2,
"NotNegativeFloat",
true,
false
);

tilesCallCenter.add(
language.model.inputNumberOfOperators,
"c",
"c",
5,
1,
10,
language.model.invalidPositiveInt,
language.model.invalidPositiveInt,
language.model.inputNumberOfOperatorsInfo1,
language.model.inputNumberOfOperatorsInfo2,
"PositiveInt",
false,
true
);

/**
* Calculates the call center results for an individual set of input parameters.
* @param {Object} input Input values
* @returns {Object} Results
*/
function calcCallCenter(input) {
const temp=[...input];
temp.splice(2,0,1000);
const c=temp[5];
temp[5]=temp[4];
temp[4]=c;
return calcExtErlangC(temp);
}

/**
* Generates a results table based on the input values in table or diagram mode.
* @param {String} mode Which input elements are to be used ("Table" or "Diagram")?
* @returns {Object} Table object with the calculated values.
*/
function calcCallCenterTable(mode) {
const input=tilesCallCenter.rangeValues(mode);
if (input==null) return null;

let table=new Table();

table.addHeading('E[I]',language.model.inputInterArrivalTimeMean);
table.addHeading('E[S]',language.model.inputServiceTimeMean);
table.addHeading('K',language.statistics.SystemSize);
table.addHeading('E[WT]',language.model.inputWaitingTimeToleranceMean);
table.addHeading('c',language.model.inputNumberOfOperators);
table.addHeading('t',language.model.inputServiceLevelSeconds);
table.addHeading('a ('+language.statistics.characteristicsModeInput+')',language.statistics.Workload+' ('+language.statistics.characteristicsModeInput+')');
table.addHeading('&rho; ('+language.statistics.characteristicsModeInput+')',language.statistics.Utilization+' ('+language.statistics.characteristicsModeInput+')');
table.addHeading('P(A)',language.statistics.waitingCancelationProbability);
table.addHeading('E[I] ('+language.statistics.characteristicsModeNet+')',language.model.inputInterArrivalTimeMean+' ('+language.statistics.characteristicsModeNet+')');
table.addHeading('&rho; ('+language.statistics.characteristicsModeNet+')',language.statistics.Utilization+' ('+language.statistics.characteristicsModeNet+')');
table.addHeading('E[W]',language.statistics.averageWaitingTime);
table.addHeading('E[V]',language.statistics.averageResidenceTime);
table.addHeading('E[N<sub>Q</sub>]',language.statistics.averageNQ);
table.addHeading('E[N<sub>S</sub>]',language.statistics.averageNS);
table.addHeading('E[N]',language.statistics.averageN);
table.addHeading('P(N=0)',language.statistics.emptySystemProbability);
table.addHeading('P(W&gt;0)',language.statistics.waitingProbability);
table.addHeading('P(W&le;t)',language.model.inputServiceLevel);

table.calc(input,function(table,input) {
const data=calcCallCenter(input);
table.addCol(data.EI);
table.addCol(data.ES);
table.addCol(data.K);
table.addCol(data.EWT);
table.addCol(data.c);
table.addCol(data.t);
table.addCol(data.a);
table.addColPercent(data.rho);
table.addColPercent(data.PA);
table.addCol(data.EINet);
table.addColPercent(data.rhoNet);
table.addCol(data.EW);
table.addCol(data.EV);
table.addCol(data.ENQ);
table.addCol(data.ENS);
table.addCol(data.EN);
table.addColPercent(data.PNeq0);
table.addColPercent(data.PWgt0);
table.addColPercent(data.PWlet);
});

return table;
}

/* Diagram */

/**
* Callback to notify the tiles system that a fix/range tab has changed (in diagram mode).
* @param {Object} sender Tab which was changed
*/
function changeTabCallCenterDiagram(sender) {
tilesCallCenter.updateTabs(sender,'Diagram');
updateCallCenterDiagram();
}

/**
* Callback for updating the diagram results.
*/
function updateCallCenterDiagram() {
const table=calcCallCenterTable('Diagram');
if (table==null) return;

let xAxisTitle='';
switch (table.xValuesCol) {
case 0: xAxisTitle='E[I] ('+language.statistics.unitTime+')'; break;
case 1: xAxisTitle='E[S] ('+language.statistics.unitTime+')'; break;
case 2: xAxisTitle='E[WT] ('+language.statistics.unitTime+')'; break;
case 3: xAxisTitle='c ('+language.statistics.unitNumber+')'; break;
case 4: xAxisTitle='t ('+language.statistics.unitTime+')'; break;
}

const ySetup=[
{columnIndex: 8, color: 'red', mode: 'percent'}, /* P(A) */
{columnIndex: 11, color: 'yellow', mode: 'time'}, /* E[W] */
{columnIndex: 12, color: 'green', mode: 'time'}, /* E[V] */
{columnIndex: 13, color: 'orange', mode: 'number'}, /* E[NQ] */
{columnIndex: 15, color: 'blue', mode: 'number'}, /* E[N] */
{columnIndex: 7, color: 'lightgray', mode: 'percent'}, /* rho */
{columnIndex: 10, color: 'gray', mode: 'percent'}, /* rhoNet */
{columnIndex: 18, color: 'black', mode: 'percent'} /* P(W<=t) */
];

table.diagram('CallCenterDiagram_results',table.xValuesCol,xAxisTitle,ySetup,{x: 4, y: Array.from({length: 12},(_,i)=>i+7)});
}

/* General setup */

window.updateCallCenterDiagram=updateCallCenterDiagram;
window.changeTabCallCenterDiagram=changeTabCallCenterDiagram;
13 changes: 12 additions & 1 deletion docs/js/gui_Start.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {tilesExtAC} from './gui_ExtAC.js';
import {tilesCompare} from './gui_Compare.js';
import {tilesShortestQueue} from './gui_ShortestQueue.js';
import {tilesEconomyOfScale} from './gui_EconomyOfScale.js';
import {tilesCallCenter} from './gui_CallCenter.js';
import {formulasErlangB, formulasErlangC, formulasExtErlangC, formulasPC, formulasKingman, formulasAC, formulasExtAC, formulasCompare, formulasShortestQueue} from './FormulaBuilder.js';
import {language} from './Language.js';

Expand Down Expand Up @@ -101,6 +102,7 @@ function buildStartTiles(isDesktopApp) {
block+=buildStartTile(6,language.GUI.formulaCompare,language.GUI.formulaCompareInfo,"Compare","100%",false,"svg","602.67 / 279.23",{values: true});
block+=buildStartTile(6,language.GUI.formulaShortestQueue,language.GUI.formulaShortestQueueInfo,"ShortestQueue","100%",false,"svg","602.67 / 319.07");
block+=buildStartTile(6,language.GUI.formulaEconomyOfScale,language.GUI.formulaEconomyOfScaleInfo,"EconomyOfScale","100%",false,"svg","151.34 / 93.66",{table: true, diagram: true});
block+=buildStartTile(6,language.GUI.formulaCallCenter,language.GUI.formulaCallCenterInfo,"CallCenter","100%",false,"svg","151.34 / 61.89",{diagram: true});
block+=buildStartTile(6,language.GUI.tabSimulation,language.GUI.tabSimulationInfo,"Simulation","100%",true,'webp','640 / 481',false,"<i class='bi-caret-right-square'></i> ");

block+="<div class=\"col-lg-6\"><div class=\"card\">";
Expand Down Expand Up @@ -327,7 +329,6 @@ function getMainGUI(isDesktopApp) {
result+=getPlaceholder({
id: "EconomyOfScale",
title: language.GUI.formulaEconomyOfScaleLong,
valuesTilesButtons: tilesEconomyOfScale.valueTilesButtons,
tableInfo: language.text.EconomyOfScaleTable,
tableTilesButtons: tilesEconomyOfScale.valueTilesButtons,
tableTiles: tilesEconomyOfScale.tableTiles,
Expand All @@ -336,6 +337,16 @@ function getMainGUI(isDesktopApp) {
diagramTiles: tilesEconomyOfScale.diagramTiles
});

/* System design: Call center */

result+=getPlaceholder({
id: "CallCenter",
title: language.GUI.formulaCallCenterLong,
diagramInfo: language.text.CallCenterDiagram,
diagramTilesButtons: tilesCallCenter.valueTilesButtons,
diagramTiles: tilesCallCenter.diagramTiles
});

/* Simulation */

result+=getSimplePlaceholder("Simulation");
Expand Down
Binary file modified image-sources/Model_de.odg
Binary file not shown.
Binary file modified image-sources/Model_en.odg
Binary file not shown.

0 comments on commit 7e211d1

Please sign in to comment.