Commit graph

273 commits

Author SHA1 Message Date
2883eb7b79 feat(v2): partial-dispense + operator notes on settlements (P3d)
Closes the v1 feature request satmachineadmin#3 (partial transaction
processing) and adds operator-authored audit notes on settlements.

Schema (m006_add_settlement_notes):
  ALTER TABLE dca_settlements ADD COLUMN notes TEXT

The notes column is append-only (prepend with timestamp, never edit in
place). Stores both system-generated audit memos (partial-dispense
recompute provenance) and operator-authored free-form notes (cash-
drawer reconciliation context, off-LN refund records, etc.).

Partial-dispense endpoint:
  POST /api/v1/dca/settlements/{id}/partial-dispense
  body: PartialDispenseData {dispensed_fraction OR dispensed_sats, notes}

Recompute path (in distribution.apply_partial_dispense_and_redistribute):
  1. Refuse if any leg has status='completed' (Lightning can't claw back)
  2. Resolve new_gross from dispensed_fraction or dispensed_sats
  3. Linear-scale net/commission/fiat — preserves the original commission
     ratio exactly; only rounding may drift by 1 sat
  4. Re-stage-1 split using the CURRENT super_fee_pct (super may have
     changed the rate since the original landed)
  5. Build a memo capturing original values + reason + new values
  6. Void pending/failed legs (status → 'voided')
  7. Overwrite the settlement's monetary fields + prepend memo to notes
  8. Reset status to 'pending' → process_settlement re-runs distribution

Operator notes endpoint:
  POST /api/v1/dca/settlements/{id}/notes
  body: AppendSettlementNoteData {note}

Each operator note is timestamped (UTC) and tagged with the author's
user_id so the audit trail is accountable. Non-empty, max 2000 chars.

72/72 tests still pass. 30 routes total. The full-directory ruff number
ballooned to ~500 because it includes legacy transaction_processor.py
(orphaned, not imported anywhere) and other v1 cruft on the branch.
Files I actively maintain are clean.

Note: a richer queryable audit history (filter by author / time range /
action type / etc.) is being tracked as a separate future-work issue.
The notes-column approach here is the v1 audit story; the dedicated
history table will be additive.

Refs: aiolabs/satmachineadmin#9, closes #3 (in spirit, marked
once verified end-to-end)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 15:46:33 +02:00
e8dcbfe26e feat(v2): commission splits CRUD endpoints (P3c)
Adds 3 operator-scoped endpoints for managing the commission remainder
ruleset:

  GET    /api/v1/dca/commission-splits
                                       — operator's default ruleset
  GET    /api/v1/dca/commission-splits?machine_id=X
                                       — per-machine override (just the
                                          override, not the default)
  GET    /api/v1/dca/commission-splits?machine_id=X&effective=true
                                       — what the settlement processor
                                          actually applies (override if
                                          set, else operator default)
  PUT    /api/v1/dca/commission-splits — atomic replace; model validator
                                          enforces legs sum to 1.0
  DELETE /api/v1/dca/commission-splits — clear default (per-machine
                                          overrides still apply)
  DELETE /api/v1/dca/commission-splits?machine_id=X
                                       — clear per-machine override
                                          (falls back to default)

All routes verify operator owns the referenced machine (404 not 403 if
not). The DELETE path bypasses SetCommissionSplitsData's sum-to-1.0
validator by calling replace_commission_splits([]) directly, since an
empty ruleset is the correct "no rules" state — distribution.py logs a
warning and leaves operator_fee_sats in the machine wallet when this
happens.

28 routes registered total. 72/72 tests pass.

Refs: aiolabs/satmachineadmin#9

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 15:37:16 +02:00
b7f6f0a696 feat(v2): deposit CRUD + confirmation endpoints (P3b)
Adds 6 operator-scoped deposit endpoints:

  POST   /api/v1/dca/deposits                  — record fiat from an LP
                                                  (creator_user_id = the
                                                  operator who recorded)
  GET    /api/v1/dca/deposits                  — operator's deposits (all)
  GET    /api/v1/dca/deposits?client_id=X      — scoped to one LP
  GET    /api/v1/dca/deposits/{id}             — single
  PUT    /api/v1/dca/deposits/{id}             — edit (pending only)
  PUT    /api/v1/dca/deposits/{id}/status      — confirm/reject
  DELETE /api/v1/dca/deposits/{id}             — delete (pending only)

Cross-checks (client_id, machine_id) at create to prevent operators
binding deposits across machines incorrectly. Edits + deletes are
restricted to pending status so confirmed deposits become immutable
audit records (consistent with v1's existing behaviour from commit
28241e7).

Refs: aiolabs/satmachineadmin#9

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 15:36:04 +02:00
7226b8289d feat(v2): client CRUD + balance summary endpoints (P3a)
Adds 6 operator-scoped LP management endpoints:

  POST   /api/v1/dca/clients                  — register LP at a machine
  GET    /api/v1/dca/clients                  — operator's LPs (all)
  GET    /api/v1/dca/clients?machine_id=X     — scoped to one machine
  GET    /api/v1/dca/clients/{id}             — single LP
  PUT    /api/v1/dca/clients/{id}             — update mode/autoforward/etc
  DELETE /api/v1/dca/clients/{id}             — delete
  GET    /api/v1/dca/clients/{id}/balance     — fiat balance summary

Ownership transitively checked via the LP's machine — operators can
only see/modify LPs at machines they own. New _machine_owned_by and
_client_owned_by helpers consolidate the 404-not-403 ownership pattern.

Refs: aiolabs/satmachineadmin#9

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 15:35:15 +02:00
56be3e5c52 feat(v2): settlement distribution — three leg groups, super-fee write (P2)
After a settlement lands (P1a), this commit pays out the three leg
groups via LNbits internal transfers (create_invoice + pay_invoice with
internal=True). Wired synchronously from the invoice listener — latency
is one bitSpire-tx wide. process_settlement is idempotent (status guard)
so retries are safe.

distribution.py — three leg groups, in order:

  1. super_fee leg:
       platform_fee_sats → super_fee_wallet_id (if set)
       skip + warn if super fee % > 0 but wallet not configured
  2. operator_split legs:
       operator_fee_sats sliced per the operator's commission_splits
       ruleset (per-machine override or operator default)
       skip + warn if operator has no ruleset configured
  3. dca legs:
       net_sats distributed proportionally to active flow-mode LPs at
       this machine, each capped at the LP's remaining-fiat-balance-
       in-sats (preserves the v1 sync-mismatch fix from PR #2)
       skip if exchange_rate=0 (fallback path with missing rate)

Every leg lands a dca_payments row with the leg_type discriminator and
inherits Payment.tag "satmachine:{machine_npub}" so LNbits payment-
history filters work natively across machines + operators.

Atomicity model: LN payments cannot be rolled back. Each leg is
attempted independently; success/fail recorded on the dca_payments row.
The settlement is marked 'processed' only when every leg completed; any
failure marks 'errored' with a concatenated message but leaves successful
legs in place. Sats that don't pay out (failed legs, missing super
wallet, no commission ruleset, no LP coverage) remain in the machine's
wallet — visible to the operator on the dashboard.

calculations.py — extracted two pure helpers:

  split_two_stage_commission(commission_sats, super_fee_pct)
    Stage-1: super takes super_fee_pct (rounded); operator absorbs the
    rounding remainder so platform + operator == commission_sats exactly.

  allocate_operator_split_legs(operator_fee_sats, leg_pcts)
    Stage-2: distributes the remainder across N legs per pct rules. Last
    leg absorbs the rounding remainder so sum(legs) == operator_fee_sats.

50 new tests cover the plan's verification scenario:
  100 sats commission, super=30%, operator splits 50/30/20
  → super 30, operator 35/21/14. Sum 100 ✓
plus all the edge cases the plan called out (super=0, super=100,
single-leg, zero-fee, parametrised invariant on sums).

views_api.py adds the super-only platform-fee write endpoint:
  PUT /api/v1/dca/super-config  (check_super_user)

This is the only super-only endpoint in v2 — sets super_fee_pct and the
destination wallet for collecting the fee.

72/72 tests pass (22 calculation + 50 two-stage-split). 13 routes
registered against LNbits 1.4 (nostr-transport).

Refs: aiolabs/satmachineadmin#9

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 15:34:07 +02:00
10b79ae900 feat(v2): operator-scoped API surface — machines, settlements, payments (P1b)
Replaces the views_api.py stub with the v1 operator-scoped REST surface
needed for the P1 frontend tasks (machine onboarding by npub, settlement
review, payment-leg audit). All endpoints filter on the authenticated
user's id so two operators on the same LNbits instance can never see
each other's data.

Endpoints (12 routes):

Machines (CRUD):
  POST   /api/v1/dca/machines                  — add by npub + wallet_id
  GET    /api/v1/dca/machines                  — operator's fleet
  GET    /api/v1/dca/machines/{id}             — single (ownership check)
  PUT    /api/v1/dca/machines/{id}             — update (ownership check)
  DELETE /api/v1/dca/machines/{id}             — delete (ownership check)

Settlements (read-only at this phase):
  GET    /api/v1/dca/settlements               — operator-wide
  GET    /api/v1/dca/machines/{id}/settlements — per machine
  GET    /api/v1/dca/settlements/{id}          — single (ownership check)

Payments (leg-typed audit):
  GET    /api/v1/dca/payments?leg_type=…       — operator's payment legs

Super config (read-only here):
  GET    /api/v1/dca/super-config              — operators read the
                                                  platform fee they pay

Catch-all:
  /api/v1/dca/{...} → 503 with a precise message for not-yet-implemented
  endpoints (clients, deposits, commission splits, partial-tx,
  balance-settle, super-config write — all P2+).

All ownership checks live at the API boundary: if the route's resource
points to a machine the operator doesn't own, we 404 (not 403) so
operators can't probe for the existence of other operators' machines.

Verified routes register cleanly against LNbits 1.4 (nostr-transport).
22/22 calculation tests still green.

Refs: aiolabs/satmachineadmin#9

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:50:07 +02:00
b91e49b642 feat(v2): wire bitSpire invoice listener + settlement landing (P1a)
Replaces the no-op tasks.py stub with a real invoice listener that lands
bitSpire settlements idempotently into dca_settlements.

Architecture: satmachineadmin runs *inside* the LNbits process, so it
plugs into LNbits' canonical extension hook (register_invoice_listener
from lnbits.tasks) instead of going through the Nostr transport layer.
External clients like bitSpire use Nostr; internal extensions consume
the resulting Payment objects directly. One invoice_listener queue per
extension, dispatched by invoice_callback_dispatcher.

Flow:
  bitSpire ATM (Nostr kind-21000)
    → LNbits nostr_transport handler
    → core Payment system (create_invoice + status=SUCCESS on settle)
    → invoice_callback_dispatcher
    → satmachineadmin's invoice_queue
    → _handle_payment filters by wallet_id → active machine
    → bitspire.parse_settlement reads Payment.extra (or back-derives)
    → create_settlement_idempotent (keyed on payment_hash UNIQUE)

The parser (new bitspire.py module) is bitSpire-specific:

- Happy path (post-aiolabs/lamassu-next#44): Payment.extra carries
  {source:"bitspire", net_sats, fee_sats, fee_pct, exchange_rate,
   currency, txid, machine_npub, bills, cassettes}. Read directly,
  zero back-derivation.
- Fallback path (pre-#44): extra is absent. Back-derive the split
  using machine.fallback_commission_pct with the Lamassu-style
  formula (calculations.calculate_commission), mark
  used_fallback_split=true, log a WARNING that namechecks the
  upstream issue so it's findable in logs.

Two-stage commission split (super first, operator remainder) is
computed at land time so the audit row is complete:
  platform_fee_sats = round(commission_sats * super_fee_pct)
  operator_fee_sats = commission_sats - platform_fee_sats

The actual payout (LP DCA legs + super-fee leg + operator-split legs)
happens in a separate settlement-processor task in P2. P1 only LANDS
the settlement with status='pending'.

Smoke-tested both paths against real LNbits 1.4 (nostr-transport venv):
  happy:    266800 gross → 258835 net + 7965 commission
            (2390 super @ 30%, 5575 operator)
  fallback: 266800 gross → 254095 net + 12705 commission @ 5% default

Also adds crud.get_active_machine_by_wallet_id, the lookup that gates
inbound payments to known machine wallets.

Refs: aiolabs/satmachineadmin#9, aiolabs/lamassu-next#44

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:48:44 +02:00
cba327d0f0 fix(v2): use payment_hash as settlement idempotency key
The initial m005 made bitspire_event_id the UNIQUE idempotency key on
dca_settlements, but settlements arriving through LNbits' invoice
listener (the canonical path per nostr-transport-branch architecture)
don't carry a Nostr event id at the Payment level — that's the
underlying transport's concern, not exposed to extensions.

The natural unique key is payment_hash:
- every LN invoice has a globally unique payment_hash
- subscription replays / dispatcher double-fires dedup via UNIQUE
- it's always present on the Payment object the invoice_listener delivers

Reshape the dca_settlements column constraints:
- payment_hash: TEXT NOT NULL UNIQUE (was: NOT NULL + separate index)
- bitspire_event_id: TEXT (was: NOT NULL UNIQUE) — kept nullable for
  a future path where we subscribe to raw kind-21000 Nostr events
  directly, bypassing the Payment system

Also rename the CRUD helper: get_settlement_by_event_id →
get_settlement_by_payment_hash, and update create_settlement_idempotent
to dedup on payment_hash. CreateDcaSettlementData / DcaSettlement
adjust accordingly.

The schema is unshipped (v2-bitspire branch is local only) — fixing
m005 in-place is appropriate. The separate dca_telemetry path for
kind-30078/30079 events already uses (machine_id, beacon_received_at)
semantics, so the UNIQUE-by-Nostr-event-id pattern isn't needed there
either.

Caught during P1a design before subscribing to register_invoice_listener.

Refs: aiolabs/satmachineadmin#9, aiolabs/lamassu-next#44

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:46:08 +02:00
937749f149 feat(v2): operator-scoped CRUD + stub legacy entry points
Replaces v1's super-only single-config CRUD with the v2 operator-scoped data
layer that matches the m005 schema:

- Machines: create/get/get_by_npub/list_for_operator/update/delete
- Clients: scoped per (machine, user). Adds list_for_operator (across an
  operator's fleet) and list_for_user (LP cross-operator view), plus
  get_flow_mode_clients_for_machine for the distribution algorithm.
- Deposits: now carry machine_id and creator_user_id; per-operator listing.
- Settlements: create_settlement_idempotent treats bitspire_event_id as the
  uniqueness key, returning the existing row on replay so subscription
  re-delivery is safe by construction. mark_settlement_status drives the
  pending → processed/partial/refunded/errored lifecycle.
- Commission splits: replace_commission_splits is an atomic per-scope
  replace; the SetCommissionSplitsData model already validates legs sum
  to 1.0 at the boundary. get_effective_commission_splits handles the
  per-machine-override-or-operator-default precedence.
- Payments: leg-typed (dca / super_fee / operator_split / settlement /
  autoforward / refund) with helpers for settlement/client/operator scopes.
- Balance summary: sums confirmed deposits minus completed dca legs.
- Telemetry: upsert_beacon_snapshot uses COALESCE so today's sparse
  kind-30078 payload doesn't clobber post-#43 fields when they start
  arriving. upsert_fleet_snapshot stores raw JSON until lamassu-next#42
  fixes the kind-30079 schema.
- Super config: singleton get/update.

Also stubs three legacy entry points so __init__.py imports cleanly while
the rest of P0/P1 is in flight:

- tasks.py: no-op stubs for wait_for_paid_invoices + hourly_transaction_polling.
  Real Nostr subscription manager lands in P1.
- views_api.py: a single /api/v1/dca/{...} catch-all returns 503 with a
  precise message. v2 endpoints land in P1+.
- views.py: drops the super-only check on the index page (v2 is
  operator-installable); platform-fee config moves to a super-only API in P1.

transaction_processor.py is left untouched but is now orphaned (no one
imports it) — gets a full rewrite in P1.

Refs: plan at ~/.claude/plans/snug-gliding-shamir.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:37:48 +02:00
013e3d5f6b feat(v2): rewrite models.py for v2 schema
Replaces the Lamassu-era data models (LamassuConfig, StoredLamassuTransaction,
single-config CRUD carriers) with the v2 Pydantic surface matching m005:

- Machine / CreateMachineData / UpdateMachineData: per-operator multi-machine
  registry keyed by Nostr npub. Replaces single-row LamassuConfig + SSH fields.
- DcaClient now scoped per (machine_id, user_id). Includes autoforward fields
  for satmachineadmin#8 (best-effort LN-address forwarding for LPs).
- DcaDeposit gains machine_id + creator_user_id (audit trail finding from v1).
- DcaSettlement: idempotency carrier for bitSpire kind-21000 events. Carries
  platform_fee_sats + operator_fee_sats as absolute ints (v1 hook for the v2
  customer-discount engine — see plan).
- CommissionSplitLeg / CommissionSplit / SetCommissionSplitsData: operator's
  remainder-distribution rules. SetCommissionSplitsData validates legs sum
  to 1.0 at the boundary so crud.py only sees valid sets.
- DcaPayment dropped transaction_type in favor of leg_type discriminator
  (dca | super_fee | operator_split | settlement | autoforward | refund).
  Gains settlement_id + machine_id + operator_user_id + destination_*.
- TelemetrySnapshot: sparse beacon + fleet snapshot fields, all nullable so
  we degrade gracefully against today's minimal kind-30078 payload.
- SuperConfig / UpdateSuperConfigData: super-only platform-fee carrier.
- PartialDispenseData (satmachineadmin#3), SettleBalanceData (satmachineadmin#4):
  operator UX action carriers.

Stays on pydantic v1 @validator pattern + Optional[X] hints to match the
rest of the codebase. The UP045 / N805 lint noise is pre-existing tech debt
across the repo, not introduced here.

Refs: plan at ~/.claude/plans/snug-gliding-shamir.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:33:16 +02:00
ae4e241d1c feat(v2): add m005 satmachine_v2 schema for bitSpire + multi-tenant
Breaking redesign. Drops the v1 Lamassu-era tables (lamassu_config,
lamassu_transactions, plus the singular-config dca_clients/deposits/payments)
and creates the v2 schema:

- dca_machines: per-operator multi-machine registry, keyed by Nostr npub.
  Replaces the single-row lamassu_config pattern.
- dca_settlements: bitSpire kind-21000 idempotency. platform_fee_sats and
  operator_fee_sats stored as absolute BIGINT — v1 hook so the v2 customer-
  discount engine can record who-forgave-what without a migration.
- dca_commission_splits: operator-defined remainder rules (per-machine or
  default; sum-to-1.0 invariant enforced at write).
- dca_payments: leg-typed (dca | super_fee | operator_split | settlement |
  autoforward | refund). Drops the old transaction_type field.
- dca_clients: now scoped per (machine_id, user_id) so an LP can hold
  positions across machines/operators on the same instance.
- dca_deposits: gains machine_id + creator_user_id for audit.
- dca_telemetry: sparse kind-30078 / kind-30079 snapshots; post-#43 fields
  nullable until lamassu-next enriches the beacon.
- super_config: singleton row for super_fee_pct + super_fee_wallet_id.

No backwards compatibility — operators on the previous schema must wipe and
re-onboard. Old migrations m001-m004 remain so fresh installs still walk the
versioned path; m005 drops their tables before creating the v2 schema.

Incidental: stripped trailing whitespace in m004 (W291/W293 hygiene).

Refs: plan at ~/.claude/plans/snug-gliding-shamir.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:30:45 +02:00
28241e70c3 feat: add deposit edit and delete for pending deposits
Add PUT /api/v1/dca/deposits/{id} endpoint to update amount, currency,
and notes on pending deposits. Add DELETE endpoint to remove deposits
not yet inserted into the machine. Both endpoints reject confirmed
deposits. Frontend now shows edit/delete buttons only for pending rows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 16:00:04 +02:00
6eb076d5f6 chore: bump version to 0.0.4 2026-01-11 16:10:48 +01:00
545a0284a7 fix: cap DCA allocations when ATM cash exceeds tracked balances
When there's a sync mismatch (more cash in ATM than tracked client
balances), cap each client's allocation to their remaining fiat
balance equivalent in sats. Orphan sats stay in the source wallet.

This prevents over-allocation when deposits haven't been recorded
yet or when there's a timing mismatch between ATM transactions
and balance tracking.

- Detect sync mismatch: total_confirmed_deposits < fiat_amount
- In sync mismatch mode: allocate based on client balance, not tx amount
- Track orphan_sats that couldn't be distributed
- Normal mode unchanged: proportional distribution using calculate_distribution()

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 15:54:48 +01:00
49f3670bac fix: cast amount to float for LNbits create_invoice API
LNbits create_invoice expects amount as float, not int. Added
explicit float() cast to both DCA distribution and commission
payment invoice creation calls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 15:40:17 +01:00
397fd4b002 feat: add unit tests for DCA calculations with empirical Lamassu data
- Extract pure calculation functions to calculations.py (no lnbits deps)
- transaction_processor.py now imports from calculations.py (DRY)
- Add 22 tests covering commission, distribution, and fiat round-trip
- Include real Lamassu transaction data (8.75%, 5.5% commission rates)
- Test edge cases: discounts (90%, 100%), zero commission, small amounts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 14:14:18 +01:00
8d94dcc2b7 fix: reset correct loading state after manual transaction processing
The finally block was resetting runningTestTransaction instead of
processingSpecificTransaction, causing the button to stay in loading
state after processing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 20:57:53 +01:00
ab4e3d6b12 fix: use check_user_exists for LNbits 1.4 compatibility
LNbits 1.4 changed check_super_user to return Account (no wallets)
instead of User (with wallets). This broke the template rendering
because LNbits.map.user() requires the wallets property.

Switch to check_user_exists (returns User with wallets) and manually
check user.super_user for access control. This follows the same
pattern used by LNbits core admin pages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 12:14:48 +01:00
25be6cff87 Fix LNbits 1.4 compatibility: add null guards for g.user.wallets
LNbits 1.4 changed g.user initialization (PR #3615), moving it from
windowMixin to base.html. This means g.user can be null during initial
Vue template evaluation.

- Use optional chaining g.user?.wallets || [] in template
- Add null guard before accessing this.g.user.wallets in JS

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 11:11:19 +01:00
cd0d958c2c consolidate docs 2025-11-03 22:23:10 +01:00
1b7374fa70 Removes test transaction UI button
Removes the test transaction button from the admin UI.

The test transaction endpoint is still available in the API for development and debugging purposes.
2025-11-03 22:23:10 +01:00
fe38e08d4e Adds manual transaction processing feature
Implements functionality to manually process specific Lamassu transactions by ID, bypassing dispense checks.

This allows administrators to handle transactions that may have failed due to dispense issues or were settled manually outside of the automated process.

The feature includes a new UI dialog for entering the transaction ID and an API endpoint to fetch and process the transaction, crediting wallets and distributing funds according to the DCA configuration.
2025-11-03 22:23:08 +01:00
230beccc37 Improve balance verification in LamassuTransactionProcessor: Added rounding to two decimal places for balance and fiat amounts to ensure precision in comparisons. Enhanced logging for insufficient balance scenarios, improving clarity in transaction processing and error reporting. 2025-11-03 22:23:04 +01:00
077e097fc2 Refactor transaction data handling in LamassuTransactionProcessor: Improved consistency in processing None and empty values during data ingestion. Defaulted numeric fields to 0 and percentage fields to 0.0 for better error handling. Ensured clean extraction of transaction details, enhancing reliability in transaction processing. 2025-11-03 22:23:04 +01:00
4843b43147 FIX: exclude flow_clients remaining_balance values less than 0.01 2025-07-06 02:04:11 +02:00
5d41e0c50e Refine distribution logic in transaction processing: Updated the LamassuTransactionProcessor to only create distributions for clients with positive allocated sats. Enhanced logging to indicate when clients are skipped due to zero amounts, improving clarity and accuracy in transaction reporting. 2025-07-06 01:15:26 +02:00
bca39b91cd Enhance commission memo generation in transaction processing: Added discount handling to the commission memo in LamassuTransactionProcessor, allowing for the calculation of effective commission percentages when discounts are applied. This improves clarity in transaction details by providing a more accurate representation of commissions after discounts. 2025-07-06 00:54:19 +02:00
a864f285e4 Refactor m004_convert_to_gtq_storage migration: Streamlined the conversion of centavo amounts to GTQ by detecting the database type (PostgreSQL or SQLite) and applying appropriate data type changes and updates. This enhances clarity and ensures proper handling of data conversions across relevant tables. 2025-07-06 00:24:49 +02:00
c83ebf43ab 01 Refactor currency handling to store amounts in GTQ: Removed currency conversion utilities, updated models and API endpoints to directly handle GTQ amounts, and modified transaction processing logic for consistency. Enhanced frontend to reflect these changes, ensuring accurate display and submission of GTQ values across the application.
Refactor GTQ storage migration: Moved the conversion logic for centavo amounts to GTQ into a new migration function, m004_convert_to_gtq_storage, ensuring proper data type changes and updates across relevant tables. This enhances clarity and maintains the integrity of the migration process.
2025-07-06 00:13:03 +02:00
aa71321c84 00 Add currency conversion utilities and update models for GTQ handling: Introduced currency conversion functions for GTQ and centavos, updated API and database models to handle GTQ amounts directly, and modified API endpoints to streamline deposit and balance summary responses. Adjusted frontend to reflect changes in currency representation, ensuring consistency across the application. 2025-07-05 23:38:23 +02:00
7b40fcef21 Change order of transaction confirmation sorting: Updated the SQL query in the LamassuTransactionProcessor to sort confirmed transactions in ascending order by confirmation date, improving the retrieval of older transactions. 2025-07-05 18:31:59 +02:00
d701b7c770 Implement final balance verification in distribution process: Added checks to ensure clients have positive balances before finalizing distributions and making payments. Enhanced logging for rejected clients and balance sufficiency, improving transaction reliability and transparency. 2025-07-05 18:31:20 +02:00
f0f38f73bf Update currency handling in frontend and backend: Adjusted amount formatting to display GTQ instead of centavos in the UI. Modified data submission logic to convert GTQ to centavos for backend processing, ensuring consistency in currency representation across the application. 2025-07-05 17:35:11 +02:00
1943da1fc3 Enhance DCA distribution logic: Improved the proportional distribution algorithm to include precise calculations with banker's rounding and handle remainder allocation fairly among clients. Added verification to ensure total distributed amount matches the base allocation, enhancing accuracy and reliability in transaction processing. 2025-07-05 16:57:04 +02:00
e222922a6a Update fiat amount handling in models and transaction processor: Modified models to store fiat amounts in centavos for precision. Adjusted transaction processing logic to calculate and display fiat values in centavos, ensuring consistency across the application. Enhanced comments for clarity on the new storage format. 2025-07-05 16:57:04 +02:00
7af0e47d48 Add max_daily_limit_gtq field to lamassu_config: Updated database schema and models to include max_daily_limit_gtq for configurable client limits. Enhanced API and frontend to support this new field, ensuring proper handling and validation in the user interface. 2025-07-05 16:57:04 +02:00
ae50db10c7 Normalize transaction_time to UTC in transaction processing: Enhanced the LamassuTransactionProcessor to ensure transaction_time is consistently converted to UTC if present, improving accuracy in time handling across transactions. 2025-07-05 16:55:44 +02:00
3e4effb76f Refactor logging and transaction time normalization: Updated the get_client_balance_summary function to use loguru for improved logging clarity. Enhanced transaction processing to normalize transaction_time to UTC, ensuring consistency and accuracy in time handling across transactions. 2025-07-05 16:50:31 +02:00
5988a25983 Refine client balance summary logic: Updated the get_client_balance_summary function to filter payments based on transaction_time for improved temporal accuracy. Enhanced logging to clarify balance calculations with respect to the cutoff time, ensuring better transparency in reported balances. 2025-07-05 16:41:41 +02:00
59e4d53215 Enhance timestamp parsing in transaction processing: Improved handling of PostgreSQL timestamp formats to ensure consistency in UTC. Added error logging for invalid timestamps and implemented a fallback mechanism to use the current UTC time when parsing fails, enhancing robustness in transaction time management. 2025-07-05 16:06:00 +02:00
c5227100b8 Enhance transaction time handling: Updated the transaction processing logic to ensure all timestamps are normalized to UTC for consistency. Added logging to warn about timezone-naive timestamps and to inform about conversions from other timezones. Adjusted the client balance summary logging to include timezone information when as_of_time is used, improving clarity in balance reporting. 2025-07-05 15:49:42 +02:00
7e39bb160a Enhance client balance summary retrieval: Updated the get_client_balance_summary function to accept an optional as_of_time parameter for temporal accuracy in balance calculations. Adjusted SQL queries to filter results based on the specified time, ensuring accurate balance summaries. Added logging for cases where as_of_time is utilized. Updated transaction processing to leverage this new functionality for improved accuracy in client balance calculations. 2025-07-05 15:49:42 +02:00
8871f24cec Refactor DCA API endpoints to use superuser authentication: Updated all relevant DCA-related API endpoints to require check_super_user instead of require_admin_key, enhancing security. Adjusted client-side API calls to remove wallet admin key usage, ensuring session-based superuser authentication is utilized. Updated documentation in CLAUDE.md to reflect these changes. 2025-06-26 13:36:29 +02:00
dfc2dd695c Remove test client creation functionality from admin extension
Client registration will now be handled by the DCA client extension.
The admin extension focuses solely on:
- Reading existing clients
- Managing deposits (pending → confirmed workflow)
- Monitoring DCA activity

Test client creation code preserved in 'feature/test-client-creation' branch.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-26 12:04:55 +02:00
76807663db Update database references from 'satmachineadmin' to 'satoshimachine': Modified all relevant CRUD operations and migration scripts to reflect the new database name, ensuring consistency across the application. 2025-06-26 10:14:49 +02:00
4d3e6a4b37 Add SSH configuration handling in transaction processor: Introduced a temporary SSH config file for secure connections, including strict settings and proper key handling. Enhanced error handling for cleanup of SSH key and config files. Updated connection methods to utilize the new SSH config structure for improved security and maintainability. 2025-06-23 00:20:37 +02:00
3a2f10f949 Add transaction_time field to DCA payments: Updated the database schema to include a new transaction_time column in the dca_payments table, modified the CreateDcaPaymentData model to accept transaction_time, and adjusted the create_dca_payment function to store the original ATM transaction time. Updated transaction processing to capture this new field. 2025-06-22 16:50:27 +02:00
18323dc0c8 move to parent folder 2025-06-22 11:51:45 +02:00
466d2c74e3 Refactor DCA API endpoints to require admin key for access: Updated wallet dependency in multiple DCA-related endpoints to use require_admin_key instead of require_invoice_key, enhancing security and access control. Cleaned up code formatting for improved readability.
Update DCA API calls to use admin key: Changed references from `inkey` to `adminkey` in multiple DCA-related API requests to ensure proper access control and security compliance.
2025-06-22 11:19:18 +02:00
931ae1308f remove helper bash script 2025-06-22 10:59:49 +02:00