Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Stripeで請求書払い&銀行振込を実装する

 Stripeで請求書払い&銀行振込を実装する

#JP_Stripes https://jpstripes.connpass.com/event/252130/
PlayTechnologies, Inc.が提供するLINE予約サービス『ポチコ』に請求書払い(カードor銀行振込)をStripeで実装した話

petitviolet

July 13, 2022
Tweet

More Decks by petitviolet

Other Decks in Programming

Transcript

  1. 4USJQFͰ੥ٻॻ෷͍ۜߦৼࠐΈ
    +1@4USJQF0OMJOF7PM
    1MBZ5FDIOPMPHJFT *OD
    )JSPLJ,PNVSBTBLJ!QFUJUWJPMFU

    View Slide

  2. ࣗݾ঺հ
    w খࢵ߂و )JSPLJ,PNVSBTBLJ

    w !QFUJUWJPMFU
    w 1MBZ5FDIOPMPHJFTͰΤϯδχΞΛ΍͍ͬͯ·͢
    w IUUQTQMBZUFDIKQ
    w ʰϙνίʱΛఏڙ͍ͯ͠·͢

    View Slide

  3. ࠓ೔࿩͢͜ͱ
    w 4USJQFͰ࣮૷͢Δ੥ٻॻ෷͍ ۜߦৼࠐ

    w ʰཌ݄຤కΊ੾Γʱͷ࣮૷
    w ະ෷͍ϢʔβΛࣗಈͰղ໿ͤ͞Δ
    w కΊ੾ΓΛ͗ͨ͢ࢧ෷͍ͷফࠐ

    View Slide

  4. ϙνίʁ
    -*/&༧໿αʔϏε
    ˇ ݄ͳαϒεΫϦϓγϣϯܕϏδωε

    View Slide

  5. ϙνίͱ4USJQF
    w ༗ྉϢʔβʔͷ؅ཧ
    w 'JSFCBTF"VUIFOUJDBUJPO
    w αϒεΫϦϓγϣϯͷ؅ཧ
    w ແྉτϥΠΞϧ
    w ੥ٻ
    w Χʔυ෷͍
    w ੥ٻॻ෷͍ ΧʔυPSۜߦৼࠐ
    ˡ/&8ʂ

    View Slide

  6. 4USJQFͰ࣮૷͢Δ੥ٻॻ෷͍ ۜߦৼࠐ

    View Slide

  7. ϙνίͷར༻ྉࢧ෷͍ํ๏
    w Χʔυ෷͍͍ͨ͠Ϣʔβʔ
    w ՝ۚ։࢝࣌ʹΧʔυ৘ใΛೖྗˠ4USJQFͰ؅ཧ
    w ੥ٻॻ෷͍͍ͨ͠Ϣʔβʔ
    w ౰ॳ͸αϙʔτ͍ͯ͠ͳ͔͕ͬͨɺཁ๬ͷଟ͞ʹ·͚ͯ
    ӡ༻ͰΧόʔ͠͸͡Ίͨ
    w (PPHMF'PSNͰͦͷࢫΛૹ৴ͯ͠΋ΒͬͯɺεϓϨου
    γʔτͰ੥ٻॻ෷͍ͷϢʔβʔΛ؅ཧ
    w .˓OFZ'PSXBSEͰ੥ٻॻൃߦɾૹ෇
    w ౰વɺ৭ʑͱਏ͍
    w ೋॏ؅ཧɺ%#ͱͷঢ়ଶ੔߹ੑɺకΊ࡞ۀɺFUD

    View Slide

  8. ͕࣌ܦͪ
    Χʔυ෷͍ɾۜߦৼࠐͷͲͪΒʹ΋ରԠͨ͠੥ٻॻ
    ෷͍͕4USJQFͰՄೳʹͳͬͨʂ
    ੥ٻॻͷϢʔβʔΛ
    εϓϨουγʔτ.˓OFZ'PSXBSE
    ˣ

    View Slide

  9. 4USJQF΁ͷҠߦεςοϓ
    4USJQFͷ$VTUPNFSΛ࡞੒
    4USJQFͷ4VCTDSJQUJPOΛ࡞੒
    w DPMMFDUJPO@NFUIPEʹzTFOE@JOWPJDFzΛ༩͑Δ

    View Slide

  10. 4USJQF΁ͷҠߦεςοϓ
    4USJQFͷ$VTUPNFSΛ࡞੒
    4USJQFͷ4VCTDSJQUJPOΛ࡞੒
    w DPMMFDUJPO@NFUIPEʹzTFOE@JOWPJDFzΛ༩͑Δ

    View Slide

  11. 4USJQFͷ$VTUPNFSΛ࡞੒
    ୯ʹ$VTUPNFSΛ࡞੒͢Δ͚ͩ
    ಛච͢΂͖͜ͱ͸ͳ͍
    stripe.customers.create({


    email,


    name,


    description,


    metadata: {


    paymentType: 'invoice', // metadataに請求書払いユーザであることをマークしている


    },


    });

    View Slide

  12. 4USJQF΁ͷҠߦεςοϓ
    4USJQFͷ$VTUPNFSΛ࡞੒
    4USJQFͷ4VCTDSJQUJPOΛ࡞੒
    w DPMMFDUJPO@NFUIPEʹzTFOE@JOWPJDFzΛ༩͑Δ

    View Slide

  13. 4USJQFͷ4VCTDSJQUJPOΛ࡞੒
    4VCTDSJQUJPOΛ࡞੒͢Δ͚ͩ
    stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    default_tax_rates: defaultTaxRates,


    collection_method: 'send_invoice',


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    backdate_start_date: today.startOf('M').unix(), // 今月頭


    billing_cycle_anchor: today.startOf('M').add(1, 'M').unix(), // 月初請求


    days_until_due: 60, // 雑な"翌月末"


    trial_end: 'now',


    });
    IUUQTTUSJQFDPNEPDTBQJTVCTDSJQUJPOTDSFBUF

    View Slide

  14. 4USJQFͷ4VCTDSJQUJPOΛ࡞੒
    4VCTDSJQUJPOΛ࡞੒͢Δ͚ͩ
    stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    default_tax_rates: defaultTaxRates,


    collection_method: 'send_invoice',


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    backdate_start_date: today.startOf('M').unix(), // 今月頭


    billing_cycle_anchor: today.startOf('M').add(1, 'M').unix(), // 月初請求


    days_until_due: 60, // 雑な"翌月末"


    trial_end: 'now',


    });
    ੥ٻॻૹ෇ɾΧʔυPSۜߦৼࠐͰͷࢧ෷͍Մ
    IUUQTTUSJQFDPNEPDTBQJTVCTDSJQUJPOTDSFBUF

    View Slide

  15. 4USJQFͷ4VCTDSJQUJPOΛ࡞੒
    4VCTDSJQUJPOΛ࡞੒͢Δ͚ͩ
    stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    default_tax_rates: defaultTaxRates,


    collection_method: 'send_invoice',


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    backdate_start_date: today.startOf('M').unix(), // 今月頭


    billing_cycle_anchor: today.startOf('M').add(1, 'M').unix(), // 月初請求


    days_until_due: 60, // 雑な"翌月末"


    trial_end: 'now',


    });
    ੥ٻλΠϛϯάͷઃఆ
    IUUQTTUSJQFDPNEPDTBQJTVCTDSJQUJPOTDSFBUF

    View Slide

  16. 4USJQFͷ4VCTDSJQUJPOΛ࡞੒
    ແྉτϥΠΞϧظؒ ΞΧ΢ϯτొ࿥ޙϲ݄
    ʹ੥ٻॻ෷͍Ͱొ࿥͢Δͱ
    return stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    default_tax_rates: defaultTaxRates,


    collection_method: 'send_invoice',


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    // 無料トライアル終了後の翌月頭


    billing_cycle_anchor: account.createdAt.add(1, 'M').startOf('M').add(1, ‘M').unix(),


    // アカウント作成後1ヶ月は無料トライアル


    trial_end: account.createdAt.add(1, 'M').startOf('d').subtract(1, ’s').unix(),


    // 支払いは翌月末


    days_until_due: today.add(1, 'M').endOf('M').diff(today, 'd'),


    });

    View Slide

  17. return stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    default_tax_rates: defaultTaxRates,


    collection_method: 'send_invoice',


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    // 無料トライアル終了後の翌月頭


    billing_cycle_anchor: account.createdAt.add(1, 'M').startOf('M').add(1, ‘M').unix(),


    // アカウント作成後1ヶ月は無料トライアル


    trial_end: account.createdAt.add(1, 'M').startOf('d').subtract(1, ’s').unix(),


    // 支払いは翌月末


    days_until_due: today.add(1, 'M').endOf('M').diff(today, 'd'),


    });
    4USJQFͷ4VCTDSJQUJPOΛ࡞੒
    ແྉτϥΠΞϧظؒ ΞΧ΢ϯτొ࿥ޙϲ݄
    ʹ੥ٻॻ෷͍Ͱొ࿥͢Δͱ
    ੥ٻλΠϛϯάͷઃఆ͕ෳࡶԽ

    View Slide

  18. 4USJQFͷ4VCTDSJQUJPOΛ࡞੒
    ແྉτϥΠΞϧظؒ ΞΧ΢ϯτొ࿥ޙϲ݄
    ʹ੥ٻॻ෷͍Ͱొ࿥͢Δͱ
    ͜ͷ··ʹ͓ͯ͘͠ͱɺ࣍ͷ੥ٻॻͷࢧ෷ظݶ͕ཌ݄຤Ͱͳ͘ͳͬͯ͠·͏
    return stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    default_tax_rates: defaultTaxRates,


    collection_method: 'send_invoice',


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    // 無料トライアル終了後の翌月頭


    billing_cycle_anchor: account.createdAt.add(1, 'M').startOf('M').add(1, ‘M').unix(),


    // アカウント作成後1ヶ月は無料トライアル


    trial_end: account.createdAt.add(1, 'M').startOf('d').subtract(1, ’s').unix(),


    // 支払いは翌月末


    days_until_due: today.add(1, 'M').endOf('M').diff(today, 'd'),


    });
    ੥ٻॻൃߦ͸ແྉτϥΠΞϧऴྃ࣌
    ࢧ෷ظݶ͸ͦͷཌ݄຤

    View Slide

  19. ʰཌ݄຤కΊ੾Γʱͷ࣮૷

    View Slide

  20. 4VCTDSJQUJPOͷEBZT@VOUJM@EVF
    return stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    default_tax_rates: defaultTaxRates,


    collection_method: 'send_invoice',


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    // 無料トライアル終了後の翌月頭


    billing_cycle_anchor: account.createdAt.add(1, 'M').startOf('M').add(1, ‘M').unix(),


    // アカウント作成後1ヶ月は無料トライアル


    trial_end: account.createdAt.add(1, 'M').startOf('d').subtract(1, ’s').unix(),


    // 支払いは翌月末


    days_until_due: today.add(1, 'M').endOf('M').diff(today, 'd'),


    });
    ແྉτϥΠΞϧதͷ4VCTDSJQUJPO࡞੒
    stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    collection_method: 'send_invoice',


    default_tax_rates: defaultTaxRates,


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    backdate_start_date: today.startOf('M').unix(), // 今月頭


    billing_cycle_anchor: today.startOf('M').add(1, 'M').unix(), // 月初請求


    days_until_due: 60, // 雑な"翌月末"


    trial_end: 'now',


    });
    ௨ৗ࣌ͷ4VCTDSJQUJPO࡞੒

    View Slide

  21. 4VCTDSJQUJPOͷEBZT@VOUJM@EVF
    return stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    default_tax_rates: defaultTaxRates,


    collection_method: 'send_invoice',


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    // 無料トライアル終了後の翌月頭


    billing_cycle_anchor: account.createdAt.add(1, 'M').startOf('M').add(1, ‘M').unix(),


    // アカウント作成後1ヶ月は無料トライアル


    trial_end: account.createdAt.add(1, 'M').startOf('d').subtract(1, ’s').unix(),


    // 支払いは翌月末


    days_until_due: today.add(1, 'M').endOf('M').diff(today, 'd'),


    });
    ແྉτϥΠΞϧதͷ4VCTDSJQUJPO࡞੒
    stripe.subscriptions.create({


    customer: customerId,


    items: [{ price: priceId }],


    collection_method: 'send_invoice',


    default_tax_rates: defaultTaxRates,


    payment_settings: { payment_method_types: ['card', 'customer_balance'] },


    backdate_start_date: today.startOf('M').unix(), // 今月頭


    billing_cycle_anchor: today.startOf('M').add(1, 'M').unix(), // 月初請求


    days_until_due: 60, // 雑な"翌月末"


    trial_end: 'now',


    });
    ௨ৗ࣌ͷ4VCTDSJQUJPO࡞੒
    ੥ٻॻͷࢧ෷ظݶΛଗ͍͑ͨ

    View Slide

  22. 8FCIPPLΛ࢖͏
    4USJQF͸Πϕϯτ͝ͱʹ8FCIPPLΛඈ͹ͯ͘͠ΕΔ
    IUUQTTUSJQFDPNEPDTXFCIPPLT

    View Slide

  23. 8FCIPPLΛ࢖͏
    4USJQF͸Πϕϯτ͝ͱʹ8FCIPPLΛඈ͹ͯ͘͠ΕΔ
    ࠓճ࢖ͬͨͷ͸zDVTUPNFSTVCTDSJQUJPOVQEBUFEz
    ແྉτϥΠΞϧऴྃ࣌ʹൃՐ͢Δ
    IUUQTTUSJQFDPNEPDTBQJFWFOUTUZQFTFWFOU@UZQFTDVTUPNFSTVCTDSJQUJPOVQEBUFE

    View Slide

  24. 8FCIPPLΛ࢖͏
    8FCIPPLͷઃఆͰDVTUPNFSTVCTDSJQUJPOVQEBUFEΛ
    ड͚औΔΑ͏ʹ໌͓ࣔͯ͘͜͠ͱ

    View Slide

  25. 8FCIPPLΛ࢖͏
    lDVTUPNFSTVCTDSJQUJPOVQEBUFEzΛड͚औͬͯ
    TVCTDSJQUJPOEBZT@VOUJM@EVFΛઃఆ͠௚͢
    if (event.type === 'customer.subscription.updated') {


    const previousAttributes = event.data.previous_attributes;


    const trialEnded = 'status' in previousAttributes &&


    previousAttributes.status === 'trialing';


    if (trialEnded) {


    // 請求書払いなsubscriptionのtrialが終わったら、


    // daysUntilDueを更新して請求書を月末発行・翌月末期限に調整する


    await updateSubscription(event.data.object.id, {


    days_until_due: 60,


    });


    }


    }

    View Slide

  26. ະ෷͍ϢʔβΛࣗಈͰղ໿ͤ͞Δ

    View Slide

  27. ࢧ෷Θͳ͍Ϣʔβʔ͸ࣗಈͰղ໿͍ͤͨ͞
    ੥ٻॻ෷͍ ۜߦৼࠐ
    ͩͱࢧ෷͍͕஗Ε͕ͪ
    ˣ
    ஗ΕͨϢʔβʔ͸ࣗಈͰղ໿͍ͤͨ͞
    Ͱ΋ଈղ໿͸ݫ͗͢͠ΔͷͰ༛༧Λ͍࣋ͨͤͨ

    View Slide

  28. ࢧ෷Θͳ͍Ϣʔβʔ͸ࣗಈͰղ໿͍ͤͨ͞
    ੥ٻॻ෷͍ ۜߦৼࠐ
    ͩͱࢧ෷͍͕஗Ε͕ͪ
    ˣ
    ஗ΕͨϢʔβʔ͸ࣗಈͰղ໿͍ͤͨ͞
    Ͱ΋ଈղ໿͸ݫ͗͢͠ΔͷͰ༛༧Λ͍࣋ͨͤͨ
    4USJQFͳΒ؆୯ʹग़དྷΔΑʂ

    View Slide

  29. ࢧ෷Θͳ͍Ϣʔβʔ͸ࣗಈͰղ໿͍ͤͨ͞

    View Slide

  30. ࢧ෷Θͳ͍Ϣʔβʔ͸ࣗಈͰղ໿͍ͤͨ͞

    View Slide

  31. ࢧ෷Θͳ͍Ϣʔβʔ͸ࣗಈͰղ໿͍ͤͨ͞
    ཌ݄຤͕ࢧ෷ظݶ
    ཌʑ݄຤ʹࣗಈղ໿

    View Slide

  32. కΊ੾ΓΛ͗ͨ͢ࢧ෷͍ͷফࠐ

    View Slide

  33. కΊ੾ΓΛ͗ͨ͢ࢧ෷͍ͷফࠐ
    కΊ੾ΓˠਅͷకΊ੾Γ ࣗಈղ໿
    ·Ͱ༛༧͕͋Δ
    ͜ͷؒʹࢧ෷͍͕͋Δͱফࠐ͞Εͣʹʰ࢒ߴʱʹ
    ೖͬͯ͠·͏

    View Slide

  34. కΊ੾ΓΛ͗ͨ͢ࢧ෷͍ͷফࠐ
    ݱۚ࢒ߴ͕͋Δͷʹ੥ٻॻ͕ະ෷͍Ͱͦͷ··ղ໿
    ͞Εͯ͠·͏ͱ͍͏࠷ѱͷ݁Ռʹ
    ͦͯۜ͠ߦৼࠐ͸4USJQFʹ൓ө͞ΕΔ·Ͱϥά͕͋Δʜ

    View Slide

  35. కΊ੾ΓΛ͗ͨ͢ࢧ෷͍ͷফࠐ
    खಈͰফࠐ͢Δ࣮૷͕ඞཁ
    IUUQTTUSJQFDPNEPDTQBZNFOUTDVTUPNFSCBMBODFSFDPODJMJBUJPODBTINBOVBMSFDPODJMJBUJPO
    await stripe.customers.update(customer.id, {


    cash_balance: {


    settings: {


    reconciliation_mode: 'manual',


    },


    },


    });


    await stripe.paymentIntents.applyCustomerBalance(


    invoice.payment_intent as string


    );


    await stripe.customers.update(customer.id, {


    cash_balance: {


    settings: {


    reconciliation_mode: 'automatic',


    },


    },


    });

    View Slide

  36. కΊ੾ΓΛ͗ͨ͢ࢧ෷͍ͷফࠐ
    खಈͰফࠐ͢Δ࣮૷͕ඞཁ
    IUUQTTUSJQFDPNEPDTQBZNFOUTDVTUPNFSCBMBODFSFDPODJMJBUJPODBTINBOVBMSFDPODJMJBUJPO
    await stripe.customers.update(customer.id, {


    cash_balance: {


    settings: {


    reconciliation_mode: 'manual',


    },


    },


    });


    await stripe.paymentIntents.applyCustomerBalance(


    invoice.payment_intent as string


    );


    await stripe.customers.update(customer.id, {


    cash_balance: {


    settings: {


    reconciliation_mode: 'automatic',


    },


    },


    });
    ফࠐϞʔυΛखಈʹมߋ

    View Slide

  37. కΊ੾ΓΛ͗ͨ͢ࢧ෷͍ͷফࠐ
    खಈͰফࠐ͢Δ࣮૷͕ඞཁ
    IUUQTTUSJQFDPNEPDTQBZNFOUTDVTUPNFSCBMBODFSFDPODJMJBUJPODBTINBOVBMSFDPODJMJBUJPO
    await stripe.customers.update(customer.id, {


    cash_balance: {


    settings: {


    reconciliation_mode: 'manual',


    },


    },


    });


    await stripe.paymentIntents.applyCustomerBalance(


    invoice.payment_intent as string


    );


    await stripe.customers.update(customer.id, {


    cash_balance: {


    settings: {


    reconciliation_mode: 'automatic',


    },


    },


    });
    ফࠐ͢Δ

    View Slide

  38. కΊ੾ΓΛ͗ͨ͢ࢧ෷͍ͷফࠐ
    खಈͰফࠐ͢Δ࣮૷͕ඞཁ
    IUUQTTUSJQFDPNEPDTQBZNFOUTDVTUPNFSCBMBODFSFDPODJMJBUJPODBTINBOVBMSFDPODJMJBUJPO
    await stripe.customers.update(customer.id, {


    cash_balance: {


    settings: {


    reconciliation_mode: 'manual',


    },


    },


    });


    await stripe.paymentIntents.applyCustomerBalance(


    invoice.payment_intent as string


    );


    await stripe.customers.update(customer.id, {


    cash_balance: {


    settings: {


    reconciliation_mode: 'automatic',


    },


    },


    });
    ফࠐϞʔυΛࣗಈʹ໭͢

    View Slide

  39. ࠓ೔࿩ͨ͜͠ͱ
    w 4USJQFͰ࣮૷͢Δ੥ٻॻ෷͍ ۜߦৼࠐ

    w ʰཌ݄຤కΊ੾Γʱͷ࣮૷
    w ະ෷͍ϢʔβΛࣗಈͰղ໿ͤ͞Δ
    w కΊ੾ΓΛ͗ͨ͢ࢧ෷͍ͷফࠐ
    ڵຯ͕͋Ε͹IUUQTQPDIJDPBQQ࢖ͬͯΈͯͶʂ

    View Slide