首頁 > web前端 > js教程 > 使用 Stripe Connect 創建市場:上線流程

使用 Stripe Connect 創建市場:上線流程

Susan Sarandon
發布: 2024-11-28 09:55:13
原創
366 人瀏覽過

介紹

考慮到沒有太多支付處理商提供它,創建一個市場可能太難了,或者是不可能的,如果他們不提供它,那麼你很可能會在他們聽到風聲的那一刻就被踢出平台,即使沒有如果您沒有堅實的基礎來處理使用該平台的賣家的付款、退款和付款,那麼創建市場是有風險的。

Stripe Connect 解決了這些問題,它將使我們能夠創建一個基本的市場,您可以在其中註冊成為賣家,並且客戶可以輕鬆地從這些賣家那裡購買商品。作為平台所有者,您還可以設定服務費,因此當用戶 X 從商店 Y 購買商品時,我們將獲得該交易的 X% 分成,但稍後會詳細介紹。

Creating a marketplace with Stripe Connect: The onboard process

設定項目

為了處理資料庫連接,我們使用 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 帳戶,但尚未加入,那麼我們也會將他們重定向到加入連結。

Creating a marketplace with Stripe Connect: The onboard process

從那裡賣家將輸入他的電子郵件/電話號碼,然後入職流程將開始,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 的事件,但讓我們看看加入是否有效。

一旦你到達最後一步,它可能會說你的帳戶詳細資料不完整,最後一步是身份驗證,因為這是測試模式,我們可以模擬

Creating a marketplace with Stripe Connect: The onboard process

好的,一旦我們完成了,我們將返回到上一頁,我們可以按提交,按提交,我們將進入控制台

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,這意味著我們已成功入門,我們可以開始建立產品。

Creating a marketplace with Stripe Connect: The onboard process

好吧,讓我們先讓賣家儀表板按鈕發揮作用,然後再繼續討論產品,創建一條位於 /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 帳戶門戶,用戶可以在那裡看到他的分析、付款等...

Creating a marketplace with Stripe Connect: The onboard process

這標誌著我們使用 Stripe Connect 創建市場的第一部分的結束,第二部分將處理產品、付款和支出,第三部分將是最終部分,我們將處理專案面向客戶的方面.

您可以在https://github.com/ddm50/stripe-connect-howto-seller查看該專案的原始碼

以上是使用 Stripe Connect 創建市場:上線流程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板