feat(royalpay): 交易对账优化

master
xiao.tang 4 years ago
parent 4d41df91bb
commit e1cd4e2287

@ -2,83 +2,296 @@
* Created by davep on 2016-09-01.
*/
define(['angular', 'uiRouter'], function () {
'use strict';
var app = angular.module('orderValidApp', ['ui.router']);
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider.state('order_valid', {
url: '/order_validation',
templateUrl: '/static/payment/validation/templates/valid-calendar.html',
controller: 'orderValidCalendarCtrl'
}).state('order_valid.report', {
url: '/{date}',
templateUrl: '/static/payment/validation/templates/valid.html',
controller: 'orderValidationCtrl'
});
}]);
app.controller('orderValidCalendarCtrl', ['$scope', '$http', '$filter', function ($scope, $http, $filter) {
$scope.today = new Date();
$scope.loadValidatedDates = function (month) {
let monthStr = $filter('date')(month, 'yyyyMM');
$http.get('/sys/financial/validated_dates/' + monthStr).then(function (resp) {
$scope.validatedDates = resp.data;
'use strict'
var app = angular.module('orderValidApp', ['ui.router'])
app.config([
'$stateProvider',
function ($stateProvider) {
$stateProvider
.state('order_valid', {
url: '/order_validation',
templateUrl: '/static/payment/validation/templates/valid-calendar.html',
controller: 'orderValidCalendarCtrl',
})
.state('order_valid.report', {
url: '/{date}',
templateUrl: '/static/payment/validation/templates/valid.html',
controller: 'orderValidationCtrl',
})
.state('order_valid.report_new', {
url: '/new/{date}',
templateUrl: '/static/payment/validation/templates/valid_new.html',
controller: 'orderValidationNewCtrl',
})
},
])
app.controller('orderValidCalendarCtrl', [
'$scope',
'$http',
'$filter',
'$state',
'commonDialog',
function ($scope, $http, $filter, $state, commonDialog) {
$scope.today = new Date()
$scope.loadValidatedDates = function (month) {
let monthStr = $filter('date')(month, 'yyyyMM')
$http.get('/sys/financial/validated_dates/' + monthStr).then(function (resp) {
$scope.validatedDates = resp.data
})
}
$scope.findReport = function (dateStr) {
if ($scope.validatedDates == null) {
return null
}
let filtered = $scope.validatedDates.filter(rp => rp.date === dateStr)
return filtered.length ? filtered[0] : null
}
$scope.checkDetail = function (date) {
const filterItem = $scope.validatedDates.filter(rp => rp.date === date)
const dateStr = date.replace(/\//g, '')
if (filterItem.length) {
if (filterItem[0].isOld) {
$state.go('order_valid.report', { date: dateStr })
} else {
sessionStorage.setItem('warningLevel', filterItem[0].warning_level)
$state.go('order_valid.report_new', { date: dateStr })
}
} else {
commonDialog
.confirm({
title: 'Confirm',
content: '是否确认重新执行对账?',
})
.then(function () {
$http
.get('/sys/financial/order_validations/' + dateStr, {
params: {
use_cache: false,
},
timeout: 300000,
})
.then(
function () {
$state.reload()
},
function (resp) {
$state.reload()
}
)
})
};
$scope.findReport = function (dateStr) {
if ($scope.validatedDates == null) {
return null;
}
let filtered = $scope.validatedDates.filter(rp => rp.date === dateStr);
return filtered.length ? filtered[0] : null
}
}]);
app.controller('orderValidationCtrl', ['$scope', '$http', '$filter', '$stateParams', 'commonDialog',
function ($scope, $http, $filter, $stateParams, commonDialog) {
$scope.date = $stateParams.date;
$scope.startValid = function (forceRebuild) {
$scope.report = {loading: true};
$http.get('/sys/financial/order_validations/' + $scope.date, {
params: {
use_cache: !forceRebuild
},
timeout: 300000
}).then(function (resp) {
$scope.report = resp.data;
$scope.notExistsKeys = [];
$scope.notEqualsKeys = [];
angular.forEach($scope.report.not_exists, function (item) {
angular.forEach(item, function (val, key) {
if ($scope.notExistsKeys.indexOf(key) < 0) {
$scope.notExistsKeys.push(key);
}
})
});
angular.forEach($scope.report.not_equals, function (item) {
angular.forEach(item, function (val, key) {
if ($scope.notExistsKeys.indexOf(key) < 0) {
$scope.notExistsKeys.push(key);
}
})
});
}, function (resp) {
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'});
$scope.report = null;
}
},
])
// old
app.controller('orderValidationCtrl', [
'$scope',
'$http',
'$filter',
'$stateParams',
'commonDialog',
function ($scope, $http, $filter, $stateParams, commonDialog) {
$scope.date = $stateParams.date
$scope.startValid = function (forceRebuild) {
$scope.report = { loading: true }
$http
.get('/sys/financial/order_validations/' + $scope.date, {
params: {
use_cache: !forceRebuild,
},
timeout: 300000,
})
.then(
function (resp) {
$scope.report = resp.data
$scope.notExistsKeys = []
$scope.notEqualsKeys = []
angular.forEach($scope.report.not_exists, function (item) {
angular.forEach(item, function (val, key) {
if ($scope.notExistsKeys.indexOf(key) < 0) {
$scope.notExistsKeys.push(key)
}
})
})
angular.forEach($scope.report.not_equals, function (item) {
angular.forEach(item, function (val, key) {
if ($scope.notExistsKeys.indexOf(key) < 0) {
$scope.notExistsKeys.push(key)
}
})
};
$scope.startValid(false);
})
},
function (resp) {
commonDialog.alert({ title: 'Error', content: resp.data.message, type: 'error' })
$scope.report = null
}
)
}
$scope.startValid(false)
$scope.fixReport = function () {
var datePattern = $filter('date')($scope.valid.date, 'yyyyMMdd');
$http.get('/sys/financial/order_validations', {
params: {
date: datePattern,
fix: true
}
}).then(function (resp) {
commonDialog.alert({title: 'Success', content: '修复完毕', type: 'success'})
}, function (resp) {
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'})
$scope.fixReport = function () {
var datePattern = $filter('date')($scope.valid.date, 'yyyyMMdd')
$http
.get('/sys/financial/order_validations', {
params: {
date: datePattern,
fix: true,
},
})
.then(
function (resp) {
commonDialog.alert({ title: 'Success', content: '修复完毕', type: 'success' })
},
function (resp) {
commonDialog.alert({ title: 'Error', content: resp.data.message, type: 'error' })
}
)
}
},
])
// new
app.controller('orderValidationNewCtrl', [
'$scope',
'$http',
'$stateParams',
'commonDialog',
'$uibModal',
function ($scope, $http, $stateParams, commonDialog, $uibModal) {
// 清除sessionStorage
$scope.$on('$destroy', function () {
sessionStorage.clear()
})
$scope.date = angular.copy($stateParams.date)
$scope.date = $scope.date.substr(0, 4) + '-' + $scope.date.substr(4, 2) + '-' + $scope.date.substr(6)
$scope.warningLevel = JSON.parse(sessionStorage.getItem('warningLevel'))
// 加载渠道信息
$scope.startValid = function () {
$http
.get('/sys/financial/order_validation_new/' + $stateParams.date, {
timeout: 300000,
})
.then(
function (resp) {
$scope.channelList = []
for (let key in resp.data) {
const obj = {}
obj.key = key
obj.channel = resp.data[key]
obj.selected = false
$scope.channelList.push(obj)
}
$scope.channelList.map(item => {
const arr = item.channel.filter(f => {
return f.success === false
})
item.status = arr.length ? 'FAILED' : 'SUCCESS'
item.success = arr.length ? false : true
})
if (sessionStorage.getItem('channel')) {
const channel = JSON.parse(sessionStorage.getItem('channel'))
channel.map(item => {
$scope.channelList.filter(f => f.key === item.key)[0].selected = item.selected
})
} else {
$scope.channelList[0].selected = true
}
console.log($scope.channelList)
},
function (resp) {
commonDialog.alert({ title: 'Error', content: resp.data.message, type: 'error' })
}
}]);
return app;
});
)
}
$scope.startValid()
// 受否折叠
$scope.fold = function (index) {
$scope.channelList[index].selected = !$scope.channelList[index].selected
}
// 是否清除缓存
$scope.clear = function (channelName, flag) {
$http.post('/sys/financial/redo_channel_validation/' + $stateParams.date, { channel: channelName, cache: flag }).then(
function () {
$scope.startValid()
},
function (resp) {
commonDialog.alert({ title: 'failed', content: resp.data.message, type: 'error' })
}
)
}
// 处理
$scope.handle = function (logId) {
sessionStorage.setItem('channel', JSON.stringify($scope.channelList))
$uibModal
.open({
templateUrl: '/static/payment/validation/templates/handle_desc.html',
controller: 'handleCtrl',
resolve: {
logId: [
'$stateParams',
function () {
return logId
},
],
},
})
.result.then(function () {
$scope.startValid()
})
}
// 下载
$scope.download = function (merchant, keyName) {
if (merchant != null) {
const params = {}
params.channel = keyName
params.pid = merchant.pid
params.billDate = merchant.bill_date
params.noCache = false
params.billType = ''
window.open(
'/sys/financial/downloadChannelReconciliationFile?billDate=' +
params.billDate +
'&channel=' +
params.channel +
'&noCache=' +
params.noCache +
'&pid=' +
params.pid +
'&billType=' +
params.billType
)
}
}
// 查看what
$scope.checkStatus = function (transactionId) {
$http.get('/sys/financial/get/transaction/status/' + transactionId, {}).then(
function (resp) {
commonDialog.alert({ title: resp.data.statusInfo, content: '', type: 'success' })
},
function (resp) {
commonDialog.alert({ title: 'failed', content: resp.data.message, type: 'error' })
}
)
}
},
])
// 处理
app.controller('handleCtrl', [
'$scope',
'$http',
'commonDialog',
'logId',
function ($scope, $http, commonDialog, logId) {
$scope.confirm = function () {
$http.post('/sys/financial/mark/resolve/message', { log_id: logId, message: $scope.message }).then(
function () {
$scope.$close()
},
function (resp) {
commonDialog.alert({ title: 'failed', content: resp.data.message, type: 'error' })
}
)
}
},
])
return app
})

@ -0,0 +1,25 @@
<div class="modal-header" style="display: flex;border-bottom: none;">
<h4>Handle</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-sm-12">
<form novalidate name="couponForm" class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-3">Description</label>
<div class="col-sm-7">
<textarea class="form-control" ng-model="message" maxlength="2000"></textarea>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="modal-footer">
<div class="btn-group">
<button class="btn btn-success" type="button" ng-click="confirm()">{{'in_common_use.submit'|translate}}</button>
</div>
<div class="btn-group">
<button class="btn btn-danger" type="button" ng-click="$dismiss()">{{'in_common_use.cancel'|translate}}</button>
</div>
</div>

@ -7,19 +7,35 @@
</ol>
</section>
<section class="content">
<div class="box">
<div class="box-body">
<div royal-calendar month-change="loadValidatedDates($month)">
<a class="rc-full" role="button" ui-sref=".report({date:(day|date:'yyyyMMdd')})"
style="font-size: 40px" ng-if="day<=today">
<a class="rc-full" role="button" ng-click="checkDetail((day|date:'yyyy/MM/dd'))"
style="font-size: 40px" ng-if="day<=today">
<i class="fa"
ng-class="{'fa-check-circle text-green':findReport((day|date:'yyyy/MM/dd')).success,'fa-warning':!findReport((day|date:'yyyy/MM/dd')).success,'text-red':findReport((day|date:'yyyy/MM/dd')).warning_level==2,'text-yellow':findReport((day|date:'yyyy/MM/dd')).warning_level==1}"
ng-if="findReport((day|date:'yyyy/MM/dd'))!=null"></i>
ng-class="{'fa-check-circle text-green':findReport((day|date:'yyyy/MM/dd')).success,'fa-warning':!findReport((day|date:'yyyy/MM/dd')).success,'text-red':findReport((day|date:'yyyy/MM/dd')).warning_level==2,'text-yellow':findReport((day|date:'yyyy/MM/dd')).warning_level==1}"
ng-if="findReport((day|date:'yyyy/MM/dd'))!=null"></i>
</a>
</div>
</div>
<div style="padding: 20px 10px;">
<div>
<i class="fa fa-check-circle text-green"></i>
<span>&nbsp;All channel transactions are reconciled successfully. </span>
</div>
<div>
<i class="fa fa-check-circle fa-warning text-yellow"></i>
<span>Yellow warning: There are some abnormal orders in a channel in the transaction reconciliation
result, such as the difference between the amount of an order in the system and the bill amount
of the corresponding channel. </span>
</div>
<div>
<i class="fa fa-check-circle fa-warning text-red"></i>
<span>There are some missing orders in a channel in the result of the transaction reconciliation,
for example, by comparing the statement of a channel, it is found that the payment order was not
found in the system on the same day.</span>
</div>
</div>
</div>
</section>
</div>

@ -0,0 +1,278 @@
<section class="content-header">
<ol class="breadcrumb">
<li><i class="fa fa-balance-scale"></i>Payment & settlement</li>
<li class="active"><a ui-sref="^">Order Validation Calendar</a></li>
<li>Validate Result</li>
</ol>
</section>
<section class="header">
<h3>{{date}}</h3>
<i class="fa fa-check-circle text-green fa-2x" style="margin-left: 24px;" ng-if="warningLevel === 0"></i>
<i class="fa fa-exclamation-triangle text-yellow fa-2x" style="margin-left: 24px;" ng-if="warningLevel === 1"></i>
<i class="fa fa-exclamation-triangle text-red fa-2x" style="margin-left: 24px;" ng-if="warningLevel === 2"></i>
</section>
<section class="content">
<div ng-repeat="(index,item) in channelList">
<div class="panel" ng-class="{'panel-success':item.success,'panel-danger':!item.success}">
<div class="panel-heading panel-box" ng-click="fold(index)">
<div class="title-box">
<img src="/static/images/wechatpay_sign.png" uib-tooltip="WechatPay" ng-if="item.key=='Wechat'" />
<img src="/static/images/alipay_sign.png" uib-tooltip="Alipay" ng-if="item.key=='Alipay'" />
<img src="/static/images/alipay_sign.png" uib-tooltip="AlipayOnline"
ng-if="item.key=='AlipayOnline'" />
<img src="/static/images/alipay_direct_sign.png" uib-tooltip="AlipayDirect"
ng-if="item.key=='Alipay_Direct'" />
<img src="/static/images/unionpay_sign.png" style="width: 16px;height: 16px;" uib-tooltip="UnionPay"
ng-if="item.key=='UnionPay'" />
<img src="/static/images/upop_sign.png" uib-tooltip="UnionPayOnline"
ng-if="item.key=='UnionPayOnline'" />
<img src="/static/images/alipay_sign.png" style="height: 20px" uib-tooltip="Alipay CN"
ng-if="item.key=='AlipayPlus'" />
<h4 style="margin-left: 16px;">{{item.key}}</h4>
</div>
<h5 style="width: 360px;">Status&nbsp;{{item.status}}
<small style="margin-left: 10px;white-space: nowrap;">
(UpdateTime : {{item.channel[0].valid_time}})</small>
</h5>
<h5 style="position: relative;" ng-click="$event.stopPropagation();">
<a role="button" ng-click="clear(item.key,false)">Revalidate</a>
<i class="fa fa-sort-desc" style="cursor:pointer" ng-click="cacheFlag = !cacheFlag"></i>
<a role="button" class="cache-style" ng-show="cacheFlag"
ng-click="clear(item.key,true);cacheFlag = false">clear
cache</a>
</h5>
</div>
<div ng-show="item.selected">
<div class="panel-body" ng-repeat="merchant in item.channel">
<div style="display: flex;justify-content: space-between;">
<h4 class="title-margin">{{merchant.pid}}:
<small>(Transaction Time Range :
{{merchant.valid_from_time}} ~ {{merchant.valid_to_time}})</small>
</h4>
<a role="button" ng-click="handle(merchant.log_id)">handle</a>
</div>
<div class="table-download">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th></th>
<th>Payment Amount in Local Currency</th>
<th>Payment Transactions Number</th>
<th>Refund Amount in Local Currency</th>
<th>Refund Transactions Number</th>
<th>Total Payment Number</th>
<th>Total Refund Number</th>
</tr>
</thead>
<tbody>
<tr>
<td><i class="fa fa-cloud fa-lg" uib-tooltip="Channel Data"></i>
</td>
<td>
{{merchant.channel_analysis.total_paid || merchant.channel_analysis.total_paid
=== 0 ? merchant.channel_analysis.total_paid : '-'}}
</td>
<td>
{{merchant.channel_analysis.pay_count || merchant.channel_analysis.pay_count ===
0 ? merchant.channel_analysis.pay_count : '-'}}
</td>
<td>
{{merchant.channel_analysis.total_refund ||
merchant.channel_analysis.total_refund === 0 ?
merchant.channel_analysis.total_refund : '-'}}
</td>
<td>
{{merchant.channel_analysis.refund_count ||
merchant.channel_analysis.refund_count === 0 ?
merchant.channel_analysis.refund_count : '-'}}
</td>
<td>
{{merchant.channel_analysis.total_paid_number ||
merchant.channel_analysis.total_paid_number === 0 ?
merchant.channel_analysis.total_paid_number : '-'}}
</td>
<td>
{{merchant.channel_analysis.total_refund_number ||
merchant.channel_analysis.total_refund_number === 0 ?
merchant.channel_analysis.total_refund_number : '-'}}
</td>
</tr>
<tr>
<td><i class="fa fa-database fa-lg" uib-tooltip="System Data"></i></td>
<td
ng-style="{'color': merchant.channel_analysis.total_paid || merchant.channel_analysis.total_paid === 0 ? (merchant.db_analysis.total_paid === merchant.channel_analysis.total_paid ? 'green' : 'red') : ''}">
{{merchant.db_analysis.total_paid || merchant.db_analysis.total_paid === 0 ?
merchant.db_analysis.total_paid : '-'}}
</td>
<td
ng-style="{'color': merchant.channel_analysis.pay_count || merchant.channel_analysis.pay_count === 0 ? (merchant.db_analysis.pay_count === merchant.channel_analysis.pay_count ? 'green' : 'red') : ''}">
{{merchant.db_analysis.pay_count || merchant.db_analysis.pay_count === 0 ?
merchant.db_analysis.pay_count : '-'}}
</td>
<td
ng-style="{'color': merchant.channel_analysis.total_refund || merchant.channel_analysis.total_refund === 0 ? (merchant.db_analysis.total_refund === merchant.channel_analysis.total_refund ? 'green' : 'red') : ''}">
{{merchant.db_analysis.total_refund || merchant.db_analysis.total_refund === 0 ?
merchant.db_analysis.total_refund : '-'}}
</td>
<td
ng-style="{'color': merchant.channel_analysis.refund_count || merchant.channel_analysis.refund_count === 0 ? (merchant.db_analysis.refund_count === merchant.channel_analysis.refund_count ? 'green' : 'red') : ''}">
{{merchant.db_analysis.refund_count || merchant.db_analysis.refund_count === 0 ?
merchant.db_analysis.refund_count : '-'}}
</td>
<td
ng-style="{'color': item.key === 'Wechat' ? (merchant.db_analysis.total_paid_number === merchant.channel_analysis.total_paid_number ? 'green' : 'red') : ''}">
{{merchant.db_analysis.total_paid_number ||
merchant.db_analysis.total_paid_number === 0 ?
merchant.db_analysis.total_paid_number : '-'}}
</td>
<td
ng-style="{'color': item.key === 'Wechat' ? (merchant.db_analysis.total_refund_number === merchant.channel_analysis.total_refund_number ? 'green' : 'red') : ''}">
{{merchant.db_analysis.total_refund_number ||
merchant.db_analysis.total_refund_number === 0 ?
merchant.db_analysis.total_refund_number : '-'}}
</td>
</tr>
</tbody>
</table>
<a role="button" style="white-space: nowrap;margin-left: 20px;"
ng-click="download(merchant,item.key)"><i class="fa fa-download"></i>download</a>
</div>
<div ng-if="merchant.not_exists.length">
<h4 class="title-margin">Not Exists Transactions</h4>
<div style="max-height: 500px;overflow: auto;">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Missing Type</th>
<th>Transaction Time</th>
<th>Transaction ID</th>
<th>Order ID</th>
<th>Transaction Type</th>
<th>Transaction Amount</th>
<th>Operation</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="notExist in merchant.not_exists">
<td>{{ notExist.missing_side ? notExist.missing_side : '-' }}</td>
<td>{{ notExist.transaction_time ? notExist.transaction_time : '-' }}
</td>
<td>{{ notExist.channel_trans_id ? notExist.channel_trans_id : '-' }}
</td>
<td>{{ notExist.order_id ? notExist.order_id : '-' }}</td>
<td>{{ notExist.trans_type ? notExist.trans_type : '-' }}</td>
<td>{{ notExist.amount || notExist.amount === 0 ? notExist.amount : '-'
}}
</td>
<td><a role="button" uib-tooltip="Clearing status"
ng-click="checkStatus(notExist.channel_trans_id)">
<i class="fa fa-eye" ng-if="notExist.channel_trans_id"></i>
<span ng-if="!notExist.channel_trans_id">-</span>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div ng-if="merchant.not_equals.length">
<h4 class="title-margin">Not Equals Transactions</h4>
<div style="max-height: 500px;overflow: auto;">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Transaction Time</th>
<th>Transaction ID</th>
<th>Order ID</th>
<th>Transaction Type</th>
<th>Transaction Amount</th>
<th>Operation</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="notEqual in merchant.not_equals">
<td>{{notEqual.trans_time ? notEqual.trans_time : '-'}}</td>
<td>{{notEqual.transaction_id ? notEqual.transaction_id : '-'}}</td>
<td>{{notEqual.order_id ? notEqual.order_id : '-'}}</td>
<td>{{notEqual.trans_type ? notEqual.trans_type : '-'}}</td>
<td>{{notEqual.channel_amount || notEqual.channel_amount === 0 ?
notEqual.channel_amount : '-'}}</td>
<td><a role="button" uib-tooltip="Clearing status"
ng-click="checkStatus(notEqual.transaction_id)">
<i class="fa fa-eye" ng-if="notEqual.transaction_id"></i>
<span ng-if="!notEqual.transaction_id">-</span>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div ng-if="merchant.resolve_msg">
<div class="title-margin">Handle Description:</div>
<div>{{ merchant.resolve_msg }}</div>
</div>
</div>
</div>
</div>
</div>
</section>
<style>
h1,
h2,
h3,
h4,
h5 {
margin: unset;
}
.header {
display: flex;
align-items: center;
margin-top: 50px;
padding: 0 20px;
}
.panel-box {
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 20px;
cursor: pointer;
}
.title-box {
display: flex;
align-items: center;
width: 180px;
}
.dropdown-menu {
min-width: unset;
left: unset;
right: 0;
}
.table-download {
display: flex;
align-items: center;
}
.title-margin {
margin: 10px 0;
}
.cache-style {
position: absolute;
right: 0;
top: 20px;
background: rgb(255, 255, 255);
padding: 10px 15px;
white-space: nowrap;
border-radius: 4px;
}
</style>
Loading…
Cancel
Save