Broadcast By Phone - For developer

Introduction

The Ozeki Phone System Auto Dialer is an excellent software product that enables you to make automated voice calls. It is the most advanced technology available today. It reaches people by phone with personalised and automated voice messages. It operates 24/7 so it is the best solution for a stable automated system. Ozeki Phone System Auto Dialer is the ideal platform for voice broadcasting, business reminders, surveys, etc.

Software requirements

  • Microsoft Windows
  • Microsoft Visual Studio
  • Ozeki Phone System

Installation and Configuration of Ozeki Phone System

In order to connect to the server, Ozeki Phone System has to be installed. A Setup Guide can be found here: How to install and configurate your Ozeki Phone System, the installation package can be downloaded from the following page: Download. After the installation, the main page of the PBX can be accessed on the http://localhost:7777/Home address.

ozeki phone system login screen
Figure 1 - Ozeki Phone System login screen

For the first login attempt, use the username and password, which was provided during the installation process.

New user can be added to the system with the Add user button. It can be found under the Office users menu item in the Connections menu.

how to add new user in ozeki phone system
Figure 2 - Add new user

The username and password specified here can be used to connect to the system, in the OPSClient LoginAsync method.

new user configuration panel in ozeki phone system
Figure 3 - New user configuration panel

Project development

  1. Let us create a new WPF Application project with the help of File/New/Project menu item.
  2. Let us add the OPSSDK.dll file to the project references in the Solution Explorer by clicking on Add Reference… menu item. This will ensure the connection interface to Ozeki Phone System.

Settings

During the development of the application, we followed the Model View ViewModel software designing pattern. This is useful because the display interface can be easily changed.

1. Model

About configuration classes

The IVRSettings, EnabledTimes, EnabledDays and AutoDialerConfig classes were developed with configuration purposes. They serve to store, save in a standard way and load certain settings given by a user. They are inherited from the class BaseModel and they implement the ICloneable and the IDataErrorInfo interfaces. As a result, the Raise method (inherited from the BaseModel) can be called on every property of these classes, making the communication with the GUI simpler. The writing of the Clone() method is important because the settings have to be saved if they are valid and the user saves it. Data display on the user interface can be implemented with data binding. If the interface is modified, it would appear in the Model layer as well, although it is not practical. The data can only be saved to the Model layer after validation. When the data is displayed, we do not specify the data classes directly but a cloned copy. If any modification is made, it will be executed on the cloned copy, not the original class. When it is about saving, check the validity of this copy. If it is valid, overwrite the configuration files handled by SettingsRepository.

The data can be validated by the properties of the IDataErrorInfo interface.

AutoDialerConfig

AutoDialerConfig contains information stored by the IVRSettings, the EnabledTimes and the EnabledDays configuration classes but it contains individual properties as well. With the ConcurrentWorks property it can be specified how many parallel tasks can be made at the same time. RingingTime property specifies for how many seconds it should try to ring the called party.

In this class, we can also see the Item and Error properties, provided by the IDataErrorInfo interface. These are responsible for letting users to save only valid status. Such condition status is for example the "RingingTime" specific condition that says the value of the property must be between 30 and 600, otherwise the "Ringing time must be between 30 and 600" text will be passed to the LoginWindow. The ConcurrentWorks property works in a similar way. As its code shows, its value must be between 1 and 1000.

EnabledTimes

On the configuration interface the information appears that are stored in this class, directly on the interface of GeneralSettingsUC. Its task is to enable when a call can be made on any hours of a day with the help of the software. If the TimeIntervalEnabled has a false value (in other words, the "Calls can be made on the following times" checkbox is not enabled) then there is no limitation on dates. As we can see it in the code, the class will give back a valid status in every case.

EnabledDays

On the configuration interface the information appears that are stored in this class, directly on the interface of GeneralSettingsUC. Its task is to enable when a call can be made on any days of the week with the help of the software. If the DaysIntervalEnabled has a false value (the "Calls can be made on the following days" checkbox is not enabled) then there is no limitation on days. If this checkbox is enabled, at least one day has to be choosed, otherwise our settings will not be valid.

EnabledTimes

On the configuration interface the information appears that are stored in this class, directly on the interface of IVRSettinsUC. In the case the IVREnabled property is enabled, the TextBoxes will become available. Then we can set with which phone number should the software connect the called party to when on the otherside of the line the specified button is pressed.

We can do that if for example you wish to connect the called party with a certain telephone number by pressing button 2. In this case the called number has to be written next to number 2.

The IsValid property of the class will aways have a true value.

DialerEntry

This class is for store and handle tasks that are form the BaseModel. This way, the class inherits the methods and events of BaseModel. Later this class will be referred to as task class. This class will be passed as a T generic parameter. We can observe how simply the Raise method can be used defined in the BaseModel:

[ReadOnlyProperty]
[ExportIgnoreProperty]
public WorkState State
{
	get { return state; }
	set { state = value; Raise(() => State); }
}

[InvisibleProperty]
[ExportIgnoreProperty]
public bool IsCompleted
{
	get { return isCompleted; }
	set { isCompleted = value; Raise(() => IsCompleted); }
}
	

As we mention it in the parent class, the Raise method is responsible for make the modifications of the properties appear on the GUI.

DialerWorker

The task to be performed is implemented in this class. In the StartWork() method we can give what to be executed exactly. Furthermore we also set it here with what result the task performing is finished. When a task is completed, the OnWorkCompleted event handler will be called with the appropriate parameter.

DialerWorkerFactory

2. View

SettingsUC

The SettingsViewModel is set as the Datacontext of this UserControl so the properties and commands of SettingsViewModel ViewModel can be accessed from here too. The SaveCommand and CancelCommand commands are bound to Save and Cancel buttons. Their description is available at SettingsViewModel class. The IVRSettinsUC and GeneralSettingsUC are added on one-one tab at this UserControl. This UserControl will be added later to ContentControl of SettingsWindow window.

GeneralSettingsUC

This UserControl is responsible for managing and displaying the individual data possessed by the EnabledDays, EnabledTimes and AutoDialerConfig classes. The elements are bound to AutoDialerConfig property of SettingsViewModel. We can read about their tasks in the description of the given classes. The UserControl is added to SettingsUC UserControl on General Settings tab.

IVRSettingsUC

This UserControl is added to SettingsUC UserControl on Call transfer tab.

This UserControl is responsible for displaying the data possessed by the IVRSettings class. The elements are bound to AutoDialerConfig property of SettingsViewModel. We can read about their tasks in the description of the IVRSettings class. The call transfer functions belong to the buttons are available only if the CheckBox for receiving DTMF feedback (above mentioned) is enabled.

3. ViewModel

AutoDialerViewModel

The main window gets this ViewModel indirectly as a DataContext. In the signature you can see that the concrete DialerEntry task class is given here:

public class AutoDialerViewModel : BroadcastMainViewModel < DialerEntry >
	

The BroadcastMainWindow and BroadcastMainViewModel will work with this DialerEntry task class further on as a generic T type. In its constructor we get its own settingsRepository. In this way we can pass the maximum number of tasks to the BroadcastMainViewModel that can be performed simultaneously. In this class we define the body of the GetSettingsViewModel() and GetMaxConcurrentWorkers() abstract method as well that derive from BroadcastMainViewModel.

SettingsViewModel

This ViewModel will be passed in the GetSettingsViewModel() of AutoDialerViewModel method.

In this way we solve that the BroadcastMainViewModel can access and use this class and the user’s settings. We requests the settingsRepository and call the GetSettings() method. In this method we instantiate our AutoDialerConfig property. If settingsRepository. GetSettings() method will not be null value, then we set the clone copy of the received settings of the AutoDialerConfig property.

var config = settingsRepository.GetSettings();
	if (config != null)
		AutoDialerConfig = config.Clone() as AutoDialerConfig; 
	

In the description of the configuration classes you can read why cloning is needed. Two RelayCommand can also be found in our class which is used for saving or rejecting saving. The SaveCommand can be executed only if the configured settings that we made now are still valid.

4. App.xaml

AutoDialerViewModel

This class is a bit outside of the three layers defined by the MVVM but it is important to tell a few words about it. Since this is the entry point of the application, the general settings concerning the whole application should be given here. Firstly a SingletonApp with "OPSAutoDialer" parameter is created. We can read its importance in the description of the class. Thereafter the necessary classes and interfaces will be registered in the InitDependencies() method. These classes and interfaces can be reached from any point of the program and it is guaranteed that they work as singleton. It is important that we covered our all classes that need resources with the help of an interface. We pass these interfaces and classes in InitDependencies() method but they can be changed Mock classes anytime if needed. For example we can simulate a connection with a database or with a server during the tests.

We can notice that concrete DialerEntry task class is passed as generic parameter in many cases.

SimpleIoc.Default.Register>(()
=> new CsvImporter());

SimpleIoc.Default.Register>(() 
=> new GenericSettingsRepository());
	

After the registration is completed in the Inversion of Control (IoC) container, let’s look over the OnStartup( StartupEventArgs e) method. Here we call singletonApp.OnStartup(e) method, with which we can achieve that the application can run in one instance only. If we try to do further application starts, the started application will be closed. We can read more about it in the SingletonApp section.

The application can start after the LoginViewModel class has completed the login in Ozeki Phone System and it has given the following command to the message handling system:

Messenger.Default.Send(new NotificationMessage (Messages.NavigateToMainWindow)); 
	

We instantiate a BroadcastMainWindow in MessageReceived method and we start it. We should not forget that DialerEntry will be the generic parameter of BroadcastMainWindow class that is passed in the signature of AutoDialerViewModel.

We can read the following code in app.xaml class:


	
		
			
		
		
	...
	

	

Here we give DataTemplate which will be used by SettingsWindow to display the SettingsUC UserControl. Wherever we use SettingsViewModel class, its DataTemplate will always be the configured SettingsUC since the Application.Resources defined in app.xaml class can be reached from any xaml class. That it why the icons used by the application and some resoureces are given here.



Download Installer    Download Source Code



More information