1
+ <?php
2
+
3
+ /**
4
+ * 自己写别抄,抄NMB抄
5
+ */
6
+
7
+ namespace App \Payments ;
8
+
9
+ use Stripe \Stripe ;
10
+ use App \Models \User ;
11
+
12
+ class StripeALL
13
+ {
14
+ public function __construct ($ config )
15
+ {
16
+ $ this ->config = $ config ;
17
+ }
18
+
19
+ public function form ()
20
+ {
21
+ return [
22
+ 'currency ' => [
23
+ 'label ' => '货币单位 ' ,
24
+ 'description ' => '请使用符合ISO 4217标准的三位字母,例如GBP ' ,
25
+ 'type ' => 'input ' ,
26
+ ],
27
+ 'stripe_sk_live ' => [
28
+ 'label ' => 'SK_LIVE ' ,
29
+ 'description ' => '' ,
30
+ 'type ' => 'input ' ,
31
+ ],
32
+ 'stripe_webhook_key ' => [
33
+ 'label ' => 'WebHook密钥签名 ' ,
34
+ 'description ' => 'whsec_.... ' ,
35
+ 'type ' => 'input ' ,
36
+ ],
37
+ 'payment_method ' => [
38
+ 'label ' => '支付方式 ' ,
39
+ 'description ' => '请输入alipay, wechat_pay, cards ' ,
40
+ 'type ' => 'input ' ,
41
+ ]
42
+ ];
43
+ }
44
+
45
+ public function pay ($ order )
46
+ {
47
+ $ currency = $ this ->config ['currency ' ];
48
+ $ exchange = $ this ->exchange ('CNY ' , strtoupper ($ currency ));
49
+ if (!$ exchange ) {
50
+ throw new abort ('Currency conversion has timed out, please try again later ' , 500 );
51
+ }
52
+ //jump url
53
+ $ jumpUrl = null ;
54
+ $ actionType = 0 ;
55
+ $ stripe = new \Stripe \StripeClient ($ this ->config ['stripe_sk_live ' ]);
56
+ // 获取用户邮箱
57
+ $ userEmail = $ this ->getUserEmail ($ order ['user_id ' ]);
58
+ if ($ this ->config ['payment_method ' ] != "cards " ) {
59
+ $ stripePaymentMethod = $ stripe ->paymentMethods ->create ([
60
+ 'type ' => $ this ->config ['payment_method ' ],
61
+ ]);
62
+ // 准备支付意图的基础参数
63
+ $ params = [
64
+ 'amount ' => floor ($ order ['total_amount ' ] * $ exchange ),
65
+ 'currency ' => $ currency ,
66
+ 'confirm ' => true ,
67
+ 'payment_method ' => $ stripePaymentMethod ->id ,
68
+ 'automatic_payment_methods ' => ['enabled ' => true ],
69
+ 'statement_descriptor ' => '修改为你的订单描述英文前缀-# ' . $ order ['user_id ' ] . '- ' . substr ($ order ['trade_no ' ], -8 ),
70
+ 'metadata ' => [
71
+ 'user_id ' => $ order ['user_id ' ],
72
+ 'customer_email ' => $ userEmail ,
73
+ 'out_trade_no ' => $ order ['trade_no ' ],
74
+ 'identifier ' => '修改为你的站点名称 '
75
+ ],
76
+ 'return_url ' => $ order ['return_url ' ]
77
+ ];
78
+
79
+ // 如果支付方式为 wechat_pay,添加相应的支付方式选项
80
+ if ($ this ->config ['payment_method ' ] === 'wechat_pay ' ) {
81
+ $ params ['payment_method_options ' ] = [
82
+ 'wechat_pay ' => [
83
+ 'client ' => 'web '
84
+ ],
85
+ ];
86
+ }
87
+ //更新支持最新的paymentIntents方法,Sources API将在今年被彻底替
88
+ $ stripeIntents = $ stripe ->paymentIntents ->create ($ params );
89
+
90
+ $ nextAction = null ;
91
+
92
+ if (!$ stripeIntents ['next_action ' ]) {
93
+ throw new abort (__ ('Payment gateway request failed ' ));
94
+ } else {
95
+ $ nextAction = $ stripeIntents ['next_action ' ];
96
+ }
97
+
98
+ switch ($ this ->config ['payment_method ' ]) {
99
+ case "alipay " :
100
+ if (isset ($ nextAction ['alipay_handle_redirect ' ])) {
101
+ $ jumpUrl = $ nextAction ['alipay_handle_redirect ' ]['url ' ];
102
+ $ actionType = 1 ;
103
+ } else {
104
+ throw new abort ('unable get Alipay redirect url ' , 500 );
105
+ }
106
+ break ;
107
+ case "wechat_pay " :
108
+ if (isset ($ nextAction ['wechat_pay_display_qr_code ' ])) {
109
+ $ jumpUrl = $ nextAction ['wechat_pay_display_qr_code ' ]['data ' ];
110
+ } else {
111
+ throw new abort ('unable get WeChat Pay redirect url ' , 500 );
112
+ }
113
+ }
114
+ } else {
115
+ $ creditCheckOut = $ stripe ->checkout ->sessions ->create ([
116
+ 'success_url ' => $ order ['return_url ' ],
117
+ 'client_reference_id ' => $ order ['trade_no ' ],
118
+ 'payment_method_types ' => ['card ' ],
119
+ 'line_items ' => [
120
+ [
121
+ 'price_data ' => [
122
+ 'currency ' => $ currency ,
123
+ 'unit_amount ' => floor ($ order ['total_amount ' ] * $ exchange ),
124
+ 'product_data ' => [
125
+ 'name ' => '修改为你的订单描述英文前缀-# ' . $ order ['user_id ' ] . '- ' . substr ($ order ['trade_no ' ], -8 ),
126
+ ]
127
+ ],
128
+ 'quantity ' => 1 ,
129
+ ],
130
+ ],
131
+ 'mode ' => 'payment ' ,
132
+ 'invoice_creation ' => ['enabled ' => true ],
133
+ 'phone_number_collection ' => ['enabled ' => false ],
134
+ 'customer_email ' => $ userEmail ,
135
+ ]);
136
+ $ jumpUrl = $ creditCheckOut ['url ' ];
137
+ $ actionType = 1 ;
138
+ }
139
+
140
+ return [
141
+ 'type ' => $ actionType ,
142
+ 'data ' => $ jumpUrl
143
+ ];
144
+ }
145
+
146
+ public function notify ($ params )
147
+ {
148
+ try {
149
+ $ event = \Stripe \Webhook::constructEvent (
150
+ request ()->getContent () ?: json_encode ($ _POST ),
151
+ $ _SERVER ['HTTP_STRIPE_SIGNATURE ' ],
152
+ $ this ->config ['stripe_webhook_key ' ]
153
+ );
154
+ } catch (\Stripe \Error \SignatureVerification $ e ) {
155
+ abort (400 );
156
+ }
157
+ switch ($ event ->type ) {
158
+ case 'payment_intent.succeeded ' :
159
+ $ object = $ event ->data ->object ;
160
+ if ($ object ->status === 'succeeded ' ) {
161
+ if (!isset ($ object ->metadata ->out_trade_no )) {
162
+ return ('order error ' );
163
+ }
164
+ $ metaData = $ object ->metadata ;
165
+ $ tradeNo = $ metaData ->out_trade_no ;
166
+ return [
167
+ 'trade_no ' => $ tradeNo ,
168
+ 'callback_no ' => $ object ->id
169
+ ];
170
+ }
171
+ break ;
172
+ case 'checkout.session.completed ' :
173
+ $ object = $ event ->data ->object ;
174
+ if ($ object ->payment_status === 'paid ' ) {
175
+ return [
176
+ 'trade_no ' => $ object ->client_reference_id ,
177
+ 'callback_no ' => $ object ->payment_intent
178
+ ];
179
+ }
180
+ break ;
181
+ case 'checkout.session.async_payment_succeeded ' :
182
+ $ object = $ event ->data ->object ;
183
+ return [
184
+ 'trade_no ' => $ object ->client_reference_id ,
185
+ 'callback_no ' => $ object ->payment_intent
186
+ ];
187
+ break ;
188
+ default :
189
+ throw new abort ('event is not support ' );
190
+ }
191
+ return ('success ' );
192
+ }
193
+ // 货币转换 API 1
194
+ private function exchange ($ from , $ to )
195
+ {
196
+ $ from = strtolower ($ from );
197
+ $ to = strtolower ($ to );
198
+
199
+ // 使用第一个API进行货币转换
200
+ try {
201
+ $ result = file_get_contents ("https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/ " . $ from . ".min.json " );
202
+ $ result = json_decode ($ result , true );
203
+
204
+ // 如果转换成功,返回结果
205
+ if (isset ($ result [$ from ][$ to ])) {
206
+ return $ result [$ from ][$ to ];
207
+ } else {
208
+ throw new \Exception ("Primary currency API failed. " );
209
+ }
210
+ } catch (\Exception $ e ) {
211
+ // 如果第一个API不可用,调用备用API
212
+ return $ this ->backupExchange ($ from , $ to );
213
+ }
214
+ }
215
+
216
+ // 备用货币转换 API 方法
217
+ private function backupExchange ($ from , $ to )
218
+ {
219
+ try {
220
+ $ url = "https://api.exchangerate-api.com/v4/latest/ {$ from }" ;
221
+ $ result = file_get_contents ($ url );
222
+ $ result = json_decode ($ result , true );
223
+
224
+ // 如果转换成功,返回结果
225
+ if (isset ($ result ['rates ' ][$ to ])) {
226
+ return $ result ['rates ' ][$ to ];
227
+ } else {
228
+ throw new \Exception ("Backup currency API failed. " );
229
+ }
230
+ } catch (\Exception $ e ) {
231
+ // 如果备用API也失败,调用第二个备用API
232
+ return $ this ->thirdExchange ($ from , $ to );
233
+ }
234
+ }
235
+
236
+ // 第二个备用货币转换 API 方法
237
+ private function thirdExchange ($ from , $ to )
238
+ {
239
+ try {
240
+ $ url = "https://api.frankfurter.app/latest?from= {$ from }&to= {$ to }" ;
241
+ $ result = file_get_contents ($ url );
242
+ $ result = json_decode ($ result , true );
243
+
244
+ // 如果转换成功,返回结果
245
+ if (isset ($ result ['rates ' ][$ to ])) {
246
+ return $ result ['rates ' ][$ to ];
247
+ } else {
248
+ throw new \Exception ("Third currency API failed. " );
249
+ }
250
+ } catch (\Exception $ e ) {
251
+ // 如果所有API都失败,抛出异常
252
+ throw new \Exception ("All currency conversion APIs failed. " );
253
+ }
254
+ }
255
+ }
0 commit comments