Intelligente Ring Group oder Call Queue

Trex_man

Mitglied seit
10. Mai 2022
Beiträge
17
Hallo,

wir möchten bei einer extern erreichbaren Ring Group eine interlegente Logik in der folgenden Form haben:
Anrufer 1 ruft auf der Gruppe an und wir zu User A durchgestellt
Wenn der Anrufer 1 später wieder auf der Gruppe anruft, soll es automatisch bei User A klingeln und nur falls dieser nicht erreichbar ist, soll es nach der Signalisierungsmethode bei anderen Usern klingeln.

Lässt sich sowas durch Signalisierungsmethode oder andere Optionen in der 3CX lösen?
Oder muss man sich hier etwas mit dem CFD überlegen?

Falls es nur mit dem CFD ginge, wäre das nicht eine Idee für eine Erweiterung? (zum ersten Mal hörte ich das bei Telefongruppen jedenfalls nicht :) )

Danke
 
Hallo,

Wenn der Anrufer 1 später wieder auf der Gruppe anruft, soll es automatisch bei User A klingeln und nur falls dieser nicht erreichbar ist, soll es nach der Signalisierungsmethode bei anderen Usern klingeln.
Wenn ich es richtig verstehe: es geht primär darum, dass Anrufer wenn möglich zur der NSt. vermittelt werden mit der sie bereits zuvor schon (wann auch immer das gewesen sein soll) telefoniert haben, richtig?

Das lässt sich mit den integrierten 3CX Bordmitteln nicht lösen. Dazu braucht es eine CFA die vor der Signalisierungsgruppe / Warteschlange sitzt, den Anruf bekommt, daraufhin die CDR auswertet (ein Problem da auch das in einer CFA nicht vorgesehen ist , eine SQL / CRM Abfrage ist besser), die NSt. auf Verfügbarkeit abfragt und dann evtl. dahin vermittelt.
 
  • Like
Reaktionen: Trex_man
Danke für die Info!
Wenn ich es richtig verstehe: es geht primär darum, dass Anrufer wenn möglich zur der NSt. vermittelt werden mit der sie bereits zuvor schon (wann auch immer das gewesen sein soll) telefoniert haben, richtig?
Ja genau.

Aber ok. Ich dachte mir schon, dass man hier etwas mit dem CFD basteln darf.
 
Hallo Trexman99,
kannst dich gerne melden - hab sowas bereits schon.
 
@Patrick_Bitblade Das würde mich auch interessieren, wie Ihr das gelöst habt. Codebeispiel?
 
Zuletzt bearbeitet:
Hier ein (kleiner) Teil
Hier eingestellt sind, das es um die letzten 10 Minuten geht.
Sollte der Agent nicht verfügbar sein erfolgt Umleitung zu einer extra Warteschleife.

WebInteractionComponent AnrufVerlauf = new WebInteractionComponent("AnrufVerlauf", callflow, myCall, logHeader);
AnrufVerlauf.HttpMethod = System.Net.Http.HttpMethod.Get;
AnrufVerlauf.ContentType = "application/json";
AnrufVerlauf.Timeout = 30000;
AnrufVerlauf.UriHandler = () => { return Convert.ToString(CFDFunctions.CONCATENATE(Convert.ToString("/api/CallLog?TimeZoneName=Europe/Berlin&callState=All&dateRangeType=LastThirtyDays&fromFilter="),Convert.ToString(variableMap["session.ani"].Value),Convert.ToString("&fromFilterType=MatchNumber&numberOfRows=1&searchFilter=&startRow=0&toFilter=&toFilterType=Any"))); }; AnrufVerlauf.ContentHandler = () => { return Convert.ToString(""); }; AnrufVerlauf.Headers.Add(new CallFlow.CFD.Parameter("Cookie", () => { return getLastCallLogin.ReturnValue; })); mainFlowComponentList.Add(AnrufVerlauf); TextAnalyzerComponent JsonXmlParser1 = new TextAnalyzerComponent("JsonXmlParser1", callflow, myCall, logHeader); JsonXmlParser1.TextType = TextAnalyzerComponent.TextTypes.JSON; JsonXmlParser1.TextHandler = () => { return Convert.ToString(AnrufVerlauf.ResponseContent); }; JsonXmlParser1.Mappings.Add("CallLogRows[0].CallTime", "callflow$.lastCallTime"); JsonXmlParser1.Mappings.Add("CallLogRows[0].Duration", "callflow$.lastCallDuration"); JsonXmlParser1.Mappings.Add("CallLogRows[0].Destination", "callflow$.lastDestination"); mainFlowComponentList.Add(JsonXmlParser1); hatSchonAngerufen658269291ECCComponent hatSchonAngerufen = new hatSchonAngerufen658269291ECCComponent("hatSchonAngerufen", callflow, myCall, logHeader); hatSchonAngerufen.Parameters.Add(new CallFlow.CFD.Parameter("lastCallDuration", () => { return variableMap["callflow$.lastCallDuration"].Value; })); hatSchonAngerufen.Parameters.Add(new CallFlow.CFD.Parameter("lastCallTime", () => { return variableMap["callflow$.lastCallTime"].Value; })); hatSchonAngerufen.Parameters.Add(new CallFlow.CFD.Parameter("now", () => { return CFDFunctions.NOW(); })); mainFlowComponentList.Add(hatSchonAngerufen); ConditionalComponent ruftWiederAn = new ConditionalComponent("ruftWiederAn", callflow, myCall, logHeader); mainFlowComponentList.Add(ruftWiederAn); ruftWiederAn.ConditionList.Add(() => { return Convert.ToBoolean(hatSchonAngerufen.ReturnValue); }); ruftWiederAn.ContainerList.Add(new SequenceContainerComponent("kleiner10Min", callflow, myCall, logHeader)); getAgentNumber1773457814ECCComponent getAgentNumber = new getAgentNumber1773457814ECCComponent("getAgentNumber", callflow, myCall, logHeader); getAgentNumber.Parameters.Add(new CallFlow.CFD.Parameter("agent", () => { return variableMap["callflow$.lastDestination"].Value; })); ruftWiederAn.ContainerList[0].ComponentList.Add(getAgentNumber); ConditionalComponent warBeiAgent = new ConditionalComponent("warBeiAgent", callflow, myCall, logHeader); ruftWiederAn.ContainerList[0].ComponentList.Add(warBeiAgent); warBeiAgent.ConditionList.Add(() => { return Convert.ToBoolean(CFDFunctions.NOT_EQUAL(getAgentNumber.ReturnValue,"")); }); warBeiAgent.ContainerList.Add(new SequenceContainerComponent("wahr", callflow, myCall, logHeader)); TcxGetExtensionStatusComponent AgentStatus = new TcxGetExtensionStatusComponent("AgentStatus", callflow, myCall, logHeader); AgentStatus.ExtensionHandler = () => { return Convert.ToString(getAgentNumber.ReturnValue); }; warBeiAgent.ContainerList[0].ComponentList.Add(AgentStatus); LoggerComponent loggerComponent2 = new LoggerComponent("loggerComponent2", callflow, myCall, logHeader); loggerComponent2.Level = LoggerComponent.LogLevels.Error; loggerComponent2.TextHandler = () => { return Convert.ToString(AgentStatus.CurrentProfile); }; warBeiAgent.ContainerList[0].ComponentList.Add(loggerComponent2); ConditionalComponent agentVerfügbar = new ConditionalComponent("agentVerfügbar", callflow, myCall, logHeader); warBeiAgent.ContainerList[0].ComponentList.Add(agentVerfügbar); agentVerfügbar.ConditionList.Add(() => { return Convert.ToBoolean(CFDFunctions.EQUAL(AgentStatus.CurrentProfileName,"Available")); }); agentVerfügbar.ContainerList.Add(new SequenceContainerComponent("istVerfügbar", callflow, myCall, logHeader)); TransferComponent zumLetztenAgenten = new TransferComponent("zumLetztenAgenten", callflow, myCall, logHeader); zumLetztenAgenten.DestinationHandler = () => { return Convert.ToString(getAgentNumber.ReturnValue); }; zumLetztenAgenten.DelayMilliseconds = 500; agentVerfügbar.ContainerList[0].ComponentList.Add(zumLetztenAgenten); agentVerfügbar.ConditionList.Add(() => { return Convert.ToBoolean(true); }); agentVerfügbar.ContainerList.Add(new SequenceContainerComponent("nichtVerfügbar", callflow, myCall, logHeader)); TransferComponent Rückruf = new TransferComponent("Rückruf", callflow, myCall, logHeader); Rückruf.DestinationHandler = () => { return Convert.ToString(809); }; Rückruf.DelayMilliseconds = 500; warBeiAgent.ContainerList[0].ComponentList.Add(Rückruf); warBeiAgent.ConditionList.Add(() => { return Convert.ToBoolean(true); }); warBeiAgent.ContainerList.Add(new SequenceContainerComponent("falsch", callflow, myCall, logHeader)); ruftWiederAn.ConditionList.Add(() => { return Convert.ToBoolean(true); }); ruftWiederAn.ContainerList.Add(new SequenceContainerComponent("mehrAls10Min", callflow, myCall, logHeader));
 
Zuletzt bearbeitet:
Hier ein (kleiner) Teil

Danke, ein nettes Stück Code. Insbesonders die hier genutzte API Abfrage des CallLog kannte ich so noch nicht. Noch dazu alles mit CFD Bordmitteln.

Wenn man damit gezielt in der Suchmaschine seines Vertrauens sucht, findet man eine recht neue Website, auf der weitere so interessante api URL auftauchen. Auch sehr nett. Daraus ergeben sich ganz neue Möglichkeiten. Das ist im Prinzip das, was wir uns als API wünschen. Die bisher von 3cx dokumentierte API ist zwar nett aber einfach nicht genug.

Ich werde bei Gelegenheit mal schauen, wie sehr es eine 3CX belastet, diese CallLog API permanent mit unterschiedlichen Anfragen zu pollen. Die Anfrage nach einem Statusmonitor ist bei div. unserer Kunden immer noch offen.

Es könnte aber für Andere hier ein größeres Problem sein, dieses unstruktierte Codeschnipsel aus der 3CX (was vmtl. aus dem CFA Dialog rauskopiert wurde und eben nicht aus dem CFD) zu lesen, zu verstehen und anderweitig umzusetzen. Du wärst ein ganz Großer, wenn du dein CFD Projekt kopierst, die für dich kritischen Teile entfernst und als ZIP hier reinstellst.
 
Zuletzt bearbeitet:
Noch dazu alles mit CFD Bordmitteln.
Kleine Korrektur weil ich mir das gerade wirklich mal anschaue: die Komponente hatSchonAngerufen steht in deinem Beispiel nicht drin und wird vmtl. als Routine (C# Komponente) hatSchonAngerufen658269291ECCComponent ganz unten im Quelltext auftauchen. Vermutlich war es einfacher diese Abfrage in C# zu schreiben (insbes. das zerlegen und auswerten des Zeiten) an Stelle das mit CFD Bordmitteln zu realisieren.

Gretchenfrage: Woher hast du das mit der API des CallLog und diesen Parametern?
 
Freut mich zu hören dass ich hiermit schon etwas helfen konnte.
Ja wurde in C# geschrieben-
Ich werde mir die Arbeit die nächste Woche machen und im CFD stellen ( hoffentlich alle) die kritisch sind "schwärzen"

Woher ich das habe.. sehr gute Frage und ich kann es Dir nicht mehr beantworten- auch weil ich an diesem Ding nicht alleine gearbeitet habe.
Wir saßen daran etwa 70 Std. bis es funktioniert hat...
 
Zwecks Auslastung:
Wir haben bisher keine Probleme feststellen können. Ca 700 Gespräche gleichzeitig :P



Schön wäre es, wenn wir so viele hätten :D 700 sind es ca im Monat ( haben aber nur 4-7Std am Tag "offen")
 
Zum Thema API:
Wir haben einfach die REST API Reverse engineered die das Admin Interface nutzt für einen ganzen Haufen Anpassungen, Monitoring Scripts wie Lizenz Nutzung (Kanäle etc.) und auch eine bessere CRM Integration für Zammad (Gibts bei Github) mit ein bisschen Mühe geht da unglaublich viel.
Aktuell bauen wir gerade eine eigene Exchange Kalender Sync Integration (Exchange, nicht o365) weil die eingebaute fün Eimer ist und einen Kontakte Sync für Kerio
 
  • Like
Reaktionen: autohaus
Wir haben einfach die REST API Reverse engineered die das Admin Interface nutzt für
Das hat bei uns noch keiner gemacht. Daran besteht Interesse. Das was wir an REST API (ausserhalb der von 3CX öffentlich dokumentieren Video Conference API) haben, wurde in kleinen Häppchen zusammengetragen und gesammelt. Das steht teils hier oder im globalen Forum und ein weiterer Teil bis letztens noch auf einer Website.
 

Statistik des Forums

Themen
44.414
Beiträge
232.721
Mitglieder
78.331
Neuestes Mitglied
b2daniel