!159 Stripe 升级优化
* wip * fixed stripe charge * wip * wip * code format * wip * wip * 优化 stripe * Background tab is automatically activated
This commit is contained in:
parent
746b0382d9
commit
7ec745c52c
|
|
@ -26,21 +26,16 @@ class StripePaymentService extends PaymentService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws ApiErrorException
|
* @throws ApiErrorException
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function capture($creditCardData): bool
|
public function capture($creditCardData): bool
|
||||||
{
|
{
|
||||||
$apiKey = plugin_setting('stripe.secret_key');
|
$apiKey = plugin_setting('stripe.secret_key');
|
||||||
Stripe::setApiKey($apiKey);
|
Stripe::setApiKey($apiKey);
|
||||||
$token = Token::create([
|
$tokenId = $creditCardData['token'] ?? '';
|
||||||
'card' => [
|
if (empty($tokenId)) {
|
||||||
'number' => $creditCardData['cardnum'],
|
throw new \Exception('Invalid token');
|
||||||
'exp_year' => $creditCardData['year'],
|
}
|
||||||
'exp_month' => $creditCardData['month'],
|
|
||||||
'cvc' => $creditCardData['cvv'],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$tokenId = $token['id'];
|
|
||||||
$currency = $this->order->currency_code;
|
$currency = $this->order->currency_code;
|
||||||
|
|
||||||
if (! in_array($currency, self::ZERO_DECIMAL)) {
|
if (! in_array($currency, self::ZERO_DECIMAL)) {
|
||||||
|
|
|
||||||
|
|
@ -1,114 +1,170 @@
|
||||||
<script src="{{ asset('vendor/vue/2.7/vue' . (!config('app.debug') ? '.min' : '') . '.js') }}"></script>
|
<script src="{{ asset('vendor/vue/2.7/vue' . (!config('app.debug') ? '.min' : '') . '.js') }}"></script>
|
||||||
<script src="{{ asset('vendor/element-ui/index.js') }}"></script>
|
<script src="https://js.stripe.com/v3/"></script>
|
||||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/index.css') }}">
|
|
||||||
|
|
||||||
<script src="{{ asset('plugin/stripe/js/demo.js') }}"></script>
|
|
||||||
<link rel="stylesheet" href="{{ asset('plugin/stripe/css/demo.css') }}">
|
<link rel="stylesheet" href="{{ asset('plugin/stripe/css/demo.css') }}">
|
||||||
<div class="mt-5" id="bk-stripe-app" v-cloak>
|
<div class="mt-5" id="stripe-form" v-cloak>
|
||||||
<hr class="mb-4">
|
<hr class="mb-4">
|
||||||
<div class="checkout-black">
|
<div class="checkout-black">
|
||||||
<h5 class="checkout-title">{{ __('Stripe::common.title_info') }}</h5>
|
<h5 class="checkout-title">{{ __('Stripe::common.title_info') }}</h5>
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="mb-2">
|
<div class="mb-4">
|
||||||
<img src="{{ plugin_origin('stripe','/image/pay-image.png') }}" class="img-fluid">
|
<img src="{{ plugin_origin('stripe','/image/pay-image.png') }}" class="img-fluid">
|
||||||
</div>
|
</div>
|
||||||
<el-form ref="form" label-position="top" :rules="rules" :model="form" class="form-wrap w-max-500">
|
<div class="stripe-card w-max-600">
|
||||||
<el-form-item label="{{ __('Stripe::common.cardnum') }}" prop="cardnum">
|
<div class="mb-3">
|
||||||
<el-input v-model="form.cardnum"></el-input>
|
<div class="mb-2">Cardholder Name</div>
|
||||||
</el-form-item>
|
<div id="card-cardholder-name">
|
||||||
<el-form-item label="{{ __('Stripe::common.expiration_date') }}" required>
|
<input type="text" @input="cardholderNameInput"
|
||||||
<div class="d-flex align-items-center">
|
:class="['form-control', errors.cardholderName ? 'border-danger' : '']"
|
||||||
<el-form-item prop="year" class="flex-grow-1">
|
v-model="form.cardholder_Name"
|
||||||
<el-date-picker class="w-100 me-2" v-model="form.year" format="yyyy" value-format="yyyy"
|
placeholder="Cardholder Name" style="height: 40px; border-color: #dee2e6">
|
||||||
type="year" placeholder="{{ __('Stripe::common.year') }}">
|
|
||||||
</el-date-picker>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="month" class="flex-grow-1 ms-3">
|
|
||||||
<el-date-picker v-model="form.month" class="w-100" format="MM" value-format="MM" type="month"
|
|
||||||
placeholder="{{ __('Stripe::common.month') }}">
|
|
||||||
</el-date-picker>
|
|
||||||
</el-form-item>
|
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</div>
|
||||||
<el-form-item label="{{ __('Stripe::common.cvv') }}" prop="cvv">
|
<div v-if="errors.cardholderName" class="text-danger mt-n2 mb-3">@{{ errors.cardholderName }}</div>
|
||||||
<el-input v-model="form.cvv"></el-input>
|
|
||||||
</el-form-item>
|
<div class="mb-3">
|
||||||
<el-form-item>
|
<div class="mb-2">Credit Card Number</div>
|
||||||
<el-checkbox v-model="form.remenber">{{ __('Stripe::common.remenber') }}</el-checkbox>
|
<div id="card-number-element" :class="['px-2 border card-input', errors.cardNumber ? 'border-danger' : '']">
|
||||||
</el-form-item>
|
</div>
|
||||||
<el-form-item>
|
</div>
|
||||||
<button class="btn btn-primary" type="button" @click="checkedBtnCheckoutConfirm('form')">{{ __('Stripe::common.btn_submit') }}</button>
|
<div class="text-danger mt-n2 mb-3" v-if="errors.cardNumber">@{{ errors.cardNumber }}</div>
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
<div class="mb-3">
|
||||||
|
<div class="mb-2">Expiration Date</div>
|
||||||
|
<div :class="['px-2 border card-input', errors.cardExpiry ? 'border-danger' : '']" id="card-expiry-element">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-danger mt-n2 mb-3" v-if="errors.cardExpiry">@{{ errors.cardExpiry }}</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="mb-2">CVV</div>
|
||||||
|
<div :class="['px-2 border card-input', errors.cardCvc ? 'border-danger' : '']" id="card-cvc-element"></div>
|
||||||
|
</div>
|
||||||
|
<div class="text-danger mt-n2 mb-3" v-if="errors.cardCvc">@{{ errors.cardCvc }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-primary btn-lg" type="button" @click="checkedBtnCheckoutConfirm">{{
|
||||||
|
__('Stripe::common.btn_submit') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
new Vue({
|
let cardNumberElement = null, cardExpiryElement = null, cardCvcElement = null, stripe = null, elements = null;
|
||||||
el: '#bk-stripe-app',
|
const orderNumber = @json($order->number ?? '');
|
||||||
|
|
||||||
|
var stripeForm = new Vue({
|
||||||
|
el: '#stripe-form',
|
||||||
|
|
||||||
data: {
|
data: {
|
||||||
form: {
|
form: {
|
||||||
order_number: @json($order->number ?? null),
|
order_number: '',
|
||||||
cardnum: '',
|
cardnum: '',
|
||||||
year: '',
|
year: '',
|
||||||
month: '',
|
month: '',
|
||||||
cvv: '',
|
cvv: '',
|
||||||
remenber: false,
|
remenber: false,
|
||||||
|
|
||||||
|
// 以上为以前自定义表单的字段
|
||||||
|
cardholder_Name: '',
|
||||||
},
|
},
|
||||||
|
|
||||||
source: {
|
errors: {
|
||||||
order: @json($order ?? null),
|
cardNumber: '',
|
||||||
|
cardExpiry: '',
|
||||||
|
cardCvc: '',
|
||||||
|
cardholderName: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
rules: {
|
|
||||||
cardnum: [{
|
|
||||||
required: true,
|
|
||||||
message: "{{ __('Stripe::common.error_cardnum') }}",
|
|
||||||
trigger: 'blur'
|
|
||||||
}, ],
|
|
||||||
cvv: [{
|
|
||||||
required: true,
|
|
||||||
message: "{{ __('Stripe::common.error_cvv') }}",
|
|
||||||
trigger: 'blur'
|
|
||||||
}, ],
|
|
||||||
year: [{
|
|
||||||
required: true,
|
|
||||||
message: "{{ __('Stripe::common.error_year') }}",
|
|
||||||
trigger: 'blur'
|
|
||||||
}, ],
|
|
||||||
month: [{
|
|
||||||
required: true,
|
|
||||||
message: "{{ __('Stripe::common.error_month') }}",
|
|
||||||
trigger: 'blur'
|
|
||||||
}, ],
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
// console.log(33)
|
stripe = Stripe("{{ plugin_setting('stripe.publishable_key') }}");
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.createAndMountFormElements()
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
checkedBtnCheckoutConfirm(form) {
|
// stripe生成卡号校验部分
|
||||||
this.$refs[form].validate((valid) => {
|
createAndMountFormElements() {
|
||||||
if (!valid) {
|
// stripe 样式,带边框
|
||||||
// this.$message.error('请检查表单是否填写正确');
|
const style = {
|
||||||
return;
|
base: {
|
||||||
|
color: "#32325d",
|
||||||
|
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
|
||||||
|
fontSmoothing: "antialiased",
|
||||||
|
lineHeight: "40px",
|
||||||
|
fontSize: "16px",
|
||||||
|
"::placeholder": {
|
||||||
|
color: "#aab7c4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
invalid: {
|
||||||
|
color: "#fa755a",
|
||||||
|
iconColor: "#fa755a"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$http.post(`/stripe/capture`, this.form).then((res) => {
|
elements = stripe.elements({
|
||||||
layer.msg(res.message)
|
locale: "en" // 设置默认显示语种 en 英文 cn 中文 auto 自动获取语种
|
||||||
|
})
|
||||||
|
|
||||||
@if (current_customer())
|
// 创建cardNumber并实例化
|
||||||
location = "{{ shop_route('account.order.show', ['number' => $order->number]) }}"
|
cardNumberElement = elements.create("cardNumber", {
|
||||||
@else
|
style: style,
|
||||||
location = "{{ shop_route('checkout.success', ['order_number' => $order->number]) }}"
|
showIcon: true, // 设置卡片icon,默认值为false
|
||||||
@endif
|
placeholder: this.cardNumberplaceholder
|
||||||
})
|
})
|
||||||
});
|
|
||||||
}
|
cardNumberElement.mount("#card-number-element")
|
||||||
|
|
||||||
|
// 创建cardExpiry并实例化
|
||||||
|
cardExpiryElement = elements.create("cardExpiry", {style: style})
|
||||||
|
cardExpiryElement.mount("#card-expiry-element")
|
||||||
|
|
||||||
|
// 创建cardCvc并实例化
|
||||||
|
cardCvcElement = elements.create("cardCvc", {style: style, placeholder: 'CVV'})
|
||||||
|
cardCvcElement.mount("#card-cvc-element")
|
||||||
|
},
|
||||||
|
|
||||||
|
cardholderNameInput(e) {
|
||||||
|
if (e.target.value == '') {
|
||||||
|
this.errors.cardholderName = 'Please fill out a cardholder name.'
|
||||||
|
} else {
|
||||||
|
this.errors.cardholderName = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
checkedBtnCheckoutConfirm() {
|
||||||
|
// 判断 stripeForm.errors 里面的值是否都为空
|
||||||
|
if (stripeForm.form.cardholder_Name == '') {
|
||||||
|
stripeForm.errors.cardholderName = 'Please fill out a cardholder name.'
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (Object.values(stripeForm.errors).every(e => e == '')) {
|
||||||
|
const options = {
|
||||||
|
name: stripeForm.form.cardholder_Name,
|
||||||
|
};
|
||||||
|
|
||||||
|
layer.load(2, {shade: [0.3, '#fff']})
|
||||||
|
|
||||||
|
stripe.createToken(cardNumberElement, options).then(function (stripeResult) {
|
||||||
|
if (stripeResult.error) {
|
||||||
|
|
||||||
|
layer.msg(stripeResult.error.message, () => {
|
||||||
|
})
|
||||||
|
layer.closeAll('loading')
|
||||||
|
} else {
|
||||||
|
$http.post(`/stripe/capture`, {token: stripeResult.token.id, order_number: orderNumber}).then((pay) => {
|
||||||
|
if (pay.status == 'success') {
|
||||||
|
location = "checkout/success?order_number=" + orderNumber
|
||||||
|
} else {
|
||||||
|
layer.msg(pay.message, () => {})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* @link https://beikeshop.com
|
* @link https://beikeshop.com
|
||||||
* @Author pu shuo <pushuo@guangda.work>
|
* @Author pu shuo <pushuo@guangda.work>
|
||||||
* @Date 2022-08-26 18:18:22
|
* @Date 2022-08-26 18:18:22
|
||||||
* @LastEditTime 2023-06-14 14:30:05
|
* @LastEditTime 2023-07-14 18:15:09
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import http from "../../../js/http";
|
import http from "../../../js/http";
|
||||||
|
|
@ -64,6 +64,7 @@ $(document).ready(function ($) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
autoActiveTab()
|
||||||
tinymceInit()
|
tinymceInit()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -114,3 +115,17 @@ const tinymceInit = () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const autoActiveTab = () => {
|
||||||
|
const tab = bk.getQueryString('tab');
|
||||||
|
|
||||||
|
if (tab) {
|
||||||
|
if ($(`a[href="#${tab}"]`).length) {
|
||||||
|
$(`a[href="#${tab}"]`)[0].click()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($(`button[data-bs-target="#${tab}"]`).length) {
|
||||||
|
$(`button[data-bs-target="#${tab}"]`)[0].click()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -255,17 +255,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
const [tab, line] = [bk.getQueryString('tab'), bk.getQueryString('line')];
|
const line = bk.getQueryString('line');
|
||||||
getZones(country_id);
|
getZones(country_id);
|
||||||
|
|
||||||
$('select[name="country_id"]').on('change', function () {
|
$('select[name="country_id"]').on('change', function () {
|
||||||
getZones($(this).val());
|
getZones($(this).val());
|
||||||
});
|
});
|
||||||
|
|
||||||
if (tab) {
|
|
||||||
$(`a[href="#${tab}"]`)[0].click()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line) {
|
if (line) {
|
||||||
$(`textarea[name="${line}"], select[name="${line}"], input[name="${line}"]`).parents('.row').addClass('active-line');
|
$(`textarea[name="${line}"], select[name="${line}"], input[name="${line}"]`).parents('.row').addClass('active-line');
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue