Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit578f5d4

Browse files
feat: Added support for invoice payment object (#245)
1 parent16ba283 commit578f5d4

File tree

8 files changed

+167
-2
lines changed

8 files changed

+167
-2
lines changed

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ To deploy the sync-engine to a Supabase Edge Function, follow this [guide](./doc
106106
- [x]`invoice.overpaid` 🟢
107107
- [x]`invoice.will_be_due` 🟢
108108
- [x]`invoice.voided` 🟢
109+
- [x]`invoice_payment.paid` 🟢
109110
- [ ]`issuing_authorization.request`
110111
- [ ]`issuing_card.created`
111112
- [ ]`issuing_cardholder.created`

‎docs/index.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ This project synchronizes your Stripe account to a PostgreSQL database. It can b
7171
-[x]`invoice.overpaid` 🟢
7272
-[x]`invoice.will_be_due` 🟢
7373
-[x]`invoice.voided` 🟢
74+
-[x]`invoice_payment.paid` 🟢
7475
-[ ]`issuing_authorization.request`
7576
-[ ]`issuing_card.created`
7677
-[ ]`issuing_cardholder.created`

‎packages/fastify-app/src/test/helpers/mockStripe.ts‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,30 @@ export const mockStripe = {
277277
},
278278
})),
279279
},
280+
invoicePayments:{
281+
retrieve:vitest.fn((id)=>
282+
Promise.resolve({
283+
id:id,
284+
object:'invoice_payment',
285+
amount_paid:2000,
286+
amount_requested:2000,
287+
created:1391288554,
288+
currency:'usd',
289+
invoice:'in_103Q0w2eZvKYlo2C5PYwf6Wf',
290+
is_default:true,
291+
livemode:false,
292+
payment:{
293+
type:'payment_intent',
294+
payment_intent:'pi_103Q0w2eZvKYlo2C364X582Z',
295+
},
296+
status:'paid',
297+
status_transitions:{
298+
canceled_at:null,
299+
paid_at:1391288554,
300+
},
301+
})
302+
),
303+
},
280304
subscriptions:{
281305
retrieve:vitest.fn((id)=>
282306
Promise.resolve({
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"id":"evt_test_invoice_payment_paid",
3+
"object":"event",
4+
"api_version":"2023-10-16",
5+
"created":1642649111,
6+
"data": {
7+
"object": {
8+
"id":"inpay_1M3USa2eZvKYlo2CBjuwbq0N",
9+
"object":"invoice_payment",
10+
"amount_paid":2000,
11+
"amount_requested":2000,
12+
"created":1391288554,
13+
"currency":"usd",
14+
"invoice":"in_103Q0w2eZvKYlo2C5PYwf6Wf",
15+
"is_default":true,
16+
"livemode":false,
17+
"payment": {
18+
"type":"payment_intent",
19+
"payment_intent":"pi_103Q0w2eZvKYlo2C364X582Z"
20+
},
21+
"status":"paid",
22+
"status_transitions": {
23+
"canceled_at":null,
24+
"paid_at":1391288554
25+
}
26+
}
27+
},
28+
"livemode":false,
29+
"pending_webhooks":1,
30+
"request": {
31+
"id":null,
32+
"idempotency_key":null
33+
},
34+
"type":"invoice_payment.paid"
35+
}

‎packages/fastify-app/src/test/webhooks.test.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ describe('POST /webhooks', () => {
125125
'refund_failed.json',
126126
'refund_updated.json',
127127
'checkout_session_completed.json',
128+
'invoice_payment_paid.json',
128129
])('event %s is upserted',async(jsonFile)=>{
129130
consteventBody=awaitimport(`./stripe/${jsonFile}`).then(({default:myData})=>myData)
130131
// Update the event body created timestamp to be the current time
@@ -147,7 +148,7 @@ describe('POST /webhooks', () => {
147148
})
148149

149150
if(response.statusCode!=200){
150-
logger.error('error: ',response.body)
151+
logger.error({responseBody:response.body},'error')
151152
}
152153
expect(response.statusCode).toBe(200)
153154

@@ -192,7 +193,7 @@ describe('POST /webhooks', () => {
192193
})
193194

194195
if(response.statusCode!=200){
195-
logger.error('error: ',response.body)
196+
logger.error({responseBody:response.body},'error')
196197
}
197198
expect(response.statusCode).toBe(200)
198199
expect(JSON.parse(response.body)).toMatchObject({received:true})
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
create table
2+
if not exists"stripe"."invoice_payments" (
3+
"id"textprimary key,
4+
objecttext,
5+
amount_paidbigint,
6+
amount_requestedbigint,
7+
createdinteger,
8+
currencytext,
9+
invoicetext,
10+
is_defaultboolean,
11+
livemodeboolean,
12+
payment jsonb,
13+
statustext,
14+
status_transitions jsonb,
15+
last_synced_attimestamptz,
16+
updated_attimestamptz default timezone('utc'::text, now())not null
17+
);
18+
19+
createindexstripe_invoice_payments_invoice_idxon"stripe"."invoice_payments" using btree (invoice);
20+
21+
createtriggerhandle_updated_at
22+
beforeupdate
23+
onstripe.invoice_payments
24+
for each row
25+
execute procedure set_updated_at();
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import{EntitySchema}from'./types'
2+
3+
exportconstinvoicePaymentSchema:EntitySchema={
4+
properties:[
5+
'id',
6+
'object',
7+
'amount_paid',
8+
'amount_requested',
9+
'created',
10+
'currency',
11+
'invoice',
12+
'is_default',
13+
'livemode',
14+
'payment',
15+
'status',
16+
'status_transitions',
17+
],
18+
}asconst

‎packages/sync-engine/src/stripeSync.ts‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { reviewSchema } from './schemas/review'
3232
import{refundSchema}from'./schemas/refund'
3333
import{activeEntitlementSchema}from'./schemas/active_entitlement'
3434
import{featureSchema}from'./schemas/feature'
35+
import{invoicePaymentSchema}from'./schemas/invoice_payment'
3536
importtype{PoolConfig}from'pg'
3637

3738
functiongetUniqueIds<T>(entries:T[],key:string):string[]{
@@ -553,6 +554,24 @@ export class StripeSync {
553554
)
554555
break
555556
}
557+
case'invoice_payment.paid':{
558+
const{entity:invoicePayment, refetched}=awaitthis.fetchOrUseWebhookData(
559+
event.data.objectasStripe.InvoicePayment,
560+
(id)=>this.stripe.invoicePayments.retrieve(id)
561+
)
562+
563+
this.config.logger?.info(
564+
`Received webhook${event.id}:${event.type} for invoicePayment${invoicePayment.id}`
565+
)
566+
567+
awaitthis.upsertInvoicePayments(
568+
[invoicePayment],
569+
false,
570+
this.getSyncTimestamp(event,refetched)
571+
)
572+
573+
break
574+
}
556575
default:
557576
thrownewError('Unhandled webhook event')
558577
}
@@ -627,6 +646,10 @@ export class StripeSync {
627646
returnthis.stripe.reviews.retrieve(stripeId).then((it)=>this.upsertReviews([it]))
628647
}elseif(stripeId.startsWith('re_')){
629648
returnthis.stripe.refunds.retrieve(stripeId).then((it)=>this.upsertRefunds([it]))
649+
}elseif(stripeId.startsWith('inpay_')){
650+
returnthis.stripe.invoicePayments
651+
.retrieve(stripeId)
652+
.then((it)=>this.upsertInvoicePayments([it]))
630653
}elseif(stripeId.startsWith('feat_')){
631654
returnthis.stripe.entitlements.features
632655
.retrieve(stripeId)
@@ -1280,6 +1303,43 @@ export class StripeSync {
12801303
)
12811304
}
12821305

1306+
asyncupsertInvoicePayments(
1307+
invoicePayments:Stripe.InvoicePayment[],
1308+
backfillRelatedEntities?:boolean,
1309+
syncTimestamp?:string
1310+
):Promise<Stripe.InvoicePayment[]>{
1311+
if(backfillRelatedEntities??this.config.backfillRelatedEntities){
1312+
constinvoiceIds=getUniqueIds(invoicePayments,'invoice')
1313+
constpaymentIntentIds:string[]=[]
1314+
constchargeIds:string[]=[]
1315+
1316+
for(constinvoicePaymentofinvoicePayments){
1317+
constpayment=invoicePayment.paymentas
1318+
|{type?:string;payment_intent?:string;charge?:string}
1319+
|undefined
1320+
1321+
if(payment?.type==='payment_intent'&&payment.payment_intent){
1322+
paymentIntentIds.push(payment.payment_intent.toString())
1323+
}elseif(payment?.type==='charge'&&payment.charge){
1324+
chargeIds.push(payment.charge.toString())
1325+
}
1326+
}
1327+
1328+
awaitPromise.all([
1329+
this.backfillInvoices(invoiceIds),
1330+
this.backfillPaymentIntents([...newSet(paymentIntentIds)]),
1331+
this.backfillCharges([...newSet(chargeIds)]),
1332+
])
1333+
}
1334+
1335+
returnthis.postgresClient.upsertManyWithTimestampProtection(
1336+
invoicePayments,
1337+
'invoice_payments',
1338+
invoicePaymentSchema,
1339+
syncTimestamp
1340+
)
1341+
}
1342+
12831343
asyncupsertPlans(
12841344
plans:Stripe.Plan[],
12851345
backfillRelatedEntities?:boolean,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp