From 9edc5fd2bad0c44d1b17300837f284a5f39c754f Mon Sep 17 00:00:00 2001 From: huangzhiyuan5 <11343052+huangzhiyuan5@user.noreply.gitee.com> Date: Thu, 6 Apr 2023 10:22:31 +0800 Subject: [PATCH 1/2] =?UTF-8?q?stripe=E8=AF=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1.txt | 15 +++++ app/controller/stripe.js | 16 +++++ app/graphql/input/schema.graphql | 3 + app/graphql/paymentIntent/connector.js | 67 +++++++++++++++++++ app/graphql/paymentIntent/resolver.js | 12 ++++ app/graphql/paymentIntent/schema.graphql | 6 ++ app/graphql/query/schema.graphql | 5 ++ app/graphql/refunds/connector.js | 35 ++++++++++ app/graphql/refunds/resolver.js | 9 +++ app/graphql/refunds/schema.graphql | 6 ++ app/model/paymentIntent.js | 84 ++++++++++++++++++++++++ app/router.js | 21 +++--- app/service/stripe.js | 35 ++++++++++ config/config.default.js | 2 +- package.json | 1 + 15 files changed, 306 insertions(+), 11 deletions(-) create mode 100644 1.txt create mode 100644 app/controller/stripe.js create mode 100644 app/graphql/input/schema.graphql create mode 100644 app/graphql/paymentIntent/connector.js create mode 100644 app/graphql/paymentIntent/resolver.js create mode 100644 app/graphql/paymentIntent/schema.graphql create mode 100644 app/graphql/refunds/connector.js create mode 100644 app/graphql/refunds/resolver.js create mode 100644 app/graphql/refunds/schema.graphql create mode 100644 app/model/paymentIntent.js create mode 100644 app/service/stripe.js diff --git a/1.txt b/1.txt new file mode 100644 index 0000000..b353d38 --- /dev/null +++ b/1.txt @@ -0,0 +1,15 @@ +query{ + createPaymentIntent(items:[{id:"skitr"},{id:"jacket"}]){ + clientSecret + } +} +query{ + retrievePaymentIntent(id:"pi_3Ms5FkFLEJ5PFQhO0jIhesMD"){ + paymentIntentStatus + } +} +query{ + refundsPaymentIntent(id:"pi_3MqzOGFLEJ5PFQhO0OVtgd0j"){ + paymentIntentStatus + } +} \ No newline at end of file diff --git a/app/controller/stripe.js b/app/controller/stripe.js new file mode 100644 index 0000000..f9de025 --- /dev/null +++ b/app/controller/stripe.js @@ -0,0 +1,16 @@ +'use strict'; + +const Controller = require('egg').Controller; + +class WebhookController extends Controller { + + async webhook() { + // 接收阿里服务器POST提交的XML数据 + const params = this.ctx.request.body; + const result = await this.service.stripe.webhook(params); + console.log('-------------------------------------------------------webhook'); + } + +} + +module.exports = WebhookController; diff --git a/app/graphql/input/schema.graphql b/app/graphql/input/schema.graphql new file mode 100644 index 0000000..f6db29d --- /dev/null +++ b/app/graphql/input/schema.graphql @@ -0,0 +1,3 @@ +input Items{ + id:String, +} \ No newline at end of file diff --git a/app/graphql/paymentIntent/connector.js b/app/graphql/paymentIntent/connector.js new file mode 100644 index 0000000..65013ea --- /dev/null +++ b/app/graphql/paymentIntent/connector.js @@ -0,0 +1,67 @@ +'use strict'; + +const DataLoader = require('dataloader'); +const { cors } = require('../../../config/plugin'); +const ObjectId = require('mongodb').ObjectID; +const stripe = require("stripe")('process.env.STRIPE_PRIVATE_KEY'); + + +const calculateOrderAmount = (items) => { + // Replace this constant with a calculation of the order's amount + // Calculate the order total on the server to prevent + // people from directly manipulating the amount on the client + return 1400; +}; + +class paymentIntentConnector { + constructor(ctx) { + this.ctx = ctx; + } + + /** + * 创建stripe订单 + * @param {{String}} items 商品对象,包含字符串元素 + * @param {Strin} userId 用户id + * @returns clientSecret + */ + + async createPaymentIntent(items, userId) { + let paymentIntent; + await stripe.paymentIntents.create({ + amount: calculateOrderAmount(items), + currency: "usd", + automatic_payment_methods: { + enabled: true, + }, + }).then(result => { + console.log(result); + paymentIntent = result; + // const user = this.ctx.model.User.findOne({ _id: userId }); + // this.ctx.model.PaymentIntent.create({ + + // }) + + }); + return { clientSecret: paymentIntent.client_secret }; + } + + /** + * 查询stripe订单 + * @param {Strin} id 订单id + * @returns paymentIntentStatus 订单状态 + */ + + async retrievePaymentIntent(id) { + let paymentIntent; + await stripe.paymentIntents.retrieve( + id + ).then(result => { + //console.log(result); + paymentIntent = result; + console.log(paymentIntent); + }); + return { paymentIntentStatus: paymentIntent.status }; + } +} + +module.exports = paymentIntentConnector; diff --git a/app/graphql/paymentIntent/resolver.js b/app/graphql/paymentIntent/resolver.js new file mode 100644 index 0000000..d04dc00 --- /dev/null +++ b/app/graphql/paymentIntent/resolver.js @@ -0,0 +1,12 @@ +'use strict'; + +module.exports = { + Query: { + createPaymentIntent(root, { items }, ctx) { + return ctx.connector.paymentIntent.createPaymentIntent(items); + }, + retrievePaymentIntent(root, { id }, ctx) { + return ctx.connector.paymentIntent.retrievePaymentIntent(id); + }, + }, +}; diff --git a/app/graphql/paymentIntent/schema.graphql b/app/graphql/paymentIntent/schema.graphql new file mode 100644 index 0000000..b968f23 --- /dev/null +++ b/app/graphql/paymentIntent/schema.graphql @@ -0,0 +1,6 @@ +type clientSecret{ + clientSecret:String, +} +type paymentIntentStatus{ + paymentIntentStatus:String, +} \ No newline at end of file diff --git a/app/graphql/query/schema.graphql b/app/graphql/query/schema.graphql index 79a2f4e..c4c945c 100644 --- a/app/graphql/query/schema.graphql +++ b/app/graphql/query/schema.graphql @@ -14,6 +14,11 @@ type Query { course(category_id: String!, page: Int, limit: Int): [CourseDetail!] courseCatalogue(course_id: String!): [Catalogue!] courseLink(detail_id: String!): Link! + #stripe paymentIntent支付 + createPaymentIntent(items:Items!):clientSecret! + retrievePaymentIntent(id:String!):paymentIntentStatus! + #stripe refunds支付 + createRefunds(id:String!):paymentIntentStatus! # 获取支付信息 reToken(token: String!): Token! diff --git a/app/graphql/refunds/connector.js b/app/graphql/refunds/connector.js new file mode 100644 index 0000000..e2cf042 --- /dev/null +++ b/app/graphql/refunds/connector.js @@ -0,0 +1,35 @@ +'use strict'; + +const DataLoader = require('dataloader'); +const { cors } = require('../../../config/plugin'); +const ObjectId = require('mongodb').ObjectID; +const stripe = require("stripe")('process.env.STRIPE_PRIVATE_KEY'); + +class refundsConnector { + constructor(ctx) { + this.ctx = ctx; + } + + /** + * 创建退款 + * @param {String} id 订单的payment_intent的id + * @returns paymentIntentStatus 退款状态 + */ + + async createRefunds(id) { + let paymentIntent; + await stripe.refunds.create({ + payment_intent: id, + }).then(result => { + //console.log(result); + paymentIntent = result; + }); + console.log('---------------------'); + console.log(paymentIntent); + console.log('---------------------'); + return { paymentIntentStatus: paymentIntent.status }; + } + +} + +module.exports = refundsConnector; diff --git a/app/graphql/refunds/resolver.js b/app/graphql/refunds/resolver.js new file mode 100644 index 0000000..624ccba --- /dev/null +++ b/app/graphql/refunds/resolver.js @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + Query: { + createRefunds(root, { id }, ctx) { + return ctx.connector.refunds.createRefunds(id); + }, + }, +}; diff --git a/app/graphql/refunds/schema.graphql b/app/graphql/refunds/schema.graphql new file mode 100644 index 0000000..b968f23 --- /dev/null +++ b/app/graphql/refunds/schema.graphql @@ -0,0 +1,6 @@ +type clientSecret{ + clientSecret:String, +} +type paymentIntentStatus{ + paymentIntentStatus:String, +} \ No newline at end of file diff --git a/app/model/paymentIntent.js b/app/model/paymentIntent.js new file mode 100644 index 0000000..56f7263 --- /dev/null +++ b/app/model/paymentIntent.js @@ -0,0 +1,84 @@ +module.exports = app => { + const mongoose = app.mongoose; + const Schema = mongoose.Schema; + const PaymentIntentSchema = new Schema({ + amount: { + type: String, + unique: false, + required: false, + }, + currency: { + type: String, + unique: false, + required: false, + }, + description: { + type: String, + unique: false, + required: false, + default: '', + }, + id: { + type: String, + unique: false, + required: false, + }, + userId: { + type: String, + unique: false, + required: false, + },//customer为该项对应值 + userPhone: { + type: String, + unique: false, + required: false, + }, + receipt_email: { + type: String, + unique: false, + required: false, + }, + ////////////////////////////////////////////////// + payTime: { + type: String, + unique: false, + required: false, + }, + refundTime: { + type: String, + unique: false, + required: false, + }, + subject: { + type: String, + unique: false, + required: false, + default: '', + }, + orderInfo: { + type: String, + unique: false, + required: false, + default: '', + }, + status: { + type: String, + unique: false, + required: false, + default: 'WAIT_BUYER_PAY', + }, + refundReason: { + type: String, + unique: false, + required: false, + default: '', + }, + refundDescription: { + type: String, + unique: false, + required: false, + default: '', + }, + }); + return mongoose.model('PaymentIntent', PaymentIntentSchema); +}; diff --git a/app/router.js b/app/router.js index d94ed54..42577d0 100644 --- a/app/router.js +++ b/app/router.js @@ -4,17 +4,18 @@ * @param {Egg.Application} app - egg application */ module.exports = app => { - const { router, controller } = app; - router.get('/', controller.home.index); + const { router, controller } = app; + router.get('/', controller.home.index); - // 解析XML的中间件 - const xmlParseMiddleware = app.middleware.xmlParse(); + // 解析XML的中间件 + const xmlParseMiddleware = app.middleware.xmlParse(); - // 调用支付_web - router.get('/aliPay', controller.default.aliPay.pay); - // 支付回调 - router.get('/aliPay/aliPayReturn', controller.default.aliPay.aliPayReturn); - // 支付通知(关闭CSRF验证) - router.post('/aliPay/aliPayNotify', xmlParseMiddleware, controller.default.aliPay.aliPayNotify); + // 调用支付_web + router.get('/aliPay', controller.default.aliPay.pay); + // 支付回调 + router.get('/aliPay/aliPayReturn', controller.default.aliPay.aliPayReturn); + // 支付通知(关闭CSRF验证) + router.post('/aliPay/aliPayNotify', xmlParseMiddleware, controller.default.aliPay.aliPayNotify); + router.post('/webhook', controller.stripe.webhook); }; diff --git a/app/service/stripe.js b/app/service/stripe.js new file mode 100644 index 0000000..29d87e2 --- /dev/null +++ b/app/service/stripe.js @@ -0,0 +1,35 @@ +'use strict'; + +const Service = require('egg').Service; +const stripe = require("stripe")(process.env.STRIPE_PRIVATE_KEY); + + +class WebhookService extends Service { + + // 异步通知 + webhook(event) { + // 实例化支付宝支付 + console.log("receive webhook"); + switch (event.type) { + case 'payment_intent.succeeded': + const paymentIntent = event.data.object; + console.log('PaymentIntent was successful!'); + break; + case 'payment_method.attached': + const paymentMethod = event.data.object; + console.log('PaymentMethod was attached to a Customer!'); + break; + // ... handle other event types + case 'payment_intent.created': + //const paymentMethod = event.data.object; + console.log('PaymentMethod was precreated!'); + break; + default: + console.log(`Unhandled event type ${event.type}`); + } + } + + +} + +module.exports = WebhookService; diff --git a/config/config.default.js b/config/config.default.js index 88b7f02..828dfc6 100644 --- a/config/config.default.js +++ b/config/config.default.js @@ -78,7 +78,7 @@ module.exports = appInfo => { ignore: ctx => { // console.log("____________________________________________________"); // console.log(ctx.request.url); - if (ctx.request.url === '/aliPay/aliPayNotify' || ctx.request.url === '/graphql' || ctx.request.url === '/graphql?' || ctx.request.url === '/api/registered' || ctx.request.url === '/api/login') { + if (ctx.request.url === '/aliPay/aliPayNotify' || ctx.request.url === '/graphql' || ctx.request.url === '/graphql?' || ctx.request.url === '/api/registered' || ctx.request.url === '/api/login' || ctx.request.url === '/webhook') { return true; } return false; diff --git a/package.json b/package.json index 478fb12..e27916a 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "nodemailer": "^6.8.0", "qiniu": "^7.7.0", "redis": "^4.3.1", + "stripe": "^11.17.0", "validator": "^13.9.0" }, "devDependencies": { -- Gitee From 4d3e6b97e21b88c17cfa917796660b9313f5c121 Mon Sep 17 00:00:00 2001 From: huangzhiyuan5 <11343052+huangzhiyuan5@user.noreply.gitee.com> Date: Thu, 6 Apr 2023 10:23:10 +0800 Subject: [PATCH 2/2] =?UTF-8?q?stripe=E8=AF=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1.txt | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 1.txt diff --git a/1.txt b/1.txt deleted file mode 100644 index b353d38..0000000 --- a/1.txt +++ /dev/null @@ -1,15 +0,0 @@ -query{ - createPaymentIntent(items:[{id:"skitr"},{id:"jacket"}]){ - clientSecret - } -} -query{ - retrievePaymentIntent(id:"pi_3Ms5FkFLEJ5PFQhO0jIhesMD"){ - paymentIntentStatus - } -} -query{ - refundsPaymentIntent(id:"pi_3MqzOGFLEJ5PFQhO0OVtgd0j"){ - paymentIntentStatus - } -} \ No newline at end of file -- Gitee