BILLmanager 6
en En
es Es

Creating plugin for BILLmanager

The article contains instructions and recommendations for writing plugins for BILLmanager. A plugin is a software component that adds specific functionality or modifies the behavior of the main system.

BILLmanager modifications

BILLmanager allows you to add the following modifications:

  • modules are large and self-contained components of the system that perform a specific function or a set of functions. For example, they extend functionality through integration with a third-party system. Modules:
    • usually have their own dependencies and can include several plugins;
    • are not intended for dynamic real-time system behavior modification;
    • may require changes to the core system architecture;
    • by functionality, they are divided into:

      • service handlers;
      • payment methods;
      • message gateways;
      • online cash registers;
      • document management modules;
      • modules for coordination with third-party systems — LDAP, Omni, amoCRM, etc.

For information about existing system modules, see the Integration article.

  • plugins are usually simpler software components that add specific functionality or modify the behavior of the main system. Plugins allow you to:

    • integrate new functions without changing the source code;
    • intercept internal events;
    • add new interface elements;
    • execute background tasks via triggers on specific events;
    • adapt the system to specific needs.

Types of plugins

Plugins are divided by functionality into:

  • plugins that modify platform behavior;
  • plugins that extend platform functionality;
  • plugins that perform background tasks.

Behavior-modifying plugins allow you to catch internal events and modify them. For example, to add additional fields to a client card and fill them with the required values. Or to add new logic for existing actions. For more details, see the COREmanager documentation article Changing system behavior through event handlers.

Plugins that extend functionality add:

  • new elements — custom tables and forms necessary for solving specific tasks;
  • new actions and scenarios for working with the platform.

Plugins that perform background tasks:

  • add triggers for specific events in the platform;
  • allow running "heavy" tasks in the background that should not affect the work with the platform in the interface. For example, executing background tasks based on events.

For more details, see the COREmanager documentation article Background plugins.

To write your own plugin for BILLmanager:

  • select a programming language;
  • prepare the environment;
  • decide on the plugin structure.

Choosing programming language

For developing plugins for BILLmanager, you can use any programming language, both scripting and compiled. We recommend:

  • Python 3 is preferred choice. ISPsystem provides an SDK (Software Development Kit) that simplifies working with:
    • XML data;
    • sessions and request parameters;
    • database;
    • error handling;
  • C++ should be chosen for tasks requiring: 

    • integration with the billing core;
    • working within a single database transaction;
    • using the billing API;
    • high performance.

 When writing a plugin in C++, you can use the platform's public headers, which expands the functionality possibilities.

Preparing environment

To prepare the environment for creating a plugin:

  1. Check that the server meets the BILLmanager installation requirements. For more details, see the article Server requirements.
  2. Install the BILLmanager platform. For more details, see the article Installation process.
  3. Install the dev packages depending on the OS used:
    Server with AlmaLinux 9
    sudo dnf install coremanager-devel billmanager-corporate-devel clang
    Server with Ubuntu or Astra Linux
    sudo apt install coremanager-dev billmanager-corporate-devapt clang

For comfortable work with the code, we recommend setting up an IDE. For example, for setting up Visual Studio Code (VS Code):

  1. Install the Remote - SSH plugin for remote development.
  2. For Python: install the Python and Pylance extensions. For more information on extension settings, see the VS Code documentation.
  3. For C++: install the extensions:
  4. Set up a connection to the server with BILLmanager.

Plugin structure. Source code

All plugins are developed and stored in the /usr/local/mgr5/src/ directory. A build system is based on isp.mk, which provides:

  • automatic file installation via make install;
  • cleaning of temporary files via make clean;
  • automatic restart of BILLmanager.
Plugin source code structure
/usr/local/mgr5/src/<my_plugin>/
├── Makefile
├── README.md
├── dist/ (optional, for SQL scripts and configuration files)
├── xml/
│   └── <my_plugin>.xml
└── addon/ (for Python) or src/ (for C++)
    └── <main_script_file>.py or <main_script_file>.cpp

Where:

  • Makefile — a mandatory file that allows installing the plugin using the command:
    make install

The make install command automatically copies files to the required directories:

    • /usr/local/mgr5/addon/
    • /usr/local/mgr5/lib/
    • /usr/local/mgr5/xml/

and restarts BILLmanager;

  • dist — a directory containing the plugin files. For example, SQL scripts or configuration files;
  • <my_plugin>.xml — the name of the XML file containing the plugin description. The XML file describes the plugin's metadata and its interaction with BILLmanager;
  • <main_script_file> — the name of the plugin file. For example, myplugin.py or myplugin.cpp

The source code directory structure of the plugin is further illustrated with examples for Python 3 and C++ languages.

Makefile for Python plugin

Example of Makefile
MGR=billmgr
PLUGIN=myplugin

dist-prepare: $(DISTDIR)/addon/myplugin.py
$(DISTDIR)/addon/myplugin.py: $(shell pwd)/myplugin.py
	@echo "myplugin: copy script"
	@mkdir -p $(DISTDIR)/addon/ && \
		cp -rf $(shell pwd)/myplugin.py $(DISTDIR)/addon/myplugin.py && chmod 744 $(DISTDIR)/addon/myplugin.py

BASE ?= /usr/local/mgr5
include $(BASE)/src/isp.mk
More details

Makefile for C++ plugin

Example of Makefile
MGR=billmgr
PLUGIN=myplugin

LIB += libmyplugin
libmyplugin_LDADD = -lmgrdb -lispapi
libmyplugin_SOURCES = src/myplugin.cpp

BASE ?= /usr/local/mgr5
include $(BASE)/src/isp.mk
More details

Plugin description in XML

The plugin description is stored in the XML file /usr/local/mgr5/xml/billmgr_mod_mypluginname.xml, where billmgr_mod_mypluginname.xml is the name of the XML file containing the plugin description.

XML example for Python 3
<mgrdata>
    <handler name="<myplugin>.py">
        <event name="employee.edit" after="yes" type="xml" ignoreerrors="yes"/>
    </handler>
    <messages name="employee.edit">
        <msg name="mood">Mood</msg>
        <msg name="mood_good">Good</msg>
        <!-- ... other messages ... -->
    </messages>
    <form>
        <field name="mood" type="select" after="name">
            <option value="good">mood_good</option>
            <!-- ... -->
        </field>
    </form>
</mgrdata>
More details
XML example for C++
?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
<library name="libmyplugin"/>
<metadata name="employee.edit" type="form">
	<form title="name">
		<page name="basic">
			<field name="mood" before="name">
				<select name="mood"/>
			</field>
			<field name="msg_to_boss" remove_if="new">
				<textarea name="msg_to_boss" rows="5" wrap="on"/>
			</field>
			<field name="employee_active" remove_if="new">
				<input name="employee_active" type="checkbox"/>
			</field>
		</page>
	</form>
</metadata>
<lang name="en">
	<messages name="employee.edit">
		<msg name="mood">Mood</msg>
		<msg name="mood_good">Good</msg>
		<!-- ... other messages ... -->
	</messages> 
	</lang>
</mgrdata>
More details

Features of Python 3 plugins

Requirements

Requirements for Python 3 plugins:

  • the plugin must be executable;
  • in response to a call from BILLmanager, the plugin must return XML. To output XML to stdout, execute:
    result = ET.tostring(xml, encoding="unicode")
    print(result)

Type field value

For the Python SDK in BILLmanager, it does not matter what is specified in the type field, as parameter retrieval will always occur the same way. However, depending on your goals, you can choose:

  • if you need to work with action metadata — type="xml";
  • if you need to modify data — type="cgi".

Regardless of type, request parameters are available via:

func = session.get_query_param("func")
elid = session.get_query_param("elid")
sok = session.get_query_param("sok")

Use a shebang to ensure the script runs correctly regardless of the Python interpreter's location in the system

 #!/usr/bin/env python3 

Import order

Use the following import order:

  1. Modules included in the standard Python library or installed globally in the system (for example, via pip):
    Standard module import example
    import xml.etree.ElementTree as ET
    import requests
  2.  The sys module and adding the path to the SDK:
    import sys
    sys.path.insert(0, "/usr/local/mgr5/lib/python")
    Where /usr/local/mgr5/lib/python — is the path to the local billing SDK. Needed for subsequent imports from billmgr to be available.
  3. Imports from the billing SDK (billmgr.*)
    Example of module imports from BILLmanager SDK
    import billmgr.logger as logging
    import billmgr.exception as exception
    import billmgr.session as session
    import billmgr.db as db
    import billmgr.misc as misc

The module libraries from the SDK provide functionality for logging, error handling, working with XML sessions, the database, and auxiliary utilities (for example, mgrctl). 

Initializing logging

Perform logging initialization:

logging.init_logging("myplugin")
logger = logging.get_logger("main")
More details

The log will be available in /usr/local/mg5/var/myplugin.log.

To log all request parameters (func, elid, sok etc), execute the command:

session.debug_session(xml)

XML validation

To ensure BILLmanager always receives valid XML, execute the main logic within a try/except block:

Example of code with try/except:
if __name__ == "__main__":
    try:
        result = process_event()
        print(result)
    except exception.XmlException as exc:
        logger.backtrace()
        print(exc.as_xml())
    except Exception as exc:
        logger.backtrace()
        print(exception.XmlException("unknown", "what", str(exc)).as_xml())

BILLmanager forms an XML document describing the form, data, metadata, etc. The document is passed to the plugin via standard input stdin. To read and parse it, use:

xml = session.get_input_xml(True)

To log all request parameters (func, elid, sok etc.), execute the command:


session.debug_session(xml)

Features of C++ plugins

Import order

Keep to the following import order:

  1. C++ standard library headers:
    Example of standard headers import
    #include <sstream>
  2. Internal platform or framework headers: common api, mgr modules:
    #include <api/action.h>
    #include <mgr/mgrlog.h>
    #include <mgr/mgrdb_struct.h>
    #include <mgr/mgrrpc.h>
    Where:
    • api/action.h — defines base classes for handling events in the plugin, including Event and Session;
    • mgr/mgrlog.h —  provides logging facilities via macros. For example, Debug, Warning and STrace;
    • mgr/mgrdb_struct.h — contains tools that describe the structure of database tables. Entities such as IdTable, StringField, ReferenceField allow linking C++ classes with database tables and fields without writing SQL queries;
    • mgr/mgrrpc.h — includes the HttpQuery class, designed for making HTTP requests to external services.
  3. Billing module headers (billmgr):
    Example of module headers import
    #include <billmgr/db.h>
    #include <billmgr/util/http/status.h>

In the example above, the billing module headers provide access to the database, utilities for checking HTTP statuses, etc.

Initializing plugin

Perform plugin initialization to set up logging:

MODULE("myplugin");
More details

The log will be saved in /usr/local/mgr5/var/billmgr.log. The logging level for the module can be configured in the file /usr/local/mgr5/etc/debug.conf or via the platform interface. For more information on configuring logging, see the article Logging in BILLmanager.

If the plugin needs to store data, describe the table as a C++ class inherited from mgr_db::IdTable:

Example of С++ table description
class EmployeeMoodTable : public mgr_db::IdTable {
public:
	mgr_db::ReferenceField User;
	mgr_db::StringField Mood;

	EmployeeMoodTable()
		: mgr_db::IdTable("employee_mood")
		, User(this, "user", mgr_db::rtCascade)
		, Mood(this, "mood")
	{
		AddIndex(mgr_db::itIndex, Mood);
	}
};

In the MODULE_INIT section, register everything needed at startup:

Registering С++ parameters
MODULE_INIT(myplugincpp, "mgr:last") {
    db->Register<plugin_table::EmployeeMoodTable>();  // Table registration
    isp_api::RegisterHandler<eEmployeeEdit>();        // Event registration
}
More details

Logging

We recommend using logging at all stages of development. To get the full log from the plugin:

  1. Add the following line to the /usr/local/mgr5/etc/debug.conf :
    • when writing a plugin in Python — billmgr.pluginname.* 9
    • when writing a plugin in C++ —  billmgr. pluginname  9,

Where:

    • pluginname — the plugin name. For example, pluginname.py or pluginname.cpp;
    • 9 or *9 — the maximum logging level. The higher the logging level, the more detailed information is written to the log. For more information on configuring logging, see the article Logging in BILLmanager.
  1. Add the logging library to the plugin using one of the commands:
    Python
    import billmgr.logger as logging
    С++
    #include <mgr/mgrlog.h>
Useful tips

Related topics:
BILLmanager documentation

COREmanager documentation

The article was last updated on 11.11.2025. The article was prepared by technical writers of ISPsystem