Conversation
|
As this PR is large enough as it is i will add integration to the event system in the branch |
|
More merge conflicts... 😩 |
There was a problem hiding this comment.
Pull request overview
This PR implements a comprehensive ledger (money/accounting) system for the application, introducing double-entry bookkeeping, Stripe payment integration, and ledger accounts for users and groups. The implementation builds on top of PR #443 which simplified service method interfaces.
Changes:
- Added complete ledger schema with accounts, transactions, entries, and payment models supporting both Stripe and manual payments
- Implemented double-entry accounting logic with automatic fee calculations and balance tracking
- Integrated Stripe for payment processing, including webhook handling and saved payment method management
- Created UI components for account management, deposits, payouts, and transaction history
- Added test infrastructure with utilities for testing ledger operations
Reviewed changes
Copilot reviewed 101 out of 103 changed files in this pull request and generated 22 comments.
Show a summary per file
| File | Description |
|---|---|
| src/prisma/schema/ledger.prisma | Core ledger database schema defining accounts, transactions, entries, and payments |
| src/prisma/schema/user.prisma | Added ledger account and Stripe customer relations to users |
| src/prisma/schema/group.prisma | Added ledger account relation to groups |
| src/services/ledger/accounts/operations.ts | Ledger account CRUD operations and balance calculations |
| src/services/ledger/transactions/operations.ts | Transaction creation, state management, and advancement logic |
| src/services/ledger/transactions/calculateFees.ts | Fee calculation formulas for debit and credit entries |
| src/services/ledger/transactions/determineTransactionState.ts | State machine for transaction lifecycle management |
| src/services/ledger/payments/operations.ts | Payment creation and initiation for Stripe and manual payments |
| src/services/ledger/payments/stripeWebhookCallback.ts | Webhook handler for Stripe payment events |
| src/services/ledger/movements/operations.ts | High-level deposit and payout orchestration |
| src/services/stripeCustomers/operations.ts | Stripe customer management and saved payment methods |
| src/lib/currency/convert.ts | Currency conversion utilities replacing old money module |
| src/app/api/stripe-events/route.ts | API route for receiving Stripe webhooks |
| src/app/_components/Ledger/* | UI components for ledger account and transaction management |
| src/app/_components/Stripe/* | Stripe integration components for payments |
| tests/services/ledger/* | Test files for ledger functionality |
| tests/utils.ts | Test utility for handling promise settlement |
| package.json | Added Stripe SDK dependencies |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 101 out of 103 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| type Props = { | ||
| ref?: React.Ref<StripePaymentRef>, | ||
| } | ||
|
|
||
| export default function StripePayment({ ref }: Props) { | ||
| const stripe = useStripe() | ||
| const elements = useElements() | ||
|
|
||
| useImperativeHandle(ref, () => ({ |
|
|
||
| stripe: | ||
| image: stripe/stripe-cli:v1.37.3 | ||
| command: listen --forward-to http://nginx:80/api/stripe-events --skip-verify |
| STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY} | ||
| NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: ${NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY} | ||
| STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET} | ||
| MAIL_DOMAIN: ${MAIL_DOMAIN} |
| stripe.paymentIntents.cancel( | ||
| paymentIntent.id, | ||
| {}, | ||
| { idempotencyKey: `project-next-payment-id-${paymentIntent.id}` }, | ||
| ) | ||
| } |
| operation: async ({ prisma, data }): Promise<LedgerAccount> => { | ||
| const type = data.type ?? data.userId !== undefined ? 'USER' : 'GROUP' | ||
|
|
| // Avoid loading the Stripe components until they are needed | ||
| const StripePayment = lazy(() => import('@/components/Stripe/StripePayment')) | ||
| const StripeProvider = lazy(() => import('@/components/Stripe/StripeProvider')) | ||
|
|
||
| const defaultPaymentProvider: PaymentProvider = 'STRIPE' | ||
| const paymentProviderNames: Record<PaymentProvider, string> = { | ||
| STRIPE: 'Stripe', | ||
| MANUAL: 'Manuell Betaling', | ||
| } |
| switch (type) { | ||
| case 'card': | ||
| return <> | ||
| <span>{card?.brand.toUpperCase()}</span> |
| <FontAwesomeIcon icon={faXmark}/> | ||
| </button> | ||
| </li> | ||
| )) : <p><em>Du har ingen lagrede betalingskort.</em></p>} |
| const event = stripe.webhooks.constructEvent(body, stripeSignature, process.env.STRIPE_WEBHOOK_SECRET) | ||
|
|
| describe.skip('payments', () => { | ||
| beforeAll(async () => { | ||
| await prisma.ledgerAccount.createMany({ |
After more than of year of waiting the ledger (money) system is finally here!* 💵 💸 💰
This includes:
✅ A flexible double entry ledger system for tracking transaction (deposits, payouts, purchases, etc.)
✅ Simple logic to calculate balances (goodbye ginormous sql query)
✅ Uniform ledger account interface between groups and users (no more source and drain accounts)
✅ Payments with Stripe (integrated with webhooks like before)
✅ Card detail saving with Stripe (makes use of new-ish CustomerSessions API for simpler integration)**
This PR is marked as draft until #443 is merged as it builts on top of it. I also have to tie up a few loose ends regarding permissions, although I think it might be best to do that in another PR.I have not tested this fully yet so a few changes might still come.