|
@@ -0,0 +1,467 @@
|
|
|
|
+<?php
|
|
|
|
+
|
|
|
|
+namespace App\Http\Controllers\Pay;
|
|
|
|
+
|
|
|
|
+use App\Exceptions\RuleValidationException;
|
|
|
|
+use App\Http\Controllers\PayController;
|
|
|
|
+use Illuminate\Http\Request;
|
|
|
|
+use GuzzleHttp\Client;
|
|
|
|
+use Illuminate\Support\Facades\Redis;
|
|
|
|
+use URL;
|
|
|
|
+
|
|
|
|
+class StripeController extends PayController
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+ public function gateway(string $payway, string $orderSN)
|
|
|
|
+ {
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // 加载网关
|
|
|
|
+ $this->loadGateWay($orderSN, $payway);
|
|
|
|
+ //构造要请求的参数数组,无需改动
|
|
|
|
+ switch ($payway) {
|
|
|
|
+ case 'wx':
|
|
|
|
+ case 'alipay':
|
|
|
|
+ default:
|
|
|
|
+ try {
|
|
|
|
+ \Stripe\Stripe::setApiKey($this->payGateway->merchant_id);
|
|
|
|
+ $amount = bcmul($this->order->actual_price, 100, 2);
|
|
|
|
+ $price = $this->order->actual_price;
|
|
|
|
+ $gbp = bcmul($this->getGbpCurrency($this->order->actual_price), 100, 2);
|
|
|
|
+ $orderid = $this->order->order_sn;
|
|
|
|
+ $pk = $this->payGateway->merchant_id;
|
|
|
|
+ $return_url = site_url() . $this->payGateway->pay_handleroute . '/return_url/?orderid=' . $this->order->order_sn;
|
|
|
|
+ $html = "<html class=\"js cssanimations\">
|
|
|
|
+<head lang=\"en\">
|
|
|
|
+ <meta charset=\"UTF-8\">
|
|
|
|
+ <title>收银台</title>
|
|
|
|
+ <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">
|
|
|
|
+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
|
|
|
+ <meta name=\"format-detection\" content=\"telephone=no\">
|
|
|
|
+ <meta name=\"renderer\" content=\"webkit\">
|
|
|
|
+ <meta http-equiv=\"Cache-Control\" content=\"no-siteapp\">
|
|
|
|
+ <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/[email protected]/dist/css/amazeui.min.css\">
|
|
|
|
+ <script src=\"https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js\"></script>
|
|
|
|
+ <script src=\"https://cdn.jsdelivr.net/npm/[email protected]/jquery.qrcode.min.js\"></script>
|
|
|
|
+ <script src=\"https://cdn.jsdelivr.net/npm/[email protected]/dist/js/amazeui.min.js\"></script>
|
|
|
|
+ <script src=\"https://js.stripe.com/v3/\"></script>
|
|
|
|
+ <style>
|
|
|
|
+ @media only screen and (min-width: 641px) {
|
|
|
|
+ .am-offcanvas {
|
|
|
|
+ display: block;
|
|
|
|
+ position: static;
|
|
|
|
+ background: none;
|
|
|
|
+ }
|
|
|
|
+ .am-offcanvas-bar {
|
|
|
|
+ position: static;
|
|
|
|
+ width: auto;
|
|
|
|
+ background: none;
|
|
|
|
+ -webkit-transform: translate3d(0, 0, 0);
|
|
|
|
+ -ms-transform: translate3d(0, 0, 0);
|
|
|
|
+ transform: translate3d(0, 0, 0);
|
|
|
|
+ }
|
|
|
|
+ .am-offcanvas-bar:after {
|
|
|
|
+ content: none;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @media only screen and (max-width: 640px) {
|
|
|
|
+ .am-offcanvas-bar .am-nav > li > a {
|
|
|
|
+ color: #ccc;
|
|
|
|
+ border-radius: 0;
|
|
|
|
+ border-top: 1px solid rgba(0, 0, 0, .3);
|
|
|
|
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05)
|
|
|
|
+ }
|
|
|
|
+ .am-offcanvas-bar .am-nav > li > a:hover {
|
|
|
|
+ background: #404040;
|
|
|
|
+ color: #fff
|
|
|
|
+ }
|
|
|
|
+ .am-offcanvas-bar .am-nav > li.am-nav-header {
|
|
|
|
+ color: #777;
|
|
|
|
+ background: #404040;
|
|
|
|
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
|
|
|
|
+ text-shadow: 0 1px 0 rgba(0, 0, 0, .5);
|
|
|
|
+ border-top: 1px solid rgba(0, 0, 0, .3);
|
|
|
|
+ font-weight: 400;
|
|
|
|
+ font-size: 75%
|
|
|
|
+ }
|
|
|
|
+ .am-offcanvas-bar .am-nav > li.am-active > a {
|
|
|
|
+ background: #1a1a1a;
|
|
|
|
+ color: #fff;
|
|
|
|
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, .3)
|
|
|
|
+ }
|
|
|
|
+ .am-offcanvas-bar .am-nav > li + li {
|
|
|
|
+ margin-top: 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .my-head {
|
|
|
|
+ margin-top: 40px;
|
|
|
|
+ text-align: center;
|
|
|
|
+ }
|
|
|
|
+ .am-tab-panel {
|
|
|
|
+ text-align: center;
|
|
|
|
+ margin-top: 50px;
|
|
|
|
+ margin-bottom: 50px;
|
|
|
|
+ }
|
|
|
|
+ .my-footer {
|
|
|
|
+ border-top: 1px solid #eeeeee;
|
|
|
|
+ padding: 10px 0;
|
|
|
|
+ margin-top: 10px;
|
|
|
|
+ text-align: center;
|
|
|
|
+ }
|
|
|
|
+ .panel-title {
|
|
|
|
+ display: inline;
|
|
|
|
+ font-weight: bold;
|
|
|
|
+ }
|
|
|
|
+ .display-table {
|
|
|
|
+ display: table;
|
|
|
|
+ }
|
|
|
|
+ .display-tr {
|
|
|
|
+ display: table-row;
|
|
|
|
+ }
|
|
|
|
+ .display-td {
|
|
|
|
+ display: table-cell;
|
|
|
|
+ vertical-align: middle;
|
|
|
|
+ width: 61%;
|
|
|
|
+ }
|
|
|
|
+ .StripeElement {
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
+ height: 40px;
|
|
|
|
+ padding: 10px 12px;
|
|
|
|
+ border: 1px solid transparent;
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+ background-color: white;
|
|
|
|
+ box-shadow: 0 1px 3px 0 #e6ebf1;
|
|
|
|
+ -webkit-transition: box-shadow 150ms ease;
|
|
|
|
+ transition: box-shadow 150ms ease;
|
|
|
|
+ }
|
|
|
|
+ .StripeElement--focus {
|
|
|
|
+ box-shadow: 0 1px 3px 0 #cfd7df;
|
|
|
|
+ }
|
|
|
|
+ .StripeElement--invalid {
|
|
|
|
+ border-color: #fa755a;
|
|
|
|
+ }
|
|
|
|
+ .StripeElement--webkit-autofill {
|
|
|
|
+ background-color: #fefde5 !important;
|
|
|
|
+ }
|
|
|
|
+ .form-row {
|
|
|
|
+ width: 70%;
|
|
|
|
+ float: left;
|
|
|
|
+ }
|
|
|
|
+ .wrapper {
|
|
|
|
+ width: 670px;
|
|
|
|
+ margin: 0 auto;
|
|
|
|
+ }
|
|
|
|
+ label {
|
|
|
|
+ font-weight: 500;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ display: block;
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
+ }
|
|
|
|
+ .button {
|
|
|
|
+ border: none;
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+ outline: none;
|
|
|
|
+ text-decoration: none;
|
|
|
|
+ color: #fff;
|
|
|
|
+ background: #32325d;
|
|
|
|
+ white-space: nowrap;
|
|
|
|
+ display: inline-block;
|
|
|
|
+ height: 40px;
|
|
|
|
+ line-height: 40px;
|
|
|
|
+ padding: 0 14px;
|
|
|
|
+ box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+ font-size: 16px;
|
|
|
|
+ font-weight: 600;
|
|
|
|
+ letter-spacing: 0.025em;
|
|
|
|
+ text-decoration: none;
|
|
|
|
+ -webkit-transition: all 150ms ease;
|
|
|
|
+ transition: all 150ms ease;
|
|
|
|
+ margin-top: 10px;
|
|
|
|
+ }
|
|
|
|
+ </style>
|
|
|
|
+</head>
|
|
|
|
+<body>
|
|
|
|
+<header class=\"am-g my-head\">
|
|
|
|
+ <div class=\"am-u-sm-12 am-article\">
|
|
|
|
+ <h1 class=\"am-article-title\">收银台</h1>
|
|
|
|
+ </div>
|
|
|
|
+</header>
|
|
|
|
+<hr class=\"am-article-divider\">
|
|
|
|
+<div class=\"am-container\">
|
|
|
|
+ <h2>付款信息
|
|
|
|
+ <div class=\"am-topbar-right\">¥{$price}</div>
|
|
|
|
+ </h2>
|
|
|
|
+ <p><small>订单编号:$orderid</small></p>
|
|
|
|
+ <div class=\"am-tabs\" data-am-tabs=\"\">
|
|
|
|
+ <ul class=\"am-tabs-nav am-nav am-nav-tabs\">
|
|
|
|
+ <li class=\"am-active\"><a href=\"#alipay\">Alipay 支付宝</a></li>
|
|
|
|
+ <li class=\"request-card-pay\"><a href=\"#cardpay\">银行卡支付</a></li>
|
|
|
|
+ </ul>
|
|
|
|
+ <div class=\"am-tabs-bd am-tabs-bd-ofv\"
|
|
|
|
+ style=\"touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\">
|
|
|
|
+ <div class=\"am-tab-panel am-active\" id=\"alipay\">
|
|
|
|
+ <a class=\"am-btn am-btn-lg am-btn-warning am-btn-primary\" id=\"alipaybtn\" href=\"#\">进入支付宝付款</a>
|
|
|
|
+ <p></p>
|
|
|
|
+ </div>
|
|
|
|
+ <div class=\"am-tab-panel am-fade\" id=\"cardpay\">
|
|
|
|
+ <div class=\"text-align:center; margin:0 auto; width:60%\">
|
|
|
|
+ <div class=\"wrapper cardpay_content\" style=\"max-width:500px\">
|
|
|
|
+ <div class=\"am-alert am-alert-danger\" style=\"display:none\">支付失败,请更换卡片或检查输入信息</div>
|
|
|
|
+ <form action=\"/pay/stripe/charge\" method=\"post\" id=\"payment-form\">
|
|
|
|
+ <div class=\"form-row\">
|
|
|
|
+ <label for=\"card-element\">
|
|
|
|
+ <p class='am-alert am-alert-secondary'>借记卡或信用卡</p>
|
|
|
|
+ </label>
|
|
|
|
+ <div id=\"card-element\">
|
|
|
|
+ <!-- A Stripe Element will be inserted here. -->
|
|
|
|
+ </div>
|
|
|
|
+ <!-- Used to display form errors. -->
|
|
|
|
+ <div id=\"card-errors\" role=\"alert\"></div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class=\"form-row\">
|
|
|
|
+ <button class=\"button\">支付</button>
|
|
|
|
+ </div>
|
|
|
|
+ </form>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+</div>
|
|
|
|
+</div>
|
|
|
|
+<script>
|
|
|
|
+ var stripe = Stripe('$pk');
|
|
|
|
+ var source = '';
|
|
|
|
+ // Create a Stripe client.
|
|
|
|
+ // Create an instance of Elements.
|
|
|
|
+ var elements = stripe.elements();
|
|
|
|
+ // Custom styling can be passed to options when creating an Element.
|
|
|
|
+ // (Note that this demo uses a wider set of styles than the guide below.)
|
|
|
|
+ var style = {
|
|
|
|
+ base: {
|
|
|
|
+ color: '#32325d',
|
|
|
|
+ fontFamily: '\"Helvetica Neue\", Helvetica, sans-serif',
|
|
|
|
+ fontSmoothing: 'antialiased',
|
|
|
|
+ fontSize: '16px',
|
|
|
|
+ '::placeholder': {
|
|
|
|
+ color: '#aab7c4'
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ invalid: {
|
|
|
|
+ color: '#fa755a',
|
|
|
|
+ iconColor: '#fa755a'
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ // Create an instance of the card Element.
|
|
|
|
+ var card = elements.create('card', {style: style});
|
|
|
|
+ // Add an instance of the card Element into the `card-element` <div>.
|
|
|
|
+ card.mount('#card-element');
|
|
|
|
+ // Handle real-time validation errors from the card Element.
|
|
|
|
+ card.on('change', function (event) {
|
|
|
|
+ var displayError = document.getElementById('card-errors');
|
|
|
|
+ if (event.error) {
|
|
|
|
+ displayError.textContent = event.error.message;
|
|
|
|
+ } else {
|
|
|
|
+ displayError.textContent = '';
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ // Handle form submission.
|
|
|
|
+ var form = document.getElementById('payment-form');
|
|
|
|
+ form.addEventListener('submit', function (event) {
|
|
|
|
+ event.preventDefault();
|
|
|
|
+ $(\".button\").attr(\"disabled\",\"true\");
|
|
|
|
+ $(\".button\").html(\"请稍后\");
|
|
|
|
+ stripe.createToken(card).then(function (result) {
|
|
|
|
+ if (result.error) {
|
|
|
|
+ // Inform the user if there was an error.
|
|
|
|
+ var errorElement = document.getElementById('card-errors');
|
|
|
|
+ errorElement.textContent = result.error.message;
|
|
|
|
+ } else {
|
|
|
|
+ // Send the token to your server.
|
|
|
|
+ stripeTokenHandler(result.token);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ // Submit the form with the token ID.
|
|
|
|
+ function stripeTokenHandler(token) {
|
|
|
|
+ // Insert the token ID into the form so it gets submitted to the server
|
|
|
|
+ var form = document.getElementById('payment-form');
|
|
|
|
+ var hiddenInput = document.createElement('input');
|
|
|
|
+ var hiddenInput1 = document.createElement('input');
|
|
|
|
+ hiddenInput.setAttribute('type', 'hidden');
|
|
|
|
+ hiddenInput.setAttribute('name', 'stripeToken');
|
|
|
|
+ hiddenInput.setAttribute('value', token.id);
|
|
|
|
+ hiddenInput1.setAttribute('type', 'hidden');
|
|
|
|
+ hiddenInput1.setAttribute('name', 'orderid');
|
|
|
|
+ hiddenInput1.setAttribute('value', '$orderid');
|
|
|
|
+ form.appendChild(hiddenInput);
|
|
|
|
+ form.appendChild(hiddenInput1);
|
|
|
|
+ // Submit the form
|
|
|
|
+ //form.submit();
|
|
|
|
+ $.ajax({
|
|
|
|
+ url: '/pay/stripe/charge/?orderid=$orderid&stripeToken=' + token.id,
|
|
|
|
+ type: 'GET',
|
|
|
|
+ success: function (result) {
|
|
|
|
+ if (result == \"success\") {
|
|
|
|
+ $(\".cardpay_content\").html(\"\");
|
|
|
|
+ $(\".cardpay_content\").html(\"<p class='am-alert am-alert-success'>支付成功,正在跳转页面</p>\");
|
|
|
|
+ window.setTimeout(function () {
|
|
|
|
+ location.href = \"/detail-order-sn/$orderid\"
|
|
|
|
+ }, 800);
|
|
|
|
+ } else {
|
|
|
|
+ $(\".am-alert\").show();
|
|
|
|
+ $(\".button\").removeAttr(\"disabled\");
|
|
|
|
+ $(\".button\").html(\"支付\");
|
|
|
|
+ setTimeout(\" $('.am-alert').hide();\", 3000);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ (function () {
|
|
|
|
+ stripe.createSource({
|
|
|
|
+ type: 'alipay',
|
|
|
|
+ amount: $gbp,
|
|
|
|
+ currency: 'gbp',
|
|
|
|
+ // 这里你需要渲染出一些用户的信息,不然后期没法知道是谁在付钱
|
|
|
|
+ owner: {
|
|
|
|
+ name: '$orderid',
|
|
|
|
+ },
|
|
|
|
+ redirect: {
|
|
|
|
+ return_url: '$return_url',
|
|
|
|
+ },
|
|
|
|
+ }).then(function (result) {
|
|
|
|
+ $(\"#alipaybtn\").attr(\"href\", result.source.redirect.url);
|
|
|
|
+ });
|
|
|
|
+ })();
|
|
|
|
+ function paymentcheck() {
|
|
|
|
+ $.ajax({
|
|
|
|
+ url: '/pay/stripe/check/?orderid=$orderid&source=' + source,
|
|
|
|
+ type: 'GET',
|
|
|
|
+ success: function (result) {
|
|
|
|
+ if (result == \"success\") {
|
|
|
|
+ window.setTimeout(function () {
|
|
|
|
+ location.href = \"/detail-order-sn/$orderid\"
|
|
|
|
+ }, 800);
|
|
|
|
+ } else {
|
|
|
|
+ setTimeout(\"paymentcheck()\", 1000);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
+</script>
|
|
|
|
+</body>
|
|
|
|
+</html>";
|
|
|
|
+
|
|
|
|
+ return $html;
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
+ throw new RuleValidationException(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function returnUrl(Request $request)
|
|
|
|
+ {
|
|
|
|
+
|
|
|
|
+ $data = $request->all();
|
|
|
|
+ $cacheord = $this->orderService->detailOrderSN($data['orderid']);
|
|
|
|
+ if (!$cacheord) {
|
|
|
|
+ return redirect(url('detail-order-sn', ['orderSN' => $data['orderid']]));
|
|
|
|
+ }
|
|
|
|
+ $payGateway = $this->payService->detail($cacheord->pay_id);
|
|
|
|
+ \Stripe\Stripe::setApiKey($payGateway -> merchant_pem);
|
|
|
|
+ $source_object = \Stripe\Source::retrieve($data['source']);
|
|
|
|
+ //die($source_object);
|
|
|
|
+ if ($source_object->status == 'chargeable') {
|
|
|
|
+ \Stripe\Charge::create([
|
|
|
|
+ 'amount' => $source_object->amount,
|
|
|
|
+ 'currency' => $source_object->currency,
|
|
|
|
+ 'source' => $data['source'],
|
|
|
|
+ ]);
|
|
|
|
+ if ($source_object->owner->name == $data['orderid']) {
|
|
|
|
+ $this->orderProcessService->completedOrder($data['orderid'], $cacheord->actual_price, $source_object->id);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return redirect(url('detail-order-sn', ['orderSN' => $data['orderid']]));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function check(Request $request)
|
|
|
|
+ {
|
|
|
|
+
|
|
|
|
+ $data = $request->all();
|
|
|
|
+ $cacheord = $this->orderService->detailOrderSN($data['orderid']);
|
|
|
|
+ if (!$cacheord) {
|
|
|
|
+ //可能已异步回调成功,跳转
|
|
|
|
+ return 'fail';
|
|
|
|
+ } else {
|
|
|
|
+ $payGateway = $this->payService->detail($cacheord->pay_id);
|
|
|
|
+ \Stripe\Stripe::setApiKey($payGateway -> merchant_pem);
|
|
|
|
+ $source_object = \Stripe\Source::retrieve($data['source']);
|
|
|
|
+ if ($source_object->status == 'chargeable') {
|
|
|
|
+ \Stripe\Charge::create([
|
|
|
|
+ 'amount' => $source_object->amount,
|
|
|
|
+ 'currency' => $source_object->currency,
|
|
|
|
+ 'source' => $data['source'],
|
|
|
|
+ ]);
|
|
|
|
+ }
|
|
|
|
+ if ($source_object->status == 'consumed' && $source_object->owner->name == $data['orderid']) {
|
|
|
|
+ $this->orderProcessService->completedOrder($data['orderid'], $cacheord->actual_price, $source_object->id);
|
|
|
|
+ return 'success';
|
|
|
|
+ } else {
|
|
|
|
+ return 'fail';
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function charge(Request $request)
|
|
|
|
+ {
|
|
|
|
+ $data = $request->all();
|
|
|
|
+ $cacheord = $this->orderService->detailOrderSN($data['orderid']);
|
|
|
|
+ if (!$cacheord) {
|
|
|
|
+ //可能已异步回调成功,跳转
|
|
|
|
+ return 'fail';
|
|
|
|
+ } else {
|
|
|
|
+ try {
|
|
|
|
+ $payGateway = $this->payService->detail($cacheord->pay_id);
|
|
|
|
+ \Stripe\Stripe::setApiKey($payGateway -> merchant_pem);
|
|
|
|
+ $result = \Stripe\Charge::create([
|
|
|
|
+ 'amount' => bcmul($this->getGbpCurrency($cacheord->actual_price), 100,0),
|
|
|
|
+ 'currency' => 'gbp',
|
|
|
|
+ 'source' => $data['stripeToken'],
|
|
|
|
+ ]);
|
|
|
|
+ if ($result->status == 'succeeded') {
|
|
|
|
+ $this->orderProcessService->completedOrder($data['orderid'], $cacheord->actual_price, $data['stripeToken']);
|
|
|
|
+ return 'success';
|
|
|
|
+ }
|
|
|
|
+ return $result;
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
+ return $e->getMessage();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 根据RMB获取英镑
|
|
|
|
+ * @param $cny
|
|
|
|
+ * @return float|int
|
|
|
|
+ * @throws \Exception
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ public function getGbpCurrency($cny)
|
|
|
|
+ {
|
|
|
|
+ $client = new Client();
|
|
|
|
+ $res = $client->get('https://api.dov.moe/exchange?src=cny&dst=gbp');
|
|
|
|
+ $fxrate = json_decode($res->getBody(), true);
|
|
|
|
+ if ($fxrate['code'] != 1) {
|
|
|
|
+ $dfFxrate = 0.12;
|
|
|
|
+ } else {
|
|
|
|
+ $dfFxrate = $fxrate['data']['value'] * 1.029;
|
|
|
|
+ }
|
|
|
|
+ return bcmul($cny , $dfFxrate, 2) + 0.2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|