Commit Graph
12 Commits
Author SHA1 Message Date
Jeppe Bandbackend-subagent f0d7d59951 fix(api): post DHL daily goal to internal goal progress webhook (TRU-76) (#405)
## Summary

`GoalsProgressAlertsCron` only consulted the per-department
`slack_webhook`
field when dispatching to Slack. For internal departments — Taulov and
Taastrup are configured as internal via `Slack >
internal_department_ids`
— those per-department webhooks are intentionally empty, so the cron had
no destination to post to and the daily DHL goal never reached the
internal Slack channel.

The dedicated `internal_department_goal_progress_webhook_url` is the
correct destination for these alerts. This change routes the dispatch
through it when **all** of a goal's departments are internal, with a
clean fallback to the existing per-department webhook loop when the
dedicated URL is empty or when the goal includes any non-internal
department. Operator-facing echo lines were added so the cron log
shows exactly which webhook was used for each goal.

## Why "in progress since 21/7"

The legacy cron flow is intact, the new cron-worker is wired up, and
the schedule fires every 60 s as expected. The goal records the right
department IDs. The destination check in the dispatcher silently
matched nothing — the per-department webhook was empty, the fallback to
the default webhook pointed to the wrong channel, and nothing in the
log indicated *which* dispatch path had been taken. Switching the
internal-department branch to the dedicated goal-progress webhook is
the real fix; the diagnostic echo lines prevent this from being silent
in the future.

## Changes

- `services/nginx/app/cron/Cron.php` (GoalsProgressAlertsCron SLACK
  branch): when all linked departments are flagged as internal and the
  dedicated `internal_department_goal_progress_webhook_url` is
  configured, post to that webhook instead of the per-department
  webhooks. Otherwise behave exactly as before.
-
`services/nginx/app/tests/Unit/Cron/GoalsProgressAlertsInternalWebhookTest.php`:
  pin the new dispatch behaviour with four targeted tests covering
  the happy path, the empty-webhook fallback, the mixed/external
  goal path, and the Slack config helper calls.

## Test plan

- `vendor/bin/pest
tests/Unit/Cron/GoalsProgressAlertsInternalWebhookTest.php`
  → 4 passed, 18 assertions.
- `vendor/bin/pest tests/Unit/Cron/` → 34 passed (full cron suite
  still green).
- Manual: after deploy, force-run the task via the existing
  `POST /api/superuser/cron/run` endpoint with body
  `{"job": "goals.progress_alerts"}` and confirm the
  `[CRON] GoalsProgressAlertsCron: goal #N sent to internal goal
  progress webhook (departments: …)` line appears in the cron log and
  the message lands in the configured internal Slack channel.

Fixes TRU-76 (DRIFT 15).

Co-authored-by: backend-subagent <backend@truck-wash.local>
2026-08-17 21:02:06 +02:00
Jeppe Bopenclaw bugfixbugfixbugfix-subagent <[email protected]>
1742033bb7 TRU-70: auto-send invoice on the 3rd business day each month (#402)
## TRU-70: DRIFT 9 — Customer rule "auto-send invoice toggle (3rd
business day each month)"

Adds a per-customer rule that auto-sends the customer's invoice on the
3rd business day of each month. The rule is implemented as a new
customer attribute (`autoSendInvoiceThirdBusinessDay`) that can be
toggled through the existing `POST /customer/attributes` endpoint, plus
a daily cron task that, on the trigger day, enqueues every ready
collected invoice for export via the existing `economic_transfer_queue`.

## Linear

- **TRU-70** (DRIFT 9)

## Changes

- **Customer attribute (TRU-70 / DRIFT 9)**
  - `classes/customer_rule_product_restriction_service.php`
Adds `'autoSendInvoiceThirdBusinessDay'` to `SUPPORTED_ATTRIBUTES` so
the existing customer-attributes route can persist the toggle.

- **3rd-business-day service**
  - `classes/auto_send_invoice_third_business_day_service.php` (new)
- Computes the 3rd business day of any month (weekend-aware, holiday
provider override).
    - `runOnce()` is a no-op on every day except the 3rd business day.
- On the trigger day, scans `customer_attributes` for opted-in customers
and loads their ready `collected_order_invoices` (not booked, not
closed, has at least one order, not deleted).
- Enqueues each via `economic_transfer_queue` and returns a summary
`{triggered, customers, collections_scanned, jobs_enqueued,
skipped_already_queued, errors[]}`.
- Public hooks (`loadEligibleCustomerNumbers`,
`loadReadyInvoiceCollections`) and protected `createTransferQueue()` are
designed for unit-test isolation so no live database is required.

- **Cron task (TRU-70 / DRIFT 9)**
  - `modules/economic/cron/tasks.php`
Registers `'economic.auto_send_invoices_third_business_day'` with a 24h
interval, 15 min timeout, priority 25. Anchored in the economic module
because the actual export goes through `economic_transfer_queue`.
  - `cron/Cron.php`
New `AutoSendInvoicesThirdBusinessDay()` handler. Mirrors the
surrounding cron-task conventions (`warn` + `error_log` breadcrumb on
failure) and only logs a one-liner when the trigger fires.

## Tests

- `tests/Unit/Cron/AutoSendInvoiceThirdBusinessDayTest.php` (new, 16
tests)
- The 3rd-business-day computation (weekday-start, weekend-start,
Saturday, 4th-business-day, holiday skip, holiday forward-shift).
- `thirdBusinessDayOfMonth()` helper for the three reference months used
in the spec (Aug/Sep 2026 and Jul 2026).
  - `runOnce()` no-op path on non-trigger days.
  - `runOnce()` summary on trigger day with zero opted-in customers.
  - `runOnce()` summary with customers and ready collections.
  - `runOnce()` per-collection error recording when enqueue throws.
  - `clearOverrides()` reset.
- The new attribute is in
`customer_rule_product_restriction_service::SUPPORTED_ATTRIBUTES` and
exposes a stable `ATTRIBUTE` constant.
- `tests/Unit/Cron/CronTaskRegistryTest.php`
Updated the discovery assertion from 22 to 23 definitions and added
coverage that the new `'economic.auto_send_invoices_third_business_day'`
task is discovered with the expected schedule and module.

## Backwards compatibility

- The new attribute is additive; existing `customer_attributes` rows are
unaffected. The default customer has no auto-send rule.
- The cron task is registered in the standard task registry; the
existing `cron_worker` (15s poll) handles the trigger without any new
infrastructure.
- The service gracefully no-ops when the transfer queue is unavailable
in unit-test contexts; the production cron task will surface a `warn()`
breadcrumb if e-conomic is unreachable, exactly like the other economic
cron tasks.

## Verification

```
vendor/bin/pest tests/Unit/Cron/ tests/Unit/Customers/
# 43 passed (199 assertions)
```

---------

Co-authored-by: openclaw bugfix <openclaw@copenhagentruckwash.local>
Co-authored-by: bugfix <bugfix@truckwash.local>
Co-authored-by: bugfix-subagent <[email protected]>
2026-08-17 16:42:14 +00:00
935b2d58ce fix(api): remove broken Coolify cron-worker auto-deploy (#389)
## Summary

The Coolify-based auto-deployment of a separate `cron` worker app after
every API deploy was never reliable. This PR removes the ~800 lines of
dead auto-deploy logic from `release_manager.php` while keeping the
underlying cron mechanism (`cron_worker.php`, `cron_scheduler.php`, the
docker-compose `cron-worker` service) intact.

## Changes

- **`release_manager.php`** (-818 lines)
- Removed 19 private methods: `deployCronWorker*`, `cronWorker*`,
`cronWorkerAutoprovision*`, etc.
- Removed 3 constants: `CRON_WORKER_APP`, `CRON_WORKER_START_COMMAND`,
`CRON_WORKER_DESIRED_COUNT`
- Kept `cronWorkerStatus()` but rewrote as a direct DB query (no Coolify
dependency)
- **`tests/Unit/ReleaseManager/ReleaseManagerTest.php`** (-208 lines,
removed 9 cron-worker tests)
- **`tests/Unit/Cron/CronWorkerWiringTest.php`** (rewritten — now
asserts removed wiring is GONE)
- **`docs/CRON_PLAN.md`** (new — comprehensive plan)

## What replaced the broken auto-deploy

- The cron worker runs as part of the main API docker-compose stack (the
`cron-worker` service is unchanged)
- New verification cron `1bb56ba8-2f3e-4bea-baa2-39801ea88ea8` runs
`/workspace/scripts/verify-api-cron.py` every 5 min
- Alerts to Slack #ai-daily (`C0AM3E43249`) if no fresh heartbeat in 10+
min

## Test results

- 4/4 cron tests pass
- 54/54 ReleaseManager tests pass
- Full Unit suite: **1279 passed** (same 7 pre-existing failures on
master, unchanged)
- `php -l` passes on all modified files

## Plan

See `docs/CRON_PLAN.md` for the full audit, plan, and acceptance
criteria.

🤖 Generated with [OpenClaw](https://docs.openclaw.ai)

---------

Co-authored-by: bugfix <bugfix@truckwash.local>
Co-authored-by: openhands <openhands@all-hands.dev>
2026-08-17 10:16:03 +02:00
Jeppe Bandopenhands 5441fea665 fix(api): simplify XLVask Selvvask surface by removing AI autopilot pipeline (#367)
## Summary

Removes the XLVask autopilot / automation / MiniMax / OpenAI pipeline
and the related module config, CLI, cron, and migration scaffolding. The
Selvvask view (Superuser -> Fakturaer -> Periode -> Selvvask) is reduced
to a single read-only listing of usage logs plus operator-driven ignore
/ unignore / accept / reject endpoints gated on the
`review_xlvask_usage_order` permission.

See `inventory/self-serve-inventory.md` for the full surface map.

## Test plan

- [x] `vendor/bin/pest --testsuite=Unit` -> **1266 passed**, 1 unrelated
pre-existing failure (`BirdControlPlaneActivationTest`, needs
`PLENO_REPO_ROOT_FOR_TESTS`).
- [x] `php -l` on every modified PHP file -> no syntax errors.
- [x] Grep validation -> zero production-code references to removed
surfaces (`xlvask_autopilot_service`, `xlvask_automation_service`,
`xlvask_automation_policy_service`, `EnsureXLVaskAutomationSchema`,
`runScheduledAutomationIfReady`, `processAutopilotQueue`, `MiniMax`,
`minimax`, ...).
- [ ] Qodana + Tests workflows green on this PR.

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-08-12 20:02:30 +02:00
Jeppe B 6d888a455d Automate XL-Vask invoice-period resolution (#340)
Deploy the revision-aware XL-Vask import and guarded autopilot infrastructure. Automatic actions remain fail-closed pending production readiness, calibration, dry-run, and canary gates.
2026-08-03 15:33:55 +02:00
Jeppe B 8d8f0eccce Fix cron worker minute cadence (#324)
Replace drifting cron loops with persistent cadence-tracked workers and CI-verifiable Compose wiring.
2026-07-27 18:16:09 +02:00
Jeppe B 0060fb45ca Add in-app account deletion (#319)
## Summary
- Add self-service deletion for the authenticated customer or subuser
identity only.
- Preserve shared customer grants, reset keys, bookings, order bookings,
vehicles, invoices, and legally required history.
- Require password/TOTP or a fresh deletion-specific, five-minute,
single-use WebAuthn assertion.
- Reject support impersonation and expired legacy plain-session tokens.
- Use durable database throttling, transactional request processing, a
durable outbox, and terminal `manual_review` state.
- Keep API and worker default-off behind separate
`account_deletion.api_enabled` and `account_deletion.worker_enabled`
module-config flags.

## Safe rollout
1. Keep both flags disabled.
2. Run `php scripts/account-deletion-schema.php check`.
3. If needed, run `php scripts/account-deletion-schema.php apply --yes`,
then rerun `check` until `ready:true`.
4. Deploy the frontend companion PR while the API remains disabled.
5. Enable `api_enabled` for a controlled canary; verify password and
passwordless request flows plus immediate authentication revocation.
6. Inspect queued request/outbox state, then enable `worker_enabled`.
7. Verify anonymization, preserved tenant/history data, outbox delivery,
retries, and manual-review behavior before broad rollout.

## Verification
- Account deletion unit tests: 2 passed, 43 assertions.
- PHP lint, both OpenAPI YAML parses, runtime-DDL scan,
destructive-scope scan, and `git diff --check` passed.
- Full API/unit/integration evidence is required from exact-head CI;
local Docker is unavailable and shared-vendor tests were explicitly
discarded.

## Security notes
- Schema mutation is CLI-only; web and cron paths perform read-only
readiness checks.
- Runtime behavior fails closed when schema/config/throttle/delivery
prerequisites are unavailable.
2026-07-22 19:22:17 +02:00
Jeppe B 0feb705059 Support collected invoice economic PDF downloads 2026-07-14 15:39:39 +02:00
Jeppe Bundgaard 026492c3bd Queue cron runs through workers 2026-07-13 20:03:39 +02:00
Jeppe Bundgaard 012e5366ba Add system status displays for Minio and Redis, and enhance backup configuration 2026-07-13 10:08:00 +02:00
Jeppe B fa1ade555f Fix self-serve cron registry test
Fix self-serve cron registry test
2026-07-09 11:36:11 +02:00
Jeppe Bundgaard 6a00f023b1 Refactor cron scheduling 2026-07-09 11:04:13 +02:00