Block and unblock internet access based on AbraFlexi invoices
console applicationSystemConsoleOnlyapt install isp-toolsISP network management tools driven by the invoice status in AbraFlexi. Customers with an overdue third reminder are marked as disconnected, their addresses are blocked in the network configuration and restored again once the debt is paid. Received payments are confirmed to customers by e-mail. Every tool can be scheduled through MultiFlexi or triggered by its events.
Included tools:
ISP network management tools for blocking/unblocking internet access based on AbraFlexi invoice status.
abraflexi-reminder (3rd reminder sent)
โ
โ emits: invoice.reminder.sent
โผ
multiflexi-event-processor
โ rule: invoice.reminder.sent โ mark-defaulters runtemplate
โผ
abraflexi-mark-defaulters
- finds customers with UPOMINKA3 + active internet contract (typSml `INTERNET`)
- sets ODPOJENO label in AbraFlexi
โ
โ AbraFlexi webhook: adresar updated
โผ
multiflexi-event-processor
โ rule: adresar update โ blocknet runtemplate
โผ
blocknet
- disconnects all customers with ODPOJENO label
Payment clears โ abraflexi-reminder-clean-labels removes UPOMINKA* โ
multiflexi-event-processor triggers unblocknet โ internet restored.
AbraFlexi: new record in banka or pokladna evidence
โ
โ webhook via abraflexi-webhook-acceptor โ changes_cache
โผ
multiflexi-event-processor
โ rule: banka/pokladna create โ abraflexi-match-received-payment runtemplate
โ env_mapping: {"DOCUMENTID": "recordid"}
โผ
abraflexi-match-received-payment (from abraflexi-matcher / multiflexi-abraflexi-matcher)
exit 0: payment matched to invoice (emits payment.received)
โ
โ AbraFlexi: faktura-vydana updated (linked to payment)
โ webhook: faktura-vydana, update
โผ
multiflexi-event-processor
โ rule: payment.received / faktura-vydana update โ potvrzeni-prijeti-uhrady runtemplate
โ env_mapping: {"DOCID": "recordid"}
โผ
isp-potvrzeni-prijeti-uhrady
- sends tax document confirmation to customer
exit 2: payment found but not matched (unknown varsym / under/overpayment)
โ emits payment.unmatched
โ rule: payment.unmatched โ potvrzeni-prijeti-bankovni-platby runtemplate
โ env_mapping: {"DOCID": "recordid"}
โผ
isp-potvrzeni-prijeti-bankovni-platby
- notifies customer their payment was received but awaits manual matching
Note on Pipeline B stage 2: the
multiflexi-event-processorreacts to AbraFlexi webhook changes (bank/cash record created, invoice settled), see Setting up event rules. Reacting to the matcher's exit code (payment.unmatched, exit 2) is not supported yet; until then runisp-potvrzeni-prijeti-bankovni-platbymanually or from a wrapper that inspects the matcher's exit code.
This project provides five MultiFlexi applications. Pipeline B payment
matching is not shipped here โ install
abraflexi-matcher
(multiflexi-abraflexi-matcher) and use its AbraFlexi Payment Matcher
app (abraflexi-match-received-payment, uuid
23bf774d-de12-44b7-b4ef-454dd11ed8fd).
abraflexi-mark-defaulters)Identifies customers with the UPOMINKA3 label (3rd reminder sent) who also
have an active internet service contract and marks them for disconnection by
adding the ODPOJENO label. Triggered by the invoice.reminder.sent event.
Customers with only VoIP, IpTV, Hosting or Housing contracts are not marked
for internet disconnection even if their invoices are overdue. Set INET_CONTRACT_TYPE
to the AbraFlexi contract type code (typSml, e.g. INTERNET) to enable precise filtering.
blocknet)Blocks internet access for all clients with the ODPOJENO (DISCONNECTED) label in AbraFlexi.
Customers labelled VIP or NEODPOJOVAT are skipped. Customer IP addresses are
resolved through the configured network backend and each IP is blocked by setting
its speed to 0.
unblocknet)Restores internet access for disconnected customers who no longer owe:
ODPOJENO label.DEFAULT_SPEED is the fallback).ODPOJENO label is removed from the customer.abraflexi-match-received-payment)Provided by abraflexi-matcher, not this package. Matches a received
bank/cash payment to an unpaid issued invoice and links it via AbraFlexi
payment pairing (sparovani).
DOCUMENTID (record code or numeric id, required),
ABRAFLEXI_PARTIAL_MATCH (settle underpayments automatically).0 = matched and linked (emits payment.received),
2 = received but cannot be auto-matched (emits payment.unmatched),
1 = error (payment not found).isp-potvrzeni-prijeti-uhrady)Sends the customer a payment-received confirmation email with the tax document
(invoice PDF) attached. Skips invoices that are not (at least partially) paid,
so it is safe to trigger from a generic faktura-vydana update rule.
DOCID (faktura-vydana code, required), EASE_FROM, MUTE
(true = dry run).0 = sent (or dry run / not paid), 1 = error (unknown
document, no email, send failure).isp-potvrzeni-prijeti-bankovni-platby)Notifies the customer that their bank payment was received but awaits manual matching by accounting.
DOCID (bank record code or numeric id, required), PAYMENT_EVIDENCE,
EASE_FROM, MUTE.0 = notified (unknown payer is a warning, not an error),
1 = error.composer install
Copy .env.example to .env and configure your connections:
cp .env.example .env
ABRAFLEXI_URL - Your AbraFlexi server URL (e.g., https://your-server.com:5434)ABRAFLEXI_LOGIN - AbraFlexi usernameABRAFLEXI_PASSWORD - AbraFlexi passwordABRAFLEXI_COMPANY - Company code in AbraFlexiEASE_LOGGER - Logging configuration (default: console|syslog)RESULT_FILE - Output file for results (default: isp_tools_result.json)APP_DEBUG - Debug mode (default: false)LABEL_DISCONNECTED - Label for disconnected customers (default: ODPOJENO)LABEL_NODISCONNECT - Label for customers not to disconnect (default: NEODPOJOVAT)LABEL_VIP - VIP customer label (default: VIP)LABEL_THIRD_REMINDER - Label set by abraflexi-reminder after the 3rd reminder (default: UPOMINKA3)Matching itself is configured on the abraflexi-matcher runtemplate
(abraflexi-match-received-payment). The confirmation scripts in this
package only need:
PAYMENT_EVIDENCE - Evidence to load unmatched payments from: banka, pokladna or auto (default auto)EASE_FROM - Sender address for confirmation emailsMUTE - true = dry run, confirmation emails are not actually sentDEFAULT_SPEED - Fallback speed used when the backend has no stored original speed (default: 0)SVNUSER - Subversion repository usernameSVNPASS - Subversion repository passwordSVNURL - Subversion repository URLSVNBIN - Path to subversion binary (default: /usr/bin/svn)LOGFILE - Path to log file for operationsBlocking rewrites the hosts-file comment of the customer's IP line to
# speed=0 orig=<previous speed>; unblocking restores the speed recorded in
the orig= token (falling back to DEFAULT_SPEED when the line never carried
a speed= value). Customer IPs are resolved preferably by the machine-readable
{code:XXXXX} comment token.
NETBOXURL - NetBox server URL (e.g., https://netbox.yourdomain.com)NETBOXTOKEN - NetBox API token for authenticationbin/abraflexi-mark-defaulters
bin/blocknet
bin/unblocknet
These applications are designed to work with MultiFlexi for automated scheduling and execution.
The MultiFlexi application definitions are located in the multiflexi/ directory:
mark_defaulters.multiflexi.app.json - MarkDefaulters application definitionblocknet.multiflexi.app.json - BlockNet application definitionunblocknet.multiflexi.app.json - UnblockNet application definitionpotvrzeni_prijeti_uhrady.multiflexi.app.json - PotvrzeniPrijetiUhrady application definitionpotvrzeni_prijeti_bankovni_platby.multiflexi.app.json - PotvrzeniPrijetiBankovniPlatby application definitionPayment matching uses match_received_payment.multiflexi.app.json from
the multiflexi-abraflexi-matcher package (executable
abraflexi-match-received-payment).
The event-driven pipelines need the whole delivery chain to work:
AbraFlexi โโwebhookโโโถ abraflexi-webhook-acceptor โโโถ changes_cache (SQL)
โ polled (30 s)
โผ
multiflexi-eventor (event source "AbraFlexiWebHookAcceptor")
โ event rules
โผ
MultiFlexi runtemplates
abraflexi-webhook-acceptor) configured in
/etc/abraflexi-webhook-acceptor/.env and reachable from the AbraFlexi
server.GET /c/<company>/hooks.json; an empty hooks list means events are lost).
Register it with the acceptor's installer.php or POST /c/<company>/hooks, URL
https://<host>/abraflexi-webhook-acceptor/webhook.php?company=<company>.multiflexi-cli event-source:list) pointing
at the acceptor database; multiflexi-eventor.service running.After registering the ISP Tools apps and the AbraFlexi Payment Matcher
app (multiflexi-abraflexi-matcher) in MultiFlexi and creating their
runtemplates, configure the event processor rules via multiflexi-cli
(event-rule:create, options --event_source_id --evidence --operation --runtemplate_id --priority --enabled --env_mapping). The env_mapping maps a
runtemplate variable to a column of the changes_cache row delivered by the
webhook acceptor: recordid (AbraFlexi record id), evidence, operation,
externalids (e.g. code:E2ETEST2), inversion. There is no kod column
and the code: prefix of externalids cannot be stripped, so the customer code
cannot be passed to the runtemplate from an adresar change.
Rules in use on the test deployment (vyvojar.spoje.net), highest priority first:
| # | Trigger | Runs | env_mapping | Status |
|---|---|---|---|---|
| 7 | adresar update (webhook) |
Mark Defaulters | {} |
works; sweep over all UPOMINKA3 customers |
| 3 | adresar update (webhook) |
BlockNet | {"CUSTOMER":"kod"} |
works, but kod does not resolve โ sweep (see below) |
| 6 | adresar update (webhook) |
UnblockNet | {} |
works; sweep over all ODPOJENO customers |
| 4 | banka create (webhook) |
Match Received Payment | {"DOCUMENTID":"recordid"} |
works |
| 5 | pokladna create (webhook) |
Match Received Payment | {"DOCUMENTID":"recordid"} |
same as 4 |
| 1 | faktura-vydana settled (webhook) |
Clear Reminder Labels | {"ABRAFLEXI_CUSTOMER":"firma"} |
fails: firma arrives as code:KOD and the app answers "Customer code:KOD not found" |
# Rules 3/6/7: any adresar change โ mark defaulters, block, unblock (in this order)
multiflexi-cli event-rule:create --event_source_id 1 --evidence adresar --operation update \
--runtemplate_id <MARK_DEFAULTERS_RUNTEMPLATE_ID> --priority 20
multiflexi-cli event-rule:create --event_source_id 1 --evidence adresar --operation update \
--runtemplate_id <BLOCKNET_RUNTEMPLATE_ID> --priority 10
multiflexi-cli event-rule:create --event_source_id 1 --evidence adresar --operation update \
--runtemplate_id <UNBLOCKNET_RUNTEMPLATE_ID> --priority 0
# Rules 4/5: new bank / cash record โ match the payment
# (recordid = AbraFlexi record id; `id` would be the cache row id and match a wrong payment!)
multiflexi-cli event-rule:create --event_source_id 1 --evidence banka --operation create \
--runtemplate_id <MATCHER_RUNTEMPLATE_ID> --env_mapping '{"DOCUMENTID":"recordid"}'
multiflexi-cli event-rule:create --event_source_id 1 --evidence pokladna --operation create \
--runtemplate_id <MATCHER_RUNTEMPLATE_ID> --env_mapping '{"DOCUMENTID":"recordid"}'
Rules that fire when another runtemplate finishes (runtemplate_source_id)
only work if the finished job produces data (produces in its application
definition); otherwise the chaining engine skips it. Reminder, Clear Reminder Labels
and Mark Defaulters produce nothing, so such rules never fire โ use the webhook
rules above instead (the Reminder sets UPOMINKA3, which AbraFlexi reports as an
adresar update).
Blocking, unblocking and marking are sweeps.
CUSTOMERis not passed (rule 3 maps a column that does not exist), so everyadresarchange runs the three tools over all relevant customers. They are idempotent, and UnblockNet keeps customers that still have overdue invoices blocked, but a customer labelledODPOJENOwithout overdue invoices is unblocked and loses the label right away. Beware of this on test AbraFlexi instances with manyODPOJENOcustomers (vyvojar DEV had 25; oneadresarchange cleared them).
Rule 1 needs a fix in
abraflexi-reminder(acceptcode:prefixed customers) or in the event processor (strip the prefix); until then Clear Reminder Labels has to be started manually withABRAFLEXI_CUSTOMER=<kod>.
payment.unmatched(matcher exit 2 โ bank payment notification) is not available: the event processor does not react to job exit codes yet. the event processor does not react to job exit codes yet.
Set to INTERNET for Spoje.net deployment to restrict disconnection
to customers with an active (stavSml = AKTIVNI) contract of type INTERNET
(evidence typ-smlouvy). code:INTERNET and the legacy typSmlouvy.INTERNET
spelling are accepted too. Leave empty to match all contract types.
| Label | Set by | Meaning |
|---|---|---|
UPOMINKA3 |
abraflexi-reminder | 3rd payment reminder sent |
ODPOJENO |
abraflexi-mark-defaulters | Customer marked for disconnection |
NEODPOJOVAT |
Manual | Never disconnect this customer |
VIP |
Manual | Skip disconnection for VIP customers |
Notes:
success: false. On the vyvojar DEV company
NEODPOJOVAT does not exist yet (ODPOJENO, UPOMINKA3, VIP do).stitky field, it does not replace it.
Removing labels needs the stitky@removeAll directive
(Adresar::unsetLabel()); writing a shorter list leaves the old labels in place.For modern infrastructure management, the system supports NetBox as an alternative backend to Subversion.
Add NetBox settings to your .env file:
# NetBox API Configuration
NETBOXURL=https://your-netbox-instance.com
NETBOXTOKEN=your-api-token-here
speed to IP addresses:
To switch from Subversion-based management to NetBox:
Pass a NetBoxer instance to the DeBlocker constructor (it defaults to
SubVersioner):
$deblocker = new \SpojeNet\DeBlocker(new \SpojeNet\NetBoxer());
Ensure all customer IPs are properly configured in NetBox with speed custom fields
Test blocking/unblocking operations
Note: the NetBox backend currently implements only customer IP lookup; its
blockIp()/unblockIp()operations are not implemented yet.
speed for speed managementThe project includes comprehensive unit tests for all components.
composer install
vendor/bin/phpunit
For testing the Subversion backend, a test repository is included in tests/svn/ containing:
tests/svn/README.mdThe test repository allows testing blocking/unblocking operations without affecting production systems.
The complete flow is rehearsed on vyvojar.spoje.net against the DEV AbraFlexi
(flexibee-dev.spoje.net, company spoje_net_s_r_o_) and a local Subversion
repository (file:///var/lib/isp-tools-test-svn/hosts-repo/hostsbrevnov, user
multiflexi-test), never against the production hosts repository. MultiFlexi company 21
("Testing") holds the runtemplates Block Internet Access, Unblock Internet Access,
Mark Defaulters - Testing and Match Received Payment; the AbraFlexi connection comes
from the shared credential Testing / AbraFlexi Testing. Test customers E2ETEST1
(10.99.99.11) and E2ETEST2 (10.99.99.12) have {code:โฆ} lines in the test hosts file.
Single customer from the command line (one-time CUSTOMER override):
multiflexi-cli run-template:schedule --id <BLOCK_RT> --schedule_time now --env CUSTOMER=E2ETEST2
svn log -v -l 1 file:///var/lib/isp-tools-test-svn/hosts-repo/hostsbrevnov # Auto-block-IP-โฆ
Verified so far:
| Case | Result |
|---|---|
Disconnect: ODPOJENO label โ BlockNet |
commit Auto-block-IP-โฆ, line becomes # speed=0 orig=N โฆ |
| Reconnect: UnblockNet without debt | commit Auto-unblock-IP-โฆ, original speed restored from orig=, label removed |
| Customer with unpaid overdue invoice | UnblockNet keeps the block (still_owes), no commit |
Customer labelled VIP |
skipped by BlockNet, hosts file untouched |
Customer with no IP in hosts |
reported as "No IP addresses found", no commit |
Mark Defaulters with no UPOMINKA3 customer |
exit 0, "No customers with UPOMINKA3 label found." |
| Webhook chain (AbraFlexi โ acceptor โ eventor โ BlockNet) | label change blocks the customer within ~1 minute |
| Customer labelled NEODPOJOVAT | skipped by BlockNet (label had to be created in DEV AbraFlexi first) |
| Mark Defaulters (UPOMINKA3 + active INTERNET contract) | customer gets ODPOJENO, webhook โ BlockNet commits speed=0 (needed the stavSml/typSml fix) |
| Bank payment with matching VS โ rule 4 โ matcher | invoice settled (exit 0) |
| adresar change โ UnblockNet (rule 6) | customers without debt unblocked, labels removed |
Not verified end to end: the complete cycle on one customer without manual steps
(Clear Reminder Labels has to be started by hand, see rule 1), and the confirmation
mails (Payment Received Confirmation fails with MAIL_FROM is not set on the test
runtemplate).
isp-tools.svg โ application icon (installed to hicolor/scalable/apps)multiflexi/<application-uuid>.svg โ one icon per MultiFlexi application,
installed to the shared /usr/share/multiflexi/images/debian/io.github.spoje_net.isp_tools.metainfo.xml โ AppStream metadata
(validate with appstreamcli validate --no-net)MIT
This package may not be indexed in our database yet. Please try again later or check the package repository directly.