Add WisePOS E in-person card payments (Stripe Terminal)
Server-driven Stripe Terminal integration for taking in-person card payments against an invoice, running on the same Stripe Connect connected account used for online payments. No native app or Terminal SDK — the WisePOS E is driven from the web backend via Stripe's REST API. - Domain: TerminalReader entity + status enum, PaymentMethod.CardReader, Company.StripeTerminalLocationId / TerminalSurchargeEnabled, DbSet + tenant filter + indexes, IUnitOfWork repo, migration AddTerminalReaders (additive). - StripeConnectService: location/reader registration, list, delete, process payment on reader, status poll, cancel, and a test-mode simulated tap. All routed to the connected account like the existing online-payment methods. - TerminalController: admin reader management + per-invoice ProcessPayment, PaymentStatus (poll), CancelPayment, SimulateTap (test mode only). Stores the PaymentIntent id on the invoice; the webhook remains the authoritative writer. - PaymentController webhook: HandlePaymentSucceededAsync records source=terminal payments as CardReader (online path unchanged — no source key means no change); new terminal.reader.action_failed handler for declines/timeouts (notification only, no ledger mutation). Refund path reused unchanged. - UI: Card Readers settings tab (register/list/deactivate + in-person surcharge toggle, default off with a compliance warning) and an invoice "Take Card Payment" modal with live status polling. External JS per project convention. - Feature bundled with the existing online-payments entitlement (no new plan flag); additionally requires StripeConnectStatus == Active. - Help: HelpKnowledgeBase + Invoices help article updated. - Tests: TerminalController validation + surcharge-routing tests (241 pass). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,18 @@ public enum PaymentMethod
|
||||
CreditDebitCard = 2,
|
||||
BankTransferACH = 3,
|
||||
DigitalPayment = 4,
|
||||
StoreCredit = 5 // Refund issued as store credit (creates a CreditMemo)
|
||||
StoreCredit = 5, // Refund issued as store credit (creates a CreditMemo)
|
||||
CardReader = 6 // In-person card payment via a Stripe Terminal reader (WisePOS E)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Local lifecycle state for a registered Stripe Terminal card reader. Distinct from Stripe's
|
||||
/// network status (online/offline) — this tracks whether the shop still uses the reader.
|
||||
/// </summary>
|
||||
public enum TerminalReaderStatus
|
||||
{
|
||||
Active = 0,
|
||||
Deactivated = 1 // Unregistered from Stripe and hidden from the shop's reader list
|
||||
}
|
||||
|
||||
public enum GiftCertificateStatus
|
||||
|
||||
Reference in New Issue
Block a user