使用 Stripe Connect 創建市場:上線流程
介紹
考慮到沒有太多支付處理商提供它,創建一個市場可能太難了,或者是不可能的,如果他們不提供它,那麼你很可能會在他們聽到風聲的那一刻就被踢出平台,即使沒有如果您沒有堅實的基礎來處理使用該平台的賣家的付款、退款和付款,那麼創建市場是有風險的。
Stripe Connect 解決了這些問題,它將使我們能夠創建一個基本的市場,您可以在其中註冊成為賣家,並且客戶可以輕鬆地從這些賣家那裡購買商品。作為平台所有者,您還可以設定服務費,因此當用戶 X 從商店 Y 購買商品時,我們將獲得該交易的 X% 分成,但稍後會詳細介紹。
設定項目
為了處理資料庫連接,我們使用 Prisma,身份驗證由 remix-auth 處理,對於這部分,我們只處理市場的賣家端。
// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model Store { id String @id // This will be the store's subdomain name String updated_at DateTime @default(now()) @updatedAt seller Seller? } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique }
這就是我們的schema.prisma 檔案的樣子,我們有一個賣家模型和一個與之相關的商店模型,「id」欄位將用作子網域,因此當我們到達買家一側時,我將能夠訪問store.localhost.com 並從那裡的賣家購買產品。
我們還將新增一個 Stripe 模型,它將儲存有關賣家 Connect 帳戶的資料。
model Stripe { account_id String @id is_onboarded Boolean @default(false) user Users @relation(fields: [user_id], references: [discord_id]) user_id String @unique created_at DateTime @default(now()) updated_at DateTime @updatedAt } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique stripe Stripe? }
現在我們可以處理使用者入門問題了,所以讓我們在 .env 檔案中定義另一個變數。
STRIPE_SK=your stripe secret key here
您可以透過在 Stripe 的開發頁面中產生 Stripe 金鑰來取得它,最好建立目前僅允許使用 Stripe Connect 的受限金鑰。
然後您需要建立一個新檔案來匯出 Stripe 用戶端,以便我們的路由可以使用它
// app/libs/stripe.server.ts import Stripe from 'stripe'; export const stripe = new Stripe(process.env.STRIPE_SK)
我們將建立一條位於「/onboarding」的新路線
// app/routes/onboarding.tsx export default function Onboarding() { const {stripe} = useLoaderData(); return <div className={'text-center pt-[6%]'}> <h1 className={'text-xl'}>Account onboarded: {stripe?.is_onboarded ? stripe?.account_id : '? Not connected'}</h1> <div className={'flex items-center text-white text-sm mt-5 justify-center gap-3'}> {!stripe ? <> <Form method={'post'}> <button type={'submit'} className={'bg-blue-600 hover:cursor-pointer rounded-[6px] px-4 py-1.5'}>Setup your seller account </button> </Form> </> : <> <div className={'bg-blue-600 rounded-[6px] px-4 py-1.5'}>Seller dashboard</div> </>} </div> </div> }
我們將新增一個載入器函數,該函數將傳遞有關賣家入職狀態的資料
export async function loader({request}: LoaderFunctionArgs) { const user = await authenticator.isAuthenticated(request, { failureRedirect: '/login' }) const seller = await prisma.seller.findFirst({ where: { id: user.id }, include: { stripe: true } }) return { stripe: seller?.stripe } }
現在,如果您轉到/onboarding,它會說您尚未連接,您將能夠按下按鈕進行註冊,這就是我們的操作功能的用武之地
export async function action({request}: ActionFunctionArgs) { const authenticated = await authenticator.isAuthenticated(request, { failureRedirect: '/login' }) const seller = await prisma.seller.findFirst({ where: { id: authenticated.id }, include: { stripe: true } }) if (seller && seller.stripe?.is_onboarded) { return json({ message: 'User is onboarded already', error: true }, { status: 400 }) } const account = seller?.stripe?.account_id ? { id: seller.stripe?.account_id } : await stripe.accounts.create({ email: seller?.email, controller: { fees: { payer: 'application', }, losses: { payments: 'application', }, stripe_dashboard: { type: 'express', }, }, }); if (!seller?.stripe?.account_id) { await prisma.seller.update({ where: { id: authenticated.id }, data: { stripe: { create: { account_id: account.id } } }, include: { stripe: true } }) } const accountLink = await stripe.accountLinks.create({ account: account.id, refresh_url: 'http://localhost:5173/onboarding', return_url: 'http://localhost:5173/onboarding', type: 'account_onboarding', collection_options: { fields: 'eventually_due', }, }); console.debug(`[ACCOUNT ID = ${account.id}] CREATED ACCOUNT ONBOARDING LINK, REDIRECTING...`) return redirect(accountLink.url) }
當賣家按下按鈕時,我們將使用他們註冊時使用的電子郵件創建一個帳戶,然後我們將創建一個帳戶鏈接,將他們重定向到入職頁面(如果賣家已經附加了Stripe 帳戶,但尚未加入,那麼我們也會將他們重定向到加入連結。
從那裡賣家將輸入他的電子郵件/電話號碼,然後入職流程將開始,Stripe 通常會詢問賣家企業位置、企業詳細資料、銀行帳戶等...
現在我們可以監聽 Stripe Connect 事件的 webhook,因此當賣家成功加入後,我們會將這些屬性加入資料庫中的賣家記錄。
為了進行測試,您可以簡單地下載 Stripe CLI,然後您可以將任何事件轉發到我們現在將創建的新路由 /api/notifications
// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model Store { id String @id // This will be the store's subdomain name String updated_at DateTime @default(now()) @updatedAt seller Seller? } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique }
當您執行該命令時,您將獲得一個Webhook 簽名,以便我們可以驗證Stripe 發送給我們的每個Webhook 的完整性,同樣,如果您在Stripe 上的開發人員門戶上創建一個Webhook,您將擁有一個秘密.
model Stripe { account_id String @id is_onboarded Boolean @default(false) user Users @relation(fields: [user_id], references: [discord_id]) user_id String @unique created_at DateTime @default(now()) updated_at DateTime @updatedAt } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique stripe Stripe? }
我們也會在 .env 檔案中加入一個新變數
STRIPE_SK=your stripe secret key here
現在我們可以編寫程式碼來處理 Stripe 發送給我們的這些事件
// app/libs/stripe.server.ts import Stripe from 'stripe'; export const stripe = new Stripe(process.env.STRIPE_SK)
我們驗證是否是 Stripe 發送了請求,如果是,那麼我們繼續,現在我們要關注的事件是 account.updated,該事件與我們在重定向賣家之前創建的帳戶相關。
當賣家開始入職流程、新增電話號碼、輸入電子郵件或最終完成入職流程時,我們將收到「account.updated」事件,並且會發送此陣列
account.requirements.currently_due
當「currently_due」數組的長度為零時,我們知道用戶已完全註冊,能夠接受付款,因此從我們這邊我們可以更新資料庫並允許用戶創建產品,但在此之前讓我們添加'/api /notifications' 操作中的邏輯
// app/routes/onboarding.tsx export default function Onboarding() { const {stripe} = useLoaderData(); return <div className={'text-center pt-[6%]'}> <h1 className={'text-xl'}>Account onboarded: {stripe?.is_onboarded ? stripe?.account_id : '? Not connected'}</h1> <div className={'flex items-center text-white text-sm mt-5 justify-center gap-3'}> {!stripe ? <> <Form method={'post'}> <button type={'submit'} className={'bg-blue-600 hover:cursor-pointer rounded-[6px] px-4 py-1.5'}>Setup your seller account </button> </Form> </> : <> <div className={'bg-blue-600 rounded-[6px] px-4 py-1.5'}>Seller dashboard</div> </>} </div> </div> }
一旦到位,我們就可以嘗試加入並看看它是否有效。例如,一旦您輸入位址,您就會在專案的控制台中看到一則訊息,例如
export async function loader({request}: LoaderFunctionArgs) { const user = await authenticator.isAuthenticated(request, { failureRedirect: '/login' }) const seller = await prisma.seller.findFirst({ where: { id: user.id }, include: { stripe: true } }) return { stripe: seller?.stripe } }
這表示主體已經過驗證,並且我們已成功接收來自 Stripe 的事件,但讓我們看看加入是否有效。
一旦你到達最後一步,它可能會說你的帳戶詳細資料不完整,最後一步是身份驗證,因為這是測試模式,我們可以模擬
好的,一旦我們完成了,我們將返回到上一頁,我們可以按提交,按提交,我們將進入控制台
export async function action({request}: ActionFunctionArgs) { const authenticated = await authenticator.isAuthenticated(request, { failureRedirect: '/login' }) const seller = await prisma.seller.findFirst({ where: { id: authenticated.id }, include: { stripe: true } }) if (seller && seller.stripe?.is_onboarded) { return json({ message: 'User is onboarded already', error: true }, { status: 400 }) } const account = seller?.stripe?.account_id ? { id: seller.stripe?.account_id } : await stripe.accounts.create({ email: seller?.email, controller: { fees: { payer: 'application', }, losses: { payments: 'application', }, stripe_dashboard: { type: 'express', }, }, }); if (!seller?.stripe?.account_id) { await prisma.seller.update({ where: { id: authenticated.id }, data: { stripe: { create: { account_id: account.id } } }, include: { stripe: true } }) } const accountLink = await stripe.accountLinks.create({ account: account.id, refresh_url: 'http://localhost:5173/onboarding', return_url: 'http://localhost:5173/onboarding', type: 'account_onboarding', collection_options: { fields: 'eventually_due', }, }); console.debug(`[ACCOUNT ID = ${account.id}] CREATED ACCOUNT ONBOARDING LINK, REDIRECTING...`) return redirect(accountLink.url) }
成功了,現在 Stripe 將使我們回到入門頁面,它會向我們顯示我們的帳戶 ID,這意味著我們已成功入門,我們可以開始建立產品。
好吧,讓我們先讓賣家儀表板按鈕發揮作用,然後再繼續討論產品,創建一條位於 /portal 的新路線
// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model Store { id String @id // This will be the store's subdomain name String updated_at DateTime @default(now()) @updatedAt seller Seller? } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique }
非常基本的功能,因此現在當您登入 /portal 時,您將被重定向到我們為 Stripe 帳戶產生的一次性連結。
在入職路線中,我們將使用連結包裹賣家儀表板 div。
model Stripe { account_id String @id is_onboarded Boolean @default(false) user Users @relation(fields: [user_id], references: [discord_id]) user_id String @unique created_at DateTime @default(now()) updated_at DateTime @updatedAt } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique stripe Stripe? }
當我們訪問 /portal 或按下按鈕時,我們將被重定向到 Stripe 的 Connect 帳戶門戶,用戶可以在那裡看到他的分析、付款等...
這標誌著我們使用 Stripe Connect 創建市場的第一部分的結束,第二部分將處理產品、付款和支出,第三部分將是最終部分,我們將處理專案面向客戶的方面.
您可以在https://github.com/ddm50/stripe-connect-howto-seller查看該專案的原始碼
以上是使用 Stripe Connect 創建市場:上線流程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務
