alerts: per-support-team webhook; printedparts routes low-stock to a chosen team

Support teams gain a webhookurl (migration 7d29 + API + settings-page field), so
a team is a notification target. send_webhook(url=) lets a caller override the
site default with a team's webhook. Printedparts gains a 'alert support team'
setting (printedparts_alert_supportteamid) + selector on its settings page;
low-stock alerts post to that team's webhook, falling back to the site
alert_webhook_url. Email leg unchanged. Same pattern extends to other alerting
plugins (printers low-toner next).
This commit is contained in:
cproudlock
2026-07-22 13:32:00 -04:00
parent 824863a95a
commit fb188fd302
9 changed files with 142 additions and 21 deletions

View File

@@ -398,3 +398,27 @@ def test_kiosk_take_records_revision_from_qr(client, app, db, directory_employee
.filter_by(printeditemid=iid, transactiontype='take')
.order_by(PrintedItemTransaction.transactionid.desc()).first())
assert last.revision is None
def test_lowstock_routes_to_support_team_webhook(client, app, db, directory_employee):
"""A low-stock crossing posts to the selected support team's webhook URL."""
from unittest.mock import patch
from shopdb.core.models import SupportTeam, Setting
with app.app_context():
team = SupportTeam(teamname='3D Print Team',
webhookurl='https://teams.example/3dprint')
db.session.add(team)
db.session.commit()
Setting.set('printedparts_alert_supportteamid', str(team.supportteamid))
row = PrintedItem(itemcode='3DP-7100', gagelabtag='WJRP7100',
itemname='Widget', quantityonhand=6, lowstockthreshold=5)
db.session.add(row)
db.session.commit()
with patch('shopdb.api.send_webhook') as mock_send:
# take 2 -> 6 crosses to 4 (<= threshold 5) -> alert fires
resp = client.post('/api/printedparts/kiosk/take', json={
'itemcode': 'WJRP7100', 'badge': directory_employee, 'quantity': 2})
assert resp.status_code == 200, resp.get_json()
assert mock_send.called
assert mock_send.call_args.kwargs['url'] == 'https://teams.example/3dprint'